u-boot 设备树处理

新版u-boot都支持设备树,和linux一样,u-boot这里也建立了一个驱动模型。比如, of_match来匹配,probe来识别等。

u-boot里面的驱动主要使用宏:

/* 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*)));
        }

再看一个实例, exynos4412里面的eMMC

static const struct udevice_id exynos_dwmmc_ids[] = {
	{ .compatible = "samsung,exynos4412-dw-mshc" },
	{ }
};

U_BOOT_DRIVER(exynos_dwmmc_drv) = {
	.name		= "exynos_dwmmc",
	.id		= UCLASS_MMC,
	.of_match	= exynos_dwmmc_ids,
	.bind		= exynos_dwmmc_bind,
	.ops		= &dm_dwmci_ops,
	.probe		= exynos_dwmmc_probe,
	.priv_auto_alloc_size	= sizeof(struct dwmci_exynos_priv_data),
	.platdata_auto_alloc_size = sizeof(struct exynos_mmc_plat),
};

驱动以{ .compatible = "samsung,exynos4412-dw-mshc" },来匹配的,再看下设备树里面

dwmmc@12550000 {
                compatible = "samsung,exynos4412-dw-mshc";
                samsung,bus-width = <8>;
                samsung,timing = <2 1 0>;
                samsung,removable = <0>;
                fifoth_val = <0x203f0040>;
                bus_hz = <400000000>;
                div = <0x3>;
                index = <4>;
        };

设备驱动模型调用流程是怎么样的呢?

 

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

再dm_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分解子节点。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值