这里让UBOOT使用串口作为控制台输出,必须要保证串口功能被完善的支持。不过在启动到初始化串口功能之前,我们必须保证前面的初始化功能能顺利走完。

先来看看UBOOT的一个启动流程:

UBOOT起始代码所在的文件一般命名为start.S。这是一段汇编代码,一般位于各个CPU体系的文件夹下,为使用该CPU体系的芯片提供基本的初始化功能。

S3C24X0芯片属于ARM 920TCPU体系。其start.S的路径位于arch\arm\cpu\arm920t\这段汇编代码一般被称作第一阶段初始化代码。主要作用是初始化运行环境;初始化内存;重新放置UBOOT代码到内存中;跳入到内存中执行第二段初始化代码。其流程大致如下:

TQ2440的学习——UBOOT移植(串口控制台的支持) - mobilefzb - mobilefzb

 

 

在上面的流程中,有几点需要修改

S3C2410在初始化的时候会关闭中断(主中断和子中断都要关掉),不过S3C2410S3C2440的中断配置是相同的。所以将“# if defined(CONFIG_S3C2410)”修改成“# if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)”可以保证中断被正确的屏蔽。

cpu_init_crit函数的功能是关闭MMU、初始化内存。所以该函数是必须要执行的。至于lowlevel_init函数,其位于board\samsung\fzb2440\目录下,这个是需要用户自己编写的部分,内存的初始化可见《TQ2440的学习——将按键驱动LED灯的代码复制到SDRAM中运行》,这里S3C2410S3C2440是相通的。要做的就是修改下内存的刷新率之类的参数。

执行完cpu_init_crit函数后,UBOOT就要将代码放置到内存中去。这部分代码是从NOR FLASH或者内部RAM将代码复制到内存中去。所以如果从NAND FLASH启动的话,注意不要开启这部分代码。TQ2440有一块NOR FLASH,所以本次UBOOT也就设计成从NOR FLASH启动。通过这部分代码熟悉下UBOOT在内存中被放置的位置是有好处的,可以得出UBOOT的内存分布图,方便调试。

首先,UBOOT要确定当前代码所在位置是FLASH还是RAM。方法是比较_start_TEXT_BASE,前者代表代码起始的地址(一般为0x0),后者代表编译代码的时候指定的起始地址(这里指定为)。相同的话则跳入到栈设置,否则计算出_bss_start - _armboot_start的值。这个值表示的是UBOOT的大小。

接下来进入copy_loop循环,将以_start为起始地址的代码数据复制到以_TEXT_BASE为起始地址的内存中,长度为_bss_start - _armboot_start

代码复制完后就是栈的设置,可以看到栈的起始地址是_TEXT_BASE - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_GBL_DATA_SIZE  8

最后将_bss_start_bss_end之间的数据全部清0,就可以跳转到start_armboot函数中去了,也就是第二段初始化代码,位于arch\arm\cpu\arm92t\board.c这个文件当中。

对于S3C2440来说,这部分和S3C2410是相同的。所以一般不会有太大问题。

在第二段代码中,UBOOT会对一些设备进行初始化设置,其中也包括串口的设置。

UBOOT为了提高代码的简洁性,使用了一个函数指针数组init_fnc_ptr。一些初始化函数被放在这个数组当中。

01  init_fnc_t *init_sequence[] = 
02  { 
03  #if defined(CONFIG_ARCH_CPU_INIT) 
04      arch_cpu_init,        /* basic arch cpu dependent setup */ 
05  #endif 
06      board_init,        /* basic board dependent setup */ 
07  #if defined(CONFIG_USE_IRQ) 
08      interrupt_init,        /* set up exceptions */ 
09  #endif 
10      timer_init,        /* initialize timer */ 
11  #ifdef CONFIG_FSL_ESDHC 
12      get_clocks, 
13  #endif 
14      env_init,        /* initialize environment */ 
15      init_baudrate,        /* initialze baudrate settings */ 
16      serial_init,        /* serial communications setup */ 
17      console_init_f,        /* stage 1 init of console */ 
18      display_banner,        /* say that we are here */ 
19  #if defined(CONFIG_DISPLAY_CPUINFO) 
20      print_cpuinfo,        /* display cpu info (and speed) */ 
21  #endif 
22  #if defined(CONFIG_DISPLAY_BOARDINFO) 
23      checkboard,        /* display board info */ 
24  #endif 
25  #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) 
26      init_func_i2c, 
27  #endif 
28      dram_init,        /* configure available RAM banks */ 
29  #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI) 
30      arm_pci_init, 
31  #endif 
32      display_dram_config, 
33      NULL, 
34  }; 

