Uboot的启动过程大同小异,rk3288的uboot启动也是分为两个过程:
uboot的启动由arch/arm/cpu/armv7/start.S 开始,调用了_main,而_main 的实现是在arch/arm/lib/crt0.S中完成,在_main中主要完成以下几个任务:
1、为调用board_init_f 设置初始环境,这个环境起始就是提供了一个堆栈和一个存储GD结构体的地方。
2、调用board_init_f。在这里会初始化串口、timer、计算重定位的位置等。
3、调用relocate_code将uboot从当前我位置重定位到上一步计算到的addr。
4、调用board_init_r。这里大多都是c代码实现了,在初始化堆栈后完成各种初始化,lcd点亮logo也是在这个函数中实现。并且最后会调用do_bootm_linux 来启动内核,
5、当没有立即启动内核时,会调用到run_main_loop,进入uboot的cmd处理阶段。
整体代码调用流程:
/*arch/arm/cpu/armv7/start.S*/
bl _main
/*arch/arm/lib/crt0.S*/
/* 以ENTRY(_main)为入口 主要调用流程如下:*/
ENTRY(_main)
/* 设置初始化环境:在RAM中提供一个临时的堆栈和一个GD */
ldr sp, =(CONFIG_SPL_STACK)
...
/* 调用board_init_f */
bl board_init_f
/*common/board_f.c*/
/* 注意此时只有一个简单的初始化环境只能使用GD来传递数据*/
void board_init_f(ulong boot_flags)
/* 挨个调用list中的函数 */
if (initcall_run_list(init_sequence_f))
arch_cpu_init, /* basic arch cpu dependent setup */
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_options, /* say that we are here */
display_text_info, /* show debugging info if required */
print_cpuinfo, /* display cpu info (and speed) */
dram_init_f, /* configure available RAM banks */
calculate_relocation_address, /* 计算重定位的位置 */
announce_dram_init,
setup_dram_config,
show_dram_config,
/* 调用重定位代码 ,重定位至board_init_f 计算出的addr */
b relocate_code
/* 调用board_init_r */
ldr pc, =board_init_r
/* commod/board_r.c */
void board_init_r(gd_t *new_gd, ulong dest_addr)
/* 一次调用list中的函数 */
if (initcall_run_list(init_sequence_r))
initr_trace,
initr_malloc,
board_init, /* Setup chipselects */
initr_serial, /* 串口初始化 */
serial_initialize();
interrupt_init
/* /u-boot/board/rockchip/rk32xx/rk32xx.c */
board_late_init,
int board_late_init(void)
board_init_adjust_env();
/* /u-boot/board/rockchip/common/rkloader/parameter.c */
load_disk_partitions();
int load_disk_partitions(void)
/* 设备树解析 */
/* /u-boot/board/rockchip/common/rkloader/rkimage.c */
rkimage_prepare_fdt();
/* 从boot或者resource image读取fdt地址,resource会覆盖boot.img的fdt. */
content = rkimage_load_fdt(get_disk_partition(RESOURCE_NAME));
pmic_init(0);
/* PWM 初始化 */
pwm_regulator_init();
fg_init(0); /*fuel gauge init*/
/* /board/rockchip/common/rkboot/fastboot.c */
board_fbt_preboot();
void board_fbt_preboot(void)
fbt_fastboot_init();
/* Uboot lcd 显示logo */
#ifdef CONFIG_LCD
g_logo_on_state = 0; /* 判断是否显示logo的标记位 */
g_logo_on_state = fdtdec_get_int(gd->fdt_blob, node, "rockchip,uboot-logo-on", 0);
/* 根据dts中的值来确定是否显示logo */
if (g_logo_on_state != 0) {
lcd_enable_logo(true);
drv_lcd_init();
}
/* 低电量、未充电关机 */
board_fbt_low_power_off();
lcd_standby(0);
/* 先显示再点亮背光 */
rk_pwm_bl_config(-1);
rkloader_run_misc_cmd();
/*/board/rockchip/common/rkloader/rkloader.c*/
int rkloader_run_misc_cmd(void)
/* common/cmd_bootrk.c */
char *const boot_cmd[] = {"bootrk", "recovery"}
do_bootrk(NULL, 0, ARRAY_SIZE(boot_cmd), boot_cmd);
/* 启动内核 */
do_bootm_linux(0, 0, NULL, &images);
boot_prep_linux(images);
boot_jump_linux(images, flag);
run_main_loop,
/* 当没有立即启动kernel时,进入uboot 的最终循环,处理各种cmd,也可以通过cmd启动kernel */
for (;;)
/* common/main.c */
main_loop();
bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
modem_init();
cli_init();
run_preboot_environment_command();
实际uboot启动打印信息: