下面开始分析U-Boot第二阶段:
/lib_arm/board.c:
由前述分析可知,在start.S中对CPU进行了基本的设置,准备好了C程序的运行环境(设置好了堆栈并清BSS),并调用C函数start_armboot,进入lib_arm目录下的board.c文件,第236行开始即为start_armboot函数:
------- /lib_arm/board.c -------
236 void start_armboot (void)
237 {
238 init_fnc_t **init_fnc_ptr;
239 char *s;
240 #ifndef CFG_NO_FLASH
241 ulong size;
242 #endif
243 #if defined(CONFIG_VFD) || defined(CONFIG_LCD)
244 unsigned long addr;
245 #endif
一些变量的定义,其中init_fnc_ptr为初始化函数序列的指针。
接下来初始化全局变量gd与gd->bd的内存区域(清0),第55行的宏定义声明了gd:
------- /lib_arm/board.c -------
55 DECLARE_GLOBAL_DATA_PTR;
这个宏定义在/include/asm-arm/global_data.h中,(凡是用到gd的文件中都会引用这个宏定义):
------- /include/asm-arm/global_data.h -------
64 #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
register volatile gd_t *gd asm ("r8"):声明一个寄存器变量gd,用R8寄存器来存储其指针,不占用内存,且避免编译器再将R8分配给其他变量。
第248行设置gd指针的具体地址,其中_armboot_start表示0x33F80000地址,CFG_MALLOC_LEN定义的大小为0x30000=192kB,然后调用memset函数将gd指针开始的、大小为sizeof(gd_t)的内存区域初始化为0:
------- /lib_arm/board.c -------
247 /* Pointer is writable since we allocated a register for it */
248 gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
249 /* compiler optimization barrier needed for GCC >= 3.4 */
250 __asm__ __volatile__("": : :"memory");
251
252 memset ((void*)gd, 0, sizeof (gd_t));
__asm__:在此插入汇编语句;
__volatile__:禁止优化,即编译器将按照此处的语句处理;
"memory":强制编译器假设所有内存单元均被汇编指令修改,即CPU必须重新读取内存中的数据,而不是利用cache的缓存数据。
举个栗子(来自网络博客):
1 int a = 5, b = 6;
2 __asm__ __volatile__("": : :"memory");
3 a = b;
此时第3行的处理,编译器不会用存放b的寄存器给a赋值,而是让CPU重新读取内存中b的值,并赋给a。
第253行、254行设置bd的指针,并将其内存区域初始化为0:
------- /lib_arm/board.c -------
253 gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
254 memset (gd->bd, 0, sizeof (bd_t));
255
256 monitor_flash_len = _bss_start - _armboot_start;
接下来按照初始化函数序列的顺序,执行所有的初始化函数:
------- /lib_arm/board.c -------
258 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
259 if ((*init_fnc_ptr)() != 0) {
260 hang ();
261 }
262 }
初始化函数正确执行的返回值应该为0,否则将调用hang()函数,输出错误信息并进入死循环暂停。
初始化函数序列包括CPU的初始化、板级初始化、中断初始化、环境变量初始化、波特率初始化、串口初始化、控制台初始化、显示U-Boot信息以及DRAM的初始化等:
------- /lib_arm/board.c -------
212 typedef int (init_fnc_t) (void);
...
216 init_fnc_t *init_sequence[] = {
217 cpu_init, /* basic cpu dependent setup */
218 board_init, /* basic board dependent setup */
219 interrupt_init, /* set up exceptions */
220 env_init, /* initialize environment */
221 init_baudrate, /* initialze baudrate settings */
222 serial_init, /* serial communications setup */
223 console_init_f, /* stage 1 init of console */
224 display_banner, /* say that we are here */
225 #if defined(CONFIG_DISPLAY_CPUINFO)
226 print_cpuinfo, /* display cpu info (and speed) */
227 #endif
228 #if defined(CONFIG_DISPLAY_BOARDINFO)
229 checkboard, /* display board info */
230 #endif
231 dram_init, /* configure available RAM banks */
232 display_dram_config,
233 NULL,
234 };
下面对初始化函数序列进行详细说明(可以先初始化波特率和串口,便于输出调试信息,这里按顺序进行分析修改)。
初始化函数序列分析:
cpu_init:
位于/cpu/arm920t/cpu.c文件中,主要用于设置中断的堆栈,在这里并没有定义CONFIG_USE_IRQ,因此实际上无作用,不需进行修改:
------- /cpu/arm920t/cpu.c -------
92 int cpu_init (void)
93 {
94 /*
95 * setup up stacks if necessary
96 */
97 #ifdef CONFIG_USE_IRQ
98 IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
99 FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
100 #endif
101 return 0;
102 }
board_init:
位于/board/mini2440/mini2440.c文件中,主要用于CPU时钟与引脚设置:
------- /board/mini2440/mini2440.c -------
68 int board_init (void)
69 {
70 S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
71 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
S3C24X0_CLOCK_POWER:在/include/s3c24x0.h中定义,而S3C2440多一个CAMDIVN寄存器,因此在添加修改(不修改也没事):
------- /include/s3c24x0.h -------
120 /* CLOCK & POWER MANAGEMENT (see S3C2400 manual chapter 6) */
121 /* (see S3C2410 manual chapter 7) */
122 typedef struct {
123 S3C24X0_REG32 LOCKTIME;
124 S3C24X0_REG32 MPLLCON;
125 S3C24X0_REG32 UPLLCON;
126 S3C24X0_REG32 CLKCON;
127 S3C24X0_REG32 CLKSLOW;
128 S3C24X0_REG32 CLKDIVN;
129 #ifdef CONFIG_S3C2440
130 S3C24X0_REG32 CAMDIVN;
131 #endif
132 } /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
...
845 /* CLOCK & POWER MANAGEMENT */
846 #define rLOCKTIME (*(volatile unsigned *)0x4C000000)
847 #define rMPLLCON (*(volatile unsigned *)0x4C000004)
848 #define rUPLLCON (*(volatile unsigned *)0x4C000008)
849 #define rCLKCON (*(volatile unsigned *)0x4C00000C)
850 #define rCLKSLOW (*(volatile unsigned *)0x4C000010)
851 #define rCLKDIVN (*(volatile unsigned *)0x4C000014)
852 #define rCAMDIVN (*(volatile unsigned *)0x4C000018)
S3C2440还有一些寄存器与S3C2410不同,在后续遇到时将进行修改。
S3C24X0_GPIO:在/include/s3c24x0.h中定义,在前面已经添加了S3C2440的GPIO寄存器:
------- /include/s3c24x0.h -------
385 /* I/O PORT (see manual chapter 9) */
386 typedef struct {
...
470 #ifdef CONFIG_S3C2440
471 S3C24X0_REG32 GPACON;
472 S3C24X0_REG32 GPADAT;
473 S3C24X0_REG32 res1[2];
474 S3C24X0_REG32 GPBCON;
475 S3C24X0_REG32 GPBDAT;
476 S3C24X0_REG32 GPBUP;
477 S3C24X0_REG32 res2;
478 S3C24X0_REG32 GPCCON;
479 S3C24X0_REG32 GPCDAT;
480 S3C24X0_REG32 GPCUP;
481 S3C24X0_REG32 res3;
482 S3C24X0_REG32 GPDCON;
483 S3C24X0_REG32 GPDDAT;
484 S3C24X0_REG32 GPDUP;
485 S3C24X0_REG32 res4;
486 S3C24X0_REG32 GPECON;
487 S3C24X0_REG32 GPEDAT;
488 S3C24X0_REG32 GPEUP;
489 S3C24X0_REG32 res5;
490 S3C24X0_REG32 GPFCON;
491 S3C24X0_REG32 GPFDAT;
492 S3C24X0_REG32 GPFUP;
493 S3C24X0_REG32 res6;
494 S3C24X0_REG32 GPGCON;
495 S3C24X0_REG32 GPGDAT;
496 S3C24X0_REG32 GPGUP;
497 S3C24X0_REG32 res7;
498 S3C24X0_REG32 GPHCON;
499 S3C24X0_REG32 GPHDAT;
500 S3C24X0_REG32 GPHUP;
501 S3C24X0_REG32 res8;
502
503 S3C24X0_REG32 MISCCR;
504 S3C24X0_REG32 DCLKCON;
505 S3C24X0_REG32 EXTINT0;
506 S3C24X0_REG32 EXTINT1;
507 S3C24X0_REG32 EXTINT2;
508 S3C24X0_REG32 EINTFLT0;
509 S3C24X0_REG32 EINTFLT1;
510 S3C24X0_REG32 EINTFLT2;
511 S3C24X0_REG32 EINTFLT3;
512 S3C24X0_REG32 EINTMASK;
513 S3C24X0_REG32 EINTPEND;
514 S3C24X0_REG32 GSTATUS0;
515 S3C24X0_REG32 GSTATUS1;
516 S3C24X0_REG32 GSTATUS2;
517 S3C24X0_REG32 GSTATUS3;
518 S3C24X0_REG32 GSTATUS4;
519 #endif
520 } /*__attribute__((__packed__))*/ S3C24X0_GPIO;
通过设置MPLLCON和UPLLCON来改变时钟频率:
修改时钟设置宏定义如下:
------- /board/mini2440/mini2440.c -------
33 //#define FCLK_SPEED 1
34 #define FCLK_SPEED 200
...
44 #elif FCLK_SPEED==200
45 #define M_MDIV 0x5C
46 #define M_PDIV 0x1
47 #define M_SDIV 0x2
...
50 //#define USB_CLOCK 1
51 #define USB_CLOCK 48
...
61 #elif USB_CLOCK==48
62 #define U_M_MDIV 0x38
63 #define U_M_PDIV 0x2
64 #define U_M_SDIV 0x2
在board_init函数中通过时钟设置的宏定义对时钟频率进行修改:
------- /board/mini2440/mini2440.c -------
83 /* to reduce PLL lock time, adjust the LOCKTIME register */
84 clk_power->LOCKTIME = 0xFFFFFF;
85
86 /* the CLKDIVN register, FCLK:HCLK:PCLK=4:2:1 */
87 clk_power->CLKDIVN = 0x3;
88 __asm__(
89 "mrc p15, 0, r0, c1, c0, 0n"
90 "orr r0, r0, #0xC0000000n"
上一篇:U-Boot-1.1.6移植到MINI2440开发板(2) —— S3C2440相关修改
下一篇:U-Boot-1.1.6移植到MINI2440开发板(3) —— 源码分析第一阶段
推荐阅读

