U_BOOT_DRIVER简析

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

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值