RK3228开发之uboot启动流程

一、引言

本章系统的介绍RK3228主板uboot的启动流程

二、启动顺序

bl    board_init_f -> crt0.S
    initcall_run_list(init_sequence_f) -> board_f.c
        arch_cpu_init ->
            rk_get_chiptype    //获取chip type (rk31xx, rk32xx等)
        timer_init
        env_init
        init_baud_rate
        serial_init
        print_cpuinfo    //dump cpu/pll info
        dram_init    //获取size以及end address
        setup_dram_config ->
            dram_init_banksize
        show_dram_config
ldr    pc, =board_init_r -> crt0.S
    board_init_r ->        board_r.c
        init_sequence_r    //调用init_sequence_r中的各个函数。
            board_init     rk32xx.c //设置machine type以及boot param起始地址,kernel要用到。
            initr_serial ->    board_r.c //初始化串口。
                serial_initialize
            initr_rk_storage    ->     //初始化storage
                board_storage_init ->    rk32xx.c
                    StorageInit ->    storage.c    //初始化eMMC.
                        memFunTab[memdev]->Init    //调用emmcFunOp的SdmmcInit()
                            SdmmcInit    sdmmcBoot.c    这里还会根据sd里存的信息来区分是要boot还是update.
                        StorageReadFlashInfo ->
                            gpMemFun->ReadInfo ->
                                SdmmcReadFlashInfo    sdmmcBoot.c
            initr_env    //初始化u-boot中的环境变量
            stdio_add_devices ->    //不做什么。
            console_init_r    //作为device来管理。
            board_late_init ->    rk32xx.c
                board_init_adjust_env    //初始化bootdelay, bootcmd这些env.
                load_disk_partitions ->
                    GetParam
                    ParseParam    ->    //解析parameter文件
                        ParseLine    ->    //获取各个参数选项,如machine model, cmdline等。
                            parse_cmdline ->
                                mtdpart_parse    //获取分区表信息
                rkimage_prepare_fdt     rkimage.c //从boot或者resource image读取fdt地址,resource会覆盖boot.img的fdt.
                key_init    //各种key init
                pmic_init    ->    power_rockchip.c    //多个型号pmic的init,如rk808, rk818,一旦匹配到成功的就不再尝试其他的了。
                    pmic_act8846_init    //sdk board用的是此IC。
                    pmic_rk808_init    -> pmic_rk808.c //后续项目要替换成这颗。
                        rk808_parse_dt ->
                            fdt_device_is_available    //status为disabled就没必要解析了。
                            fdt_get_i2c_info    //获取i2c address, number, 
                            rk808_i2c_probe        //detect pmic.
                            fdt_get_regulator_node    //获取pmic regulator信息
                            fdt_regulator_match    //获取regulator初始化数据
                            rk808_set_regulator_init    //设置各regulator初始化电压
                            fdtdec_decode_gpios    //获取gpio内容, pwr_hold
                        charger_init
                        i2c_init
                    pmic_rk818_init
                pwm_regulator_init ->    //pwm init.
                    pwm_regulator_parse_dt
                fg_init    //gauge init.
                SecureBootCheck    
                board_fbt_preboot ->
                    fbt_fastboot_init
                    board_fbt_get_reboot_type    //读取reboot flag
                    board_fbt_key_pressed //再次检查key有没有按下来决定进入哪种模式。
                    board_fbt_low_power_check    //电量检查,过低就充电,如果失败就直接关机.
                    fdtdec_get_int    //读取u-boot是否显示logo值
                    drv_lcd_init ->    lcd.c
                        lcd_init ->
                            lcd_ctrl_init ->    rockchip_fb.c
                                rk_fb_parse_dt ->    //从dts中解析出lcd的参数。
                                                                    rk_fb_pwr_enable    //上电
                                rkclk_lcdc_clk_set    //设置clock
                                rk_lcdc_init    //lcdc控制器初始化
                                rk_lcdc_load_screen    //根据不同的接口设置不同的配置到控制器
                            lcd_clear ->
                                lcd_logo ->    //show logo
                                    bitmap_plot ->
                                        rk_bitmap_from_resource ->
                                            show_resource_image    -> //name是logo.bmp
                                                get_content ->
                                                    get_base_offset    //先从resoure分区获取,失败的话从boot分区获取.
                                                lcd_display_bitmap_center
                    board_fbt_low_power_off    //如果是低电量而且没在充电,那就显示fail的logo,1s后关机.
                    lcd_standby
                    rk_backlight_ctrl
                    board_fbt_run_recovery    //进recovery的情况
                    board_fbt_run_recovery_wipe_data    //wipe data的情况,也是进recovery
                    board_fbt_request_start_fastboot    //进fastboot mode
                    rkloader_run_misc_cmd    //其他情况
            run_main_loop ->
                main_loop //启动kernel
                    do_bootrk ->    cmd_bootrk.c
                        rk_load_image_from_storage ->
                            rkimage_load_image    //先尝试从boot.img读取内核以及ramdisk
                            StorageReadLba    //如果boot.img没有内核则从kernel中读取
                            rkimage_load_fdt    //从resource分区中读取fdt.
                        rk_load_kernel_logo    -> //加载kernel logo
                            get_content        //图片存在resource 分区
                        rk_commandline_setenv
                        do_bootm_linux    //加载kernel,这里就是标准u-boot的做法了.        

