从上节我们知道,C语言部分主要集中在两个函数board_init_f和board_init_r,主要是board初始化的前部分(front)及后部分(rear),我们先来看board_init_f函数的实现:
common/board_f.c
void board_init_f(ulong boot_flags)
{
....
gd->flags = boot_flags;
gd->have_console = 0;
if (initcall_run_list(init_sequence_f))
hang();
....
}
board_init_f() 函数的实现很简单,主要就是执行init_sequence_f里面包含的函数的初始化。
static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX
setup_ram_buf,
#endif
setup_mon_len,
setup_fdt,
#ifdef CONFIG_TRACE
trace_early_init,
#endif
initf_malloc,
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
/* TODO: can this go into arch_cpu_init()? */
probecpu,
#endif
arch_cpu_init, /* basic arch cpu dependent setup */
mark_bootstage,
#ifdef CONFIG_OF_CONTROL
fdtdec_check_fdt,
#endif
initf_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
/* TODO: can any of this go into arch_cpu_init()? */
#if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
get_clocks, /* get CPU and bus clocks (etc.) */
#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
&& !defined(CONFIG_TQM885D)
adjust_sdram_tbs_8xx,
#endif
/* TODO: can we rename this to timer_init()? */
init_timebase,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_BLACKFIN)
timer_init, /* initialize timer */
#endif
#ifdef CONFIG_SYS_ALLOC_DPRAM
#if !defined(CONFIG_CPM2)
dpram_init,
#endif
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
#if defined(CONFIG_8xx_CPUCLK_DEFAULT)
/* get CPU and bus clocks according to the environment variable */
get_clocks_866,
/* adjust sdram refresh rate according to the new clock */
sdram_adjust_866,
init_timebase,
#endif
init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
#ifdef CONFIG_SANDBOX
sandbox_early_getopt_check,
#endif
#ifdef CONFIG_OF_CONTROL
fdtdec_prepare_fdt,
#endif
display_options, /* say that we are here */
display_text_info, /* show debugging info if required */
#if defined(CONFIG_MPC8260)
prt_8260_rsr,
prt_8260_clks,
#endif /* CONFIG_MPC8260 */
#if defined(CONFIG_MPC83xx)
prt_83xx_rsr,
#endif
#ifdef CONFIG_PPC
checkcpu,
#endif
print_cpuinfo, /* display cpu info (and speed) */
#if defined(CONFIG_MPC5xxx)
prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
misc_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI)
init_func_spi,
#endif
announce_dram_init,
/* TODO: unify all these dram functions? */
#if defined(CONFIG_ARM) || defined(CONFIG_X86)
dram_init, /* configure available RAM banks */
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC)
init_func_ram,
#endif
#ifdef CONFIG_POST
post_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
testdram,
#endif /* CONFIG_SYS_DRAM_TEST */
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_POST
init_post,
#endif
INIT_FUNC_WATCHDOG_RESET
/*
* Now that we have DRAM mapped and working, we can
* relocate the code and continue running from DRAM.
*
* Reserve memory at end of RAM for (top down in that order):
* - area that won't get touched by U-Boot and Linux (optional)
* - kernel log buffer
* - protected RAM
* - LCD framebuffer
* - monitor code
* - board info struct
*/
setup_dest_addr,
#if defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2)
/* Blackfin u-boot monitor should be on top of the ram */
reserve_uboot,
#endif
#if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
reserve_logbuffer,
#endif
#ifdef CONFIG_PRAM
reserve_pram,
#endif
reserve_round_4k,
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
defined(CONFIG_ARM)
reserve_mmu,
#endif
#ifdef CONFIG_LCD
reserve_lcd,
#endif
reserve_trace,
/* TODO: Why the dependency on CONFIG_8xx? */
#if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
!defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
!defined(CONFIG_BLACKFIN)
reserve_video,
#endif
#if !defined(CONFIG_BLACKFIN) && !defined(CONFIG_NIOS2)
reserve_uboot,
#endif
#ifndef CONFIG_SPL_BUILD
reserve_malloc,
reserve_board,
#endif
setup_machine,
reserve_global_data,
reserve_fdt,
reserve_stacks,
setup_dram_config,
show_dram_config,
#ifdef CONFIG_PPC
setup_board_part1,
INIT_FUNC_WATCHDOG_RESET
setup_board_part2,
#endif
display_new_sp,
#ifdef CONFIG_SYS_EXTBDINFO
setup_board_extra,
#endif
INIT_FUNC_WATCHDOG_RESET
reloc_fdt,
setup_reloc,
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
jump_to_copy,
#endif
NULL,
};
这里面的函数初始化很多,我们也不是都了解,大致的解释下我们知道的函数:
setup_fdt device tree相关的
initf_malloc 初始化malloc相关的global data
arch_cpu_init cpu级别的初始化操作
initf_dm driver model相关的初始化
board_early_init_f board相关的early的初始化操作,可以根据实际的情况完成board的early初始化,
具体定义在项目对于的C文件中,例如(axg_s400_v1.c)
get_clocks 获取CPU和BUS的时钟频率,并保存在global data中
timer_init 初始化系统的timer
env_init 环境变量相关的初始化
init_baud_rate 设置波特率
serial_init 初始化串口,初始化之后串口即可用
console_init_f 初始化控制台,
fdtdec_prepare_fdt device tree相关的准备操作
display_options
display_text_info 显示及打印一些debug信息
misc_init_f misc driver相关的初始化
init_func_i2c i2c driver相关的初始化
init_func_spi spi driver相关的初始化
announce_dram_init 仅仅打印DRAM,提示即将DDR的初始化
dram_init DDR初始化
testdram DDR测试
setup_dram_config 调用dram_init_banksize接口,初始化DDR的bank信息。
reloc_fdt device tree的relocation操作
setup_reloc 计算relocation有关的信息,主要是 gd->reloc_off
由于env是uboot中比较重要的一部分,我们来看看uboot相关的操作:
int env_init(void)
{
/* use default */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
return 0;
}
缺省的env主要是来自于default_environment, 我们来看看default_environment的定义(include/env_default.h):
const uchar default_environment[] = {......
ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
"bootargs=" CONFIG_BOOTARGS "\0"
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
"ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
"nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
"bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"
"baudrate=" __stringify(CONFIG_BAUDRATE) "\0"
"loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0"
"ethaddr=" __stringify(CONFIG_ETHADDR) "\0"
"eth1addr=" __stringify(CONFIG_ETH1ADDR) "\0"
"eth2addr=" __stringify(CONFIG_ETH2ADDR) "\0"
"eth3addr=" __stringify(CONFIG_ETH3ADDR) "\0"
"eth4addr=" __stringify(CONFIG_ETH4ADDR) "\0"
"eth5addr=" __stringify(CONFIG_ETH5ADDR) "\0"
"ethprime=" CONFIG_ETHPRIME "\0"
"ipaddr=" __stringify(CONFIG_IPADDR) "\0"
"serverip=" __stringify(CONFIG_SERVERIP) "\0"
"autoload=" CONFIG_SYS_AUTOLOAD "\0"
"preboot=" CONFIG_PREBOOT "\0"
"rootpath=" CONFIG_ROOTPATH "\0"
"gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0"
"netmask=" __stringify(CONFIG_NETMASK) "\0
"hostname=" __stringify(CONFIG_HOSTNAME) "\0"
"bootfile=" CONFIG_BOOTFILE "\0"
"loadaddr=" __stringify(CONFIG_LOADADDR) "\0"
"clocks_in_mhz=1\0"
"pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY)"\0"
"arch=" CONFIG_SYS_ARCH "\0"
"cpu=" CONFIG_SYS_CPU "\0"
"board=" CONFIG_SYS_BOARD "\0"
"board_name=" CONFIG_SYS_BOARD "\0"
"vendor=" CONFIG_SYS_VENDOR "\0"
"soc=" CONFIG_SYS_SOC "\0"
};
这里定义了一系列的uboot env变量及赋值,包括bootcmd,preboot等变量
我们在头文件axg_s400_v1.h头文件中,可以看到CONFIG_BOOTCOMMAND,CONFIG_PREBOOT,CONFIG_EXTRA_ENV_SETTINGS等的定义:
#define CONFIG_EXTRA_ENV_SETTINGS \
"firstboot=1\0"\
"jtag=apao\0"\
"loadaddr=1080000\0"\
"panel_type=lcd_0\0" \
"outputmode=panel\0" \
"osd_reverse=0\0"\
"video_reverse=0\0"\
bcb_cmd; "\..................
"factory_reset_poweroff_protect="\.......................................
"switch_bootmode="\....................................
................................
.................................
"storeboot="\.........................................
......................................................
#define CONFIG_PREBOOT \
"run bcb_cmd; "\
"run factory_reset_poweroff_protect;"\
"run upgrade_check;"\
"run init_display;"\
"run storeargs;"\
"run switch_bootmode;"
#define CONFIG_BOOTCOMMAND "run storeboot"
没有列出所有的,中间部分省略.......
CONFIG_EXTRA_ENV_SETTINGS: 定义的一些额外的env变量
CONFIG_PREBOOT:启动前执行的命令
CONFIG_BOOTCOMMAND:启动命令
我们分别解释下这几个命令:
CONFIG_BOOTCOMMAND "run storeboot"
"storeboot="\
"hdmitx output 1080p60hz;"\
"if imgread kernel boot ${loadaddr}; then bootm ${loadaddr}; fi;"\
"run update;"\
"\0"\
设置hdmi输出为1080p60Hz,读取boot分区到${loadaddr}即0x1080000地址,然后从0x1080000地址启动boot,如果启动失败,则run update,走升级烧录流程。
CONFIG_PREBOOT \
"run bcb_cmd; "\
"run factory_reset_poweroff_protect;"\
"run upgrade_check;"\
"run init_display;"\
"run storeargs;"\
"run switch_bootmode;"
读取misc分区的bcb command,查看是否有进入recovery的标志
判断是否有恢复出厂过程掉电标志,如果有,则进入recovery继续执行恢复出厂设置
判断是否有升级掉电标志,如果有升级过程掉电,则进入recovery继续升级。
OSD初始化,显示开机logo
设置启动参数bootargs
根据bootmode,选择进入不同的系统(recovery,fastboot等)
board_f.c主要的功能就是完成board的前部分初始化工作,我们主要关心的是uboot env的初始化的,后部分board_r.c的流程我们下节再详细描述。