【u-boot】u-boot对设备树的节点解析

1,设备树的引入

2,uboot本身对设备树的支持

3,对uboot中设备树节点解析代码的分析

(1)上一篇文章中提到函数 dm_init_and_scan(bool pre_reloc_only) 中有对设备树节点解析的函数dm_extended_scan_fdt()该函数的主要作用就是扫描设备树中的节点,并创立对应的设备驱动等结构的绑定工作。
先看对应的代码

int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
{
	ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
	//顾名思义,该函数就是扫描设备树并与设备驱动建立联系
	ret = dm_scan_fdt_ofnode_path("/clocks", pre_reloc_only);
	ret = dm_scan_fdt_ofnode_path("/firmware", pre_reloc_only);
	//上面这两个该函数扫描clocks节点和firmware节点
}

重点看第一个函数的具体实现过程

int dm_scan_fdt(const void *blob, bool pre_reloc_only)
{
#if CONFIG_IS_ENABLED(OF_LIVE)
	if (of_live_active())
		return dm_scan_fdt_live(gd->dm_root, gd->of_root,
					pre_reloc_only);
	else
#endif
	return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
}

由于没有定义OF_LIVE宏,所以该函数最终调用的是dm_scan_fdt_node函数,那么接下来看该函数的实现过程

tatic int dm_scan_fdt_node(struct udevice *parent, const void *blob,
			    int offset, bool pre_reloc_only)
{
	int ret = 0, err;
	//从偏移offset处开始一个个的扫描节点(node)
	for (offset = fdt_first_subnode(blob, offset); offset > 0; offset = fdt_next_subnode(blob, offset))
		{
		const char *node_name = fdt_get_name(blob, offset, NULL);
		 /*chosen或者firmware节点本身不是一个设备,但是有可能包含其他设备节点,
		 扫描其子节点*/
		if (!strcmp(node_name, "chosen") ||
		    !strcmp(node_name, "firmware")) {
			pr_debug("parsing subnodes of \"%s\"\n", node_name);

			err = dm_scan_fdt_node(parent, blob, offset,
					       pre_reloc_only);
			if (err && !ret)
				ret = err;
			continue;//没有子节点的话则继续扫描下一个节点
		}

		if (!fdtdec_get_is_enabled(blob, offset)) {//忽略失能设备
			pr_debug("   - ignoring disabled device\n");
			continue;
		}
		err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL,
				     pre_reloc_only);
		if (err && !ret) {
			ret = err;
			debug("%s: ret=%d\n", node_name, ret);
		}
	}

	if (ret)
		dm_warn("Some drivers failed to bind\n");

	return ret;
}
int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
		   bool pre_reloc_only)
{
	struct driver *driver = ll_entry_start(struct driver, driver);
	const int n_ents = ll_entry_count(struct driver, driver);
	const struct udevice_id *id;
	struct driver *entry;
	struct udevice *dev;
	bool found = false;
	const char *name, *compat_list, *compat;
	int compat_length, i;
	int result = 0;
	int ret = 0;

	if (devp)
		*devp = NULL;
	name = ofnode_get_name(node);
	pr_debug("bind node %s\n", name);

	compat_list = ofnode_get_property(node, "compatible", &compat_length);
	if (!compat_list) {
		if (compat_length == -FDT_ERR_NOTFOUND) {
			pr_debug("Device '%s' has no compatible string\n",
				 name);
			return 0;//这里直接返回,设备能bind的话,需要设备节点有 compatible 属性
		}

		dm_warn("Device tree error at node '%s'\n", name);
		return compat_length;
	}
	 //遍历compatible 字符串列表
	for (i = 0; i < compat_length; i += strlen(compat) + 1) {
		compat = compat_list + i;
		pr_debug("   - attempt to match compatible string '%s'\n",
			 compat);

		for (entry = driver; entry != driver + n_ents; entry++) {
			ret = driver_check_compatible(entry->of_match, &id,
						      compat);
			if (!ret)//遍历driver段表,找到相对应的driver
				break;
		}
		if (entry == driver + n_ents)
			continue;

		if (pre_reloc_only) {
			if (!dm_ofnode_pre_reloc(node) &&
			    !(entry->flags & DM_FLAG_PRE_RELOC))
				return 0;
		}

		pr_debug("   - found match at '%s'\n", entry->name);
		ret = device_bind_with_driver_data(parent, entry, name,
						   id->data, node, &dev);
		if (ret == -ENODEV) {
			pr_debug("Driver '%s' refuses to bind\n", entry->name);
			continue;
		}
		if (ret) {
			dm_warn("Error binding driver '%s': %d\n", entry->name,
				ret);
			return ret;
		} else {
			found = true;
			if (devp)
				*devp = dev;
		}
		break;
	}

	if (!found && !result && ret != -ENODEV)
		pr_debug("No match for node '%s'\n", name);

	return result;
}

函数device_bind_with_driver_data()最终调用的是device_bind_common()函数。

你可能感兴趣的:(uboot)