uboot 在start.S中完成了第一阶段启动后,由汇编语言调用C语言函数start_armboot进入第二阶段的启动,在海思给的Uboot代码中,该函数定义在/u-boot-2010.06/arch/arm/lib/board.c。它主要完成了:
说明:对于官方默认没有配置的功能都直接跳过,不做详细的介绍。
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr; //①
char *s;
#ifdef CONFIG_HAS_SLAVE
char *e;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)); //②
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t)); //③
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
gd->flags |= GD_FLG_RELOC; //④
monitor_flash_len = _bss_start - _armboot_start; //⑤
结构体的内容为:
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
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
#ifdef CONFIG_FSL_ESDHC
unsigned long sdhc_clk;
#endif
#if 0
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
phys_size_t ram_size; /* RAM size */
unsigned long reset_status;/* reset status register at boot */
#endif
void **jt; /* jump table */
} gd_t;
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
struct environment_s *bi_env;
ulong bi_arch_number; /* unique id for this board */
ulong bi_boot_params; /* where this board expects params */
struct /* RAM configuration */
{
ulong start;
ulong size;
} bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
timer_init, /* initialize timer before usb init */
board_init, /* basic board dependent setup */ //①
#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
#endif
// timer_init, /* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
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 */ //⑥
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */ //⑦
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
/* display_dram_config */
NULL,
};
int board_init(void)
{
unsigned long reg;
/* set uart clk from XTAL OSC 24M */
reg = readl(CRG_REG_BASE + PERI_CRG33);
reg &= ~UART_CKSEL_MASK;
reg |= UART_CKSEL_24M;
writel(reg, CRG_REG_BASE + PERI_CRG33);
DECLARE_GLOBAL_DATA_PTR;
gd->bd->bi_arch_number = MACH_TYPE_HI3521A;
gd->bd->bi_boot_params = CFG_BOOT_PARAMS;
gd->flags = 0;
boot_flag_init();
return 0;
}
boot_flag_init()启动类型判断
void boot_flag_init(void)
{
unsigned int regval, device_type;
/* get boot device type */
regval = __raw_readl(SYS_CTRL_REG_BASE + REG_SYSSTAT);
device_type = (regval >> 8) & 0x1;
switch (device_type) {
/* spi nor device */
case 0:
boot_media = BOOT_MEDIA_SPIFLASH;
break;
/* spi nand device */
case 1:
boot_media = BOOT_MEDIA_NAND;
break;
default:
boot_media = BOOT_MEDIA_SPIFLASH;
break;
}
}
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
#ifdef CONFIG_CMD_SF
#if (defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556)
if(get_boot_media() == BOOT_MEDIA_SPIFLASH) {
#endif
spi_flash_probe(0, 0, 0, 0);//①
#if (defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556)
}
#endif
#endif
/* it is not needed in A7 in A17-A7 */
#ifdef CONFIG_CMD_NAND
#if (defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556)
if(get_boot_media() == BOOT_MEDIA_NAND) {
#endif
nand_init(); /* go init the NAND */ //②
#if (defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556)
}
#endif
#endif
Check Flash Memory Controller v100 ... Found
SPI Nor(cs 0) ID: 0xc2 0x20 0x19
Block:64KB Chip:32MB Name:"MX25L(256/257)XX"
SPI Nor total size: 32MB
SPI Nand(cs 1) ID: 0xc2 0x12 Name:"MX35LF1GE4AB"
Block:128KB Page:2KB Chip:128MB*1 OOB:64B ECC:4bit/512
ECC provided by Flash Memory Controller
SPI Nand total size: 128MB
env_relocate
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); //①
stdio_init (); /* get the devices list going. */ //②
jumptable_init (); //③
#if defined(CONFIG_API)
/* Initialize API */
api_init ();
#endif
console_init_r (); /* fully init console as a device */ //④
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r (); //⑤
#endif
/* enable exceptions */
enable_interrupts (); //⑥
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) { //①
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) { //②
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) { //③
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd); //④
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
#if defined(CONFIG_BOOTROM_SUPPORT) && (!defined(CONFIG_ARCH_HI3559) && !defined(CONFIG_ARCH_HI3556))
extern void download_boot(const int (*handle)(void));
download_boot(NULL);
#endif
#ifdef CONFIG_HAS_SLAVE
e = getenv("slave_autostart");
if (e && (*e == '1'))
slave_start();
#endif
#ifdef CONFIG_DDR_TRAINING_V300
check_ddr_training();
#endif /* CONFIG_DDR_TRAINING_V300 */
product_control(); //⑤
#ifdef CONFIG_SNAPSHOT_BOOT
/* example */
/* set_mtdparts_info("mtdparts=hinand:1M(boot),3M(kernel),64M(rootfs),2M(param),16M(hibernate)"); */
extern void comp_save_snapshot_image(void);
comp_save_snapshot_image();
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
在这里的最后一步就是进入了一个死循环main_loop(),等待用户命令的输入。如果uboot超时没有接收到用户输入命令,则执行环境变量bootcmd中的命令,使用bootcmd环境变量中的命令来引导内核的启动。关于uboot命令解析,可以查看博客《bootm启动命令解析》,其它uboot内容可以查看博客《序言与目录》。