1、board_init_f和board_init_r(uboot/common/board_r.c、board_f.c)
board_init_f调用init_sequence_f[]中数组元素表示的函数接口。board_init_r调用init_sequence_r[]中数组元素表示的函数接口。
board_init_f是uboot重定位前的流程,它包括一些基础模块的初始化和重定位相关的准备工作。board_init_r是uboot重定位后需要执行的流程,它包含基础模块、硬件驱动以及板级特性等的初始化,并最终通过run_main_loop启动os会进入命令行窗口。
2、U_BOOT_DRIVER
新版u-boot都支持设备树,和linux一样,u-boot这里也建立了一个驱动模型。比如, of_match来匹配,probe来识别等。
定义一个U_BOOT_DRIVER:
U_BOOT_DRIVER(mtk_eth) = {
.name = "mtk-eth",
.id = UCLASS_ETH,
.of_match = mtk_eth_ids,
.of_to_plat = mtk_eth_of_to_plat,
.plat_auto = sizeof(struct eth_pdata),
.probe = mtk_eth_probe,
.remove = mtk_eth_remove,
.ops = &mtk_eth_ops,
.priv_auto = sizeof(struct mtk_eth_priv),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
//其中:
/* Declare a new U-Boot driver */
#define U_BOOT_DRIVER(__name) \
ll_entry_declare(struct driver, __name, driver)
#define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name)))
使用U_BOOT_DRIVER宏都会指向u_boot_list_2_xx段,展开后,相当于定义了一个struct driver类型的变量
对于struct driver结构体来看:
struct driver {
char *name;
enum uclass_id id;
const struct udevice_id *of_match;
int (*bind)(struct udevice *dev);
int (*probe)(struct udevice *dev);
int (*remove)(struct udevice *dev);
int (*unbind)(struct udevice *dev);
int (*ofdata_to_platdata)(struct udevice *dev);
int (*child_post_bind)(struct udevice *dev);
int (*child_pre_probe)(struct udevice *dev);
int (*child_post_remove)(struct udevice *dev);
int priv_auto_alloc_size;
int platdata_auto_alloc_size;
int per_child_auto_alloc_size;
int per_child_platdata_auto_alloc_size;
const void *ops; /* driver-specific operations */
uint32_t flags;
};
看起来和linux确实很像。 再回来看链接脚本arch/arm/cpu/u-boot.lds
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
}
设备驱动模型调用流程:
init_sequence_f[] // comman/board_f.c
initf_dm
dm_init_and_scan
dm_init
dm_scan_platdata
dm_scan_fdt
dm_scan_other
dm_timer_init
int dm_init(void)
{
int ret;
if (gd->dm_root) {
dm_warn("Virtual root driver already exists!\n");
return -EINVAL;
}
INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
if (ret)
return ret;
ret = device_probe(DM_ROOT_NON_CONST);
if (ret)
return ret;
return 0;
}
// device_bind_by_name里面根据名字绑定
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
const struct driver_info *info, struct udevice **devp)
{
lists_driver_lookup_name(info->name);
...
return device_bind_common(parent, drv, info->name,
}
//其中device_bind_common是核心,其与uclass建立关系,里面调用uclass_bind_device
在初始化里面主要调用dm_scan_platdata来解析设备树信息并保存
int dm_scan_platdata(bool pre_reloc_only)
{
int ret;
ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
if (ret == -ENOENT) {
dm_warn("Some drivers were not found\n");
ret = 0;
}
return ret;
}
int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
{
struct driver_info *info =
ll_entry_start(struct driver_info, driver_info);
const int n_ents = ll_entry_count(struct driver_info, driver_info);
struct driver_info *entry;
struct udevice *dev;
int result = 0;
int ret;
for (entry = info; entry != info + n_ents; entry++) { // 扫描
ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
if (ret && ret != -EPERM) {
dm_warn("No match for driver '%s'\n", entry->name);
if (!result || ret != -ENOENT)
result = ret;
}
}
return result;
}
然后再调用dm_scan_fdt_node分解子节点。
参考链接:https://blog.csdn.net/qq_21353001/article/details/91337650