本文还是以u-boot-1.1.4为例,以make smdk2410_config命令配置源代码之后进行分析。
对于C语言部分代码的调用出现在cpu/arm920t/start.S的第223行:
[code]
ldr pc, _start_armboot
_start_armboot: .word start_armboot
[/code]
这里的start_armboot就是lib_arm/board.c中第207行的start_armboot()函数,由此U-Boot开始执行C语言部分的代码。
start_armboot()函数一开始首先是一个宏调用:
[code]
DECLARE_GLOBAL_DATA_PTR;
[/code]
这个宏的定义在include/asm-arm/global_data.h文件的第64行:
[code]
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
[/code]
大概的意思是声明一个指向gd_t结构体变量的指针gd,并固定使用寄存器r8来存放该指针。而对gd_t结构体的定义从上面的第36行开始:
[code]
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long reloc_off; /* Relocation Offset */
unsigned long env_addr; /* Address of Environment struct */
unsigned long env_valid; /* Checksum of Environment valid? */
unsigned long fb_base; /* base address of frame buffer */
#ifdef CONFIG_VFD
unsigned char vfd_type; /* display type */
#endif
#if 0
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
unsigned long ram_size; /* RAM size */
unsigned long reset_status; /* reset status register at boot */
#endif
void **jt; /* jump table */
} gd_t;
[/code]
在lib_arm/board.c文件中之所以能够直接使用这个宏和gd_t结构体是因为包含了include/common.h头文件,在common.h的第115行包含了include/asm-arm/global_data.h头文件。
继续来看start_armboot()函数的执行。lib_arm/board.c第229行开始的一个for循环:
[code]
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
[/code]
这里的init_sequence是定义在上面第190行处的一个指针数组:
[code]
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
dram_init, /* configure available RAM banks */
display_dram_config,
#if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)
checkboard,
#endif
NULL,
};
[/code]
数组类型init_fnc_t则是一个定义在第188行的函数指针类型:
[code]
typedef int (init_fnc_t) (void);
[/code]
由此可知,init_sequence[]数组当中的所有元素都是函数指针了,而这个for循环的作用就是遍历这个数组的所有元素,然后用“(*init_fnc_ptr)()”就依次调用了这些函数来进行初始化的工作。
书接上回,我们依次来看看init_sequence[]数组当中的各个元素。
首先是cpu_init()函数,定义于lib_arm/arm920t/cpu.c第88行。
接下来的board_init()函数定义于board/smdk2410/smdk2410.c第68行:
int board_init (void) { DECLARE_GLOBAL_DATA_PTR; S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
/* to reduce PLL lock time, adjust the LOCKTIME register */ clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */ clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
/* some delay between MPLL and UPLL */ delay (4000);
/* configure UPLL */ clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
/* some delay between MPLL and UPLL */ delay (8000);
/* set up the I/O ports */ gpio->GPACON = 0x007FFFFF; gpio->GPBCON = 0x00044555; gpio->GPBUP = 0x000007FF; gpio->GPCCON = 0xAAAAAAAA; gpio->GPCUP = 0x0000FFFF; gpio->GPDCON = 0xAAAAAAAA; gpio->GPDUP = 0x0000FFFF; gpio->GPECON = 0xAAAAAAAA; gpio->GPEUP = 0x0000FFFF; gpio->GPFCON = 0x000055AA; gpio->GPFUP = 0x000000FF; gpio->GPGCON = 0xFF95FFBA; gpio->GPGUP = 0x0000FFFF; gpio->GPHCON = 0x002AFAAA; gpio->GPHUP = 0x000007FF;
/* arch number of SMDK2410-Board */ gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
/* adress of boot parameters */ gd->bd->bi_boot_params = 0x30000100;
icache_enable(); dcache_enable();
return 0; }
|
interrupt_init()函数定义于cpu/arm920t/s3c24x0/interrupts.c第55行:
int interrupt_init (void) { S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();
/* use PWM Timer 4 because it has no output */ /* prescaler for Timer 4 is 16 */ timers->TCFG0 = 0x0f00; if (timer_load_val == 0) { /* * for 10 ms clock period @ PCLK with 4 bit divider = 1/2 * (default) and prescaler = 16. Should be 10390 * @33.25MHz and 15625 @ 50 MHz */ timer_load_val = get_PCLK()/(2 * 16 * 100); } /* load value for 10 ms timeout */ lastdec = timers->TCNTB4 = timer_load_val; /* auto load, manual update of Timer 4 */ timers->TCON = (timers->TCON & ~0x0700000) | 0x600000; /* auto load, start Timer 4 */ timers->TCON = (timers->TCON & ~0x0700000) | 0x500000; timestamp = 0;
return (0); }
|