for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }

通过前面的定义init_fnc_t **init_fnc_ptr;可以知道init_fnc_ptr是一个二重指针,而init_sequence是一个函数指针数组里面存放的都是函数的函数名,这些函数都是板级初始化函数,*init_fnc_ptr解引用得到的就是一个函数指针,这个for循环的作用就是去遍历这个函数指针数组,而遍历的目的就是去执行这个函数指针数组里面的函数,从而对开发板的部分外设进行初始化。当遍历到最后一个元素NULL的时候跳出这个for循环。

init_fnc_t *init_sequence[] = {
    cpu_init,        /* basic cpu dependent setup */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)
    reloc_init,        /* Set the relocation done flag, must
                   do this AFTER cpu_init(), but as soon
                   as possible */
#endif
    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 */
#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 */
    display_dram_config,
    NULL,
};

(1)cpu_init:cpu内部初始化,实际这个函数是个空函数

(2)board_init:初始化网卡和DDR

(3)interrupt_init:初始化定时器4(用来计时比如bootdelay),这里设置的10ms计时一次

(4)env_init:环境变量设置

(5)init_baudrate:初始化波特率

(6)serial_init:串口初始化(串口在uboot启动的第一阶段已经完成了),这里实际啥也没干

(6)console_init_f控制台初始化的第一阶段(实际上我们没有用到控制台)

(7)display_banner:打印uboot的版本信息

(8)print_cpuinf:初始化时钟

(9)checkboard:打印时钟信息

(10)init_func_i2c:这里没有用到I2C的设备,所以无实际作用

(11)dram_init:gd->bd中关于DDR配置部分全局变量的赋值(大小 起始地址 等)

(12)display_dram_config:打印DDR的配置信息

(13)NULL:用于跳出for循环。


以上是uboot在第二阶段做的主要事情

env_relocate ();

环境变量的重定位,将SD卡中的环境变量读取到DDR中

需要注意的是SD卡中一开始是没有环境变量的,uboot第一次启动时环境变量是使用uboot中的配置头文件(如x210sd.h)中硬编码的一套默认的环境变量,当我启动uboot后使用saveen命令才会把环境变量写到SD卡的raw分区。以后使用的也是SD卡中的这一份环境变量。


uboot启动第二阶段的最后是进入一个死循环,输入命令  解析命令

for (;;) {  
        main_loop ();
    }

main_loop函数执行一次代表了一次命令的输入 解析  和执行。内核启动阶段也是从这个函数开始的。