三、总结

在board_r的启动序列中有

board_late_init

{
.......
load_disk_partitions(这里解析了parameter参数)
.......
board_fbt_preboot()这里检测了按键并且执行了启动流程
........
}

board_fbt_preboot中对按键进行了检查。随后根据不同按键执行不同的函数。

如果没有进行其他按键。最后正常的启动流程会走入

rkloader_run_misc_cmd函数(在rkloader.c中)

先找到misc的分区信息,这个分区信息是从前面load_disk_partitions里面解析的结构中得到的。

从MISC分区中读取bootload message

const disk_partition_t *ptn = get_disk_partition(MISC_NAME);

bmsg = (struct bootloader_message *)buf;
if (StorageReadLba(ptn->start + MISC_COMMAND_OFFSET, buf, DIV_ROUND_UP(
sizeof(struct bootloader_message), RK_BLK_SIZE)) != 0) 

根据bmsg里面的命令执行。由于bmsg->command 既不是boot-recovery 也不是bootloader所以返回false

最终导致从board_late_init返回了。继续执行

最终到了main_loop
在main_loop里面进入cli_loop前执行了

autoboot_command(s);

只有一条指令。那就是bootrk

do_bootrk(NULL, 0, ARRAY_SIZE(boot_cmd), boot_cmd)

{

得到内核所在的分区信息默认先从boot分区开始

ptn = get_disk_partition(boot_source);

从分区中读取image到内存。并且取得image信息

hdr = rk_load_image_from_storage(ptn, &images);

设置命令行参数等等。也就是commandline这些 root=xxxxx这样的

rk_commandline_setenv(boot_source, hdr, charge);

接下来执行

do_bootm_linux(0, 0, NULL, &images); 正式启动内核。

}

rk_load_image_from_storage 首先从 boot分区中读取头部。查看头部是不是ANDROID!!

如果是的话。那么加载内核到内存中

如果不是,尝试使用rkimage_load_image从kernel分区和boot分区中读取内核和ramdisk

如果这次还是失败。

表示整个 rk_load_image_from_storage失败,执行 board_fbt_boot_failed 。再尝试从recovery分区执行do_bootrk

如果从recovery分区执行do_boottk还是失败。尝试从backup分区执行do_bootrk

如果还是失败。执行do_rockusb模式 等待usb刷机。

三、涉及到的文件

1、init_sequence_r :common/board_r.c //调用init_sequence_r中的各个函数。

2、board_late_init() board/rockchip/rk33xx/rk33xx.c

3、main_loop(): common/main.c
uboot启动进入命令行 与准备自动启动

4、autoboot_command() : common/autoboot.c 自动启动

5、board/rockchip/common/rkloader/parameter.h 分区表的定义

6、board/rockchip/common/rkloader/parameter.c 分区表的读取

7、board/rockchip/common/rkloader/rkloader.c 没有按键进入

你可能感兴趣的:(RK3228开发之uboot启动流程)