一. uboot启动流程
本文来了解 board_init_r 函数执行过程。_main函数会调用到 board_init_r 函数。
二. board_init_r函数执行过程
_main 函数会调用到 board_init_r 函数。
_main 函数在 uboot的 /arch/arm/lib/crt0.S 文件中。_main函数中,执行完 relocate_vectors 函数(即重定位中断向量表)后,然后清 BSS 段,之后就是调用 board_init_r函数。
前面有文章讲解了 board_init_f 函数,在此函数里面会调用一系列的函数来初始化一些外设和 gd 的成员变量。但是 board_init_f 函数并没有初始化所有的外设,还需要做一些后续工作,这些后续工作就是由 board_init_r 函数来完成的,board_init_r 函数定义在文件 common/board_r.c 中,关键的代码如下:
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
......
if (initcall_run_list(init_sequence_r))
hang();
......
}
initcall_run_list
函数来执行初始化序列
init_sequence_r
,
init_sequence_r
是一个函数集合,
init_sequence_r
也定义在文件
common/board_r.c
中,由于
init_sequence_f
的内容
比较长,里面有大量的条件编译代码,这里为了缩小篇幅,将条件编译部分删除掉了,去掉条
件编译以后的
init_sequence_r
定义如下:
init_fnc_t init_sequence_r[] = {
initr_trace,
initr_reloc,
initr_caches,
initr_reloc_global_data,
initr_barrier,
initr_malloc,
initr_console_record,
bootstage_relocate,
initr_bootstage,
board_init, /* Setup chipselects */
stdio_init_tables,
initr_serial,
initr_announce,
INIT_FUNC_WATCHDOG_RESET
INIT_FUNC_WATCHDOG_RESET
INIT_FUNC_WATCHDOG_RESET
power_init_board,
initr_flash,
INIT_FUNC_WATCHDOG_RESET
initr_nand,
initr_mmc,
initr_env,
INIT_FUNC_WATCHDOG_RESET
initr_secondary_cpu,
INIT_FUNC_WATCHDOG_RESET
stdio_add_devices,
initr_jumptable,
console_init_r, /* fully init console as a device */
INIT_FUNC_WATCHDOG_RESET
interrupt_init,
initr_enable_interrupts,
initr_ethaddr,
board_late_init,
INIT_FUNC_WATCHDOG_RESET
INIT_FUNC_WATCHDOG_RESET
INIT_FUNC_WATCHDOG_RESET
initr_net,
INIT_FUNC_WATCHDOG_RESET
run_main_loop,
};
第
2
行,
initr_trace
函数,如果定义了宏
CONFIG_TRACE
的话就会调用函数
trace_init
,初始化和调试跟踪有关的内容。
第
3
行,
initr_reloc
函数用于设置
gd->flags
,标记重定位完成。
第
4
行,
initr_caches
函数用于初始化
cache
,使能
cache
。
第
5
行,
initr_reloc_global_data
函数,初始化重定位后
gd
的一些成员变量。
第
6
行,
initr_barrier
函数,
I.MX6ULL
未用到。
第
7
行,
initr_malloc
函数,初始化
malloc
。
第
8
行,
initr_console_record
函数,初始化控制台相关的内容,
I.MX6ULL
未用到,空函数。
第
9
行,
bootstage_relocate
函数,启动状态重定位。
第
10
行,
initr_bootstage
函数,初始化
bootstage
什么的。
第
11
行,
board_init
函数,板级初始化,包括
74XX
芯片,
I2C
、
FEC
、
USB
和
QSPI
等。
这里 board_init 函数调用的是 mx6ull_alientek_nand.c文件中(因为这里我所使用的是 Nand-Flash版的开发板)
第
12
行,
stdio_init_tables
函数,
stdio
相关初始化。
第
13
行,
initr_serial
函数,初始化串口。
第
14
行,
initr_announce
函数,与调试有关,通知已经在
RAM
中运行。
第
18
行,
power_init_board
函数,初始化电源芯片,正点原子的
I.MX6ULL
开发板没有用到。
第
19
行,
initr_flash
函数,对于
I.MX6ULL
而言,没有定义宏
CONFIG_SYS_NO_FLASH 的话函数
initr_flash
才有效。但是
mx6_common.h
中定义了宏
CONFIG_SYS_NO_FLASH
,所以
此函数无效。
第
21
行,
initr_nand
函数,初始化
NAND
,如果使用
NAND
版本核心板的话就会初始化
NAND
。
第
22
行,
initr_mmc
函数,初始化
EMMC
,如果使用
EMMC
版本核心板的话就会初始化
EMMC。就会有 MMC打印信息。
第
23
行,
initr_env
函数,初始化环境变量。
第
25
行,
initr_secondary_cpu
函数,初始化其他
CPU
核,
I.MX6ULL
只有一个核,因此此
函数没用。
第
27
行,
stdio_add_devices
函数,各种输入输出设备的初始化,如
LCD driver
,
I.MX6ULL
使用
drv_video_init
函数初始化
LCD
。我所使用的开发板未带LCD屏幕,所以用不到。
第 28 行,initr_jumptable 函数,初始化跳转表。
第
29
行 ,
console_init_r
函 数 , 控 制 台 初 始 化 , 初 始 化 完 成 以 后 此 函 数 会 调 用
stdio_print_current_devices
函数来打印出当前的控制台设备。串口打印如下:
In: serial
Out: serial
Err: serial
第
31
行,
interrupt_init
函数,初始化中断。
第
32
行,
initr_enable_interrupts
函数,使能中断。
第
33
行,
initr_ethaddr
函数,初始化网络地址,也就是获取
MAC
地址。读取环境变量 “
ethaddr” 的值。
第
34
行,
board_late_init
函数,板子后续初始化,此函数定义在文件
mx6ull_alientek_emmc.c
中,如果环境变量存储在
EMMC
或者
SD
卡中的话此函数会调用
board_late_mmc_env_init
函数
初始化
EMMC/SD
。会切换到正在时候用的
emmc
设备。
注意: 类似 CONFIG_CMD_SCSI这种带 CMD的是 uboot支持的 命令。配置是否使用该命令的文件是 mx6ull_alientek_nand.h。
第
38
行 ,
initr_net
函 数 , 初 始 化 网 络 设 备 , 函 数 调 用 顺 序 为 :
initr_net->eth_initialize->board_eth_init()
串口打印如下:
Net: FEC1
第 40 行,run_main_loop函数 ,是主循环,处理
uboot命令行模式下输入的
命令。
uboot命令行模式:开发板上电时,uboot启动时会进入几秒的倒计时,如果在倒计时之前按下 "Enter"回车键,会进入 uboot命令行模式。uboot命令行模式下可以输入命令,开发板可以接收到 输入的命令。如下就是进入了uboot命令行模式:

以上就是 board_init_r函数大体执行过程。