3.6.3. MMC 加载

SPL 从 MMC 加载 U-Boot 的处理过程。

程序编码的时候,针对 MMC 设备添加了对应的加载程序支持,如 spl_mmc.c 中,通过使用宏:

SPL_LOAD_IMAGE_METHOD(“MMC1”, 0, BOOT_DEVICE_MMC1, spl_mmc_load_image);

spl_mmc_load_image 函数添加到 .u_boot_list_2_spl_image_loader_* 段。

在 SPL 初始化过程中,通过 boot_from_devices(spl_boot_list) 函数调用,检查当前项目 所支持的 SPL 读取的存储介质类型,然后依次检查是否存在对应的程序加载器。

board_init_r()    // common/spl/spl.c
|-> boot_from_devices(spl_boot_list)
    |-> spl_ll_find_loader()  // 根据boot device找到spl_load_image指针
            // 这里可能是各种介质的 load image 函数
            // SPL_LOAD_IMAGE_METHOD() 定义的 Loader
            // 可能是 MMC/SPI/BROM/...

找到 SPL MMC Loader 之后,从项目配置的指定 Sector 读取数据。

  • CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR

boot_from_devices(spl_boot_list); // common/spl/spl.c
|-> spl_ll_find_loader()  // 根据boot device找到spl_load_image指针
|   // 此处通过遍历固件的 .u_boot_list_2_spl_image_loader_* 段
|   // 找到当前支持的存储介质,然后逐个尝试
|
|-> spl_load_image(loader);
    |-> loader->load_image(spl_image, &bootdev);
        spl_mmc_load_image();  // common/spl/spl_mmc.c
        |-> spl_mmc_load();
                    |
      +-------------+
      |
spl_mmc_load();
|-> spl_mmc_find_device(&mmc, bootdev->boot_device);
|   |-> mmc_initialize
|       |-> mmc_probe
|           |-> uclass_get(UCLASS_MMC, &uc)
|           |-> device_probe(dev)
|               |-> uclass_resolve_seq(dev)
|               |-> pinctrl_select_state(dev, "default")
|               |   |-> pinctrl_select_state_full(dev, "default")
|               |   |   |-> state = dev_read_stringlist_search(dev,
|               |   |   |                       "pinctrl-names", "default");
|               |   |   |-> dev_read_prop(dev, propname, &size)
|               |   |   |   // snprintf(propname, sizeof(propname),
|               |   |   |   //              "pinctrl-%d", state)
|               |   |   |
|               |   |   |-> pinctrl_config_one(config)
|               |   |       |-> ops = pinctrl_get_ops(pctldev)
|               |   |       |-> ops->set_state(pctldev, config)
|               |   |
|               |   |-> pinctrl_select_state_simple(dev)
|               |       |-> uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &pctldev)
|               |       |-> ops=pinctrl_get_ops(pctldev)
|               |       |   // #define pinctrl_get_ops(dev)
|               |       |   //         ((struct pinctrl_ops *)(dev)->driver->ops)
|               |       |
|               |       |-> ops->set_state_simple(pctldev, dev)
|               |
|               |-> power_domain_on(&powerdomain)
|               |-> uclass_pre_probe_device(dev)
|               |-> clk_set_defaults(dev)
|               |   |-> clk_set_default_parents(dev)
|               |   |-> clk_set_default_rates(dev)
|               |
|               |-> drv->probe(dev)
|               |-> uclass_post_probe_device(dev)
|
|-> mmc_init
|-> boot_mode=spl_boot_mode(bootdev->boot_device)
|-> mmc_load_image_raw_sector
    |-> header=spl_get_load_buffer(-sizeof(*header), bd->blksz)
    |   // header位于load_addr偏移-head_size处
    |
    |-> blk_dread(bd, sector, 1, header)
    |   // 读取一个sector的u-boot image header
    |
    |-> mmc_load_legacy(spl_image, mmc, sector, header)
    |   |-> spl_parse_image_header(spl_image, header)
    |   // 解析u-boot image header信息,得到u-boot的addr和size信息
    |
    |-> blk_dread(bd, sector, cnt, load_addr)
        // 读取完整的u-boot image,包括header,注意load_addr是向前偏移过的地址