在执行这个初始化列表之前,UBOOT首先要为global_data(全局数据结构体)和bd_info(板子信息结构体)开辟内存空间并初始化。这两段数据可以说是整个UBOOT运行环境的一个展示。

01      /* Pointer is writable since we allocated a register for it */ 
02      gd = (gd_t *)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)); 
03      /* compiler optimization barrier needed for GCC >= 3.4 */ 
04      __asm__ __volatile__("": : :"memory"); 
05       
06      memset ((void *)gd, 0sizeof (gd_t)); 
07      gd->bd = (bd_t *)((char *)gd - sizeof(bd_t)); 
08      memset (gd->bd, 0sizeof (bd_t)); 
09       
10      gd->flags |= GD_FLG_RELOC; 

上述结构体初始化完成后,UBOOT就会顺序执行init_fnc_ptr中的函数。其中有一些函数使用宏在控制,可以根据自己的需要开启相关的宏。这里就按照SMDK2410的默认宏设置来配置这部分代码。首先执行的是board_init函数,其位于board\samsung\smdk2410\目录下。这个函数是用户自己实现的部分,SMDK2410在这里实现了CPU的设置和GPIO的设置,S3C2440S3C2410在系统时钟和GPIO部分几乎相同,不过S3C2440S3C2410GPIO方面多扩展了几组,而且功能也有一定调整。可以将两者的芯片资料关于这部分的介绍对比一下,这里直接将SMDK2410GPIO设置用来设置TQ2440(只需要引导LINUX的话,这样的配置无问题,如果要配置其他功能可自行修改)。

108      gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; 

这句需要修改下,毕竟不是2410了要改成MACH_TYPE_S3C2440。这样LINUX在引导的时候能正确识别CPU信号。

111      gd->bd->bi_boot_params = 0x30000100

这句就是UBOOT指定的LINUX引导启动参数存放的地方。引导LINUX的时候,会从这个地方读取启动参数。所以到时候要保证两者的一致性。

下面执行timer_init函数,这个部分位于arch\arm\cpu\arm920t\s3c24x\timer.c文件里。初始化了定时器。时间控制是一个调度系统的核心之一,所以这部分是非常重要的。S3C2440S3C2410在定时器部件上是完全一样的,所以可以将其应用到本次的移植之中。

timer_init执行完后是env_init,这个函数是环境的初始化函数。该函数的主要功能就是将存储在某个位置的环境参数读取到UBOOT中去,可以预先将环境变量保存到某个位置,然后让UBOOT在启动的时候去读取,这里也许是用于一些早已配置好环境变量的板子的功能。但是TQ2440没有将UBOOT的环境变量保存在任何地方,所以感觉现在使用CONFIG_ENV_IS_NOWHERE要好一点(将这个宏添加到fzb2440.h中去),表示环境变量没有保存在任何地方。

在前面的初始化执行完后,UBOOT就开始初始化串口了。不过这里要注意S3C2410S3C2440在串口初始化可以共享一套代码,但是这套代码CONFIG_S3C2410也控制了一部分,所以在定义了CONFIG_S3C2410的地方也加上CONFIG_S3C2440这样就可以保证串口的代码被完整的使用。控制台的初始化函数console_init_f确定了串口1作为输出。当前面所有这些被正确初始化后,在display_banner函数里将会向串口控制台输出一些字符串:

TQ2440的学习——UBOOT移植(串口控制台的支持) - mobilefzb - mobilefzb