所有dtb对应啥芯片

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了所有dtb对应啥芯片相关的知识,希望对你有一定的参考价值。

参考技术A 设备树的源文件为.dts和.dtsi文件,经过设备树专用的编译器编译后生成一个二进制的DTB(Device tree Blob)文件。在系统启动时,DTB文件由bootloader加载进内存,此时,内存中的DTB成为FDT(Flat Device Tree)。Bootloader启动kernel时,将FDT的地址传给Kernel,在Kernel启动的汇编阶段,将FDT地址保存在“x5”寄存器中,并定义8字节变量“__fdt_pointer”,用来表示该地址,以供Kernel的C代码使用

设备树——dtb格式到struct device node结构体的转换

1、参考资料

(1)《设备树 — dtb到device node的转换(三)》
(2)《linux设备树dts文件详解》

2、struct device_node结构体

struct device_node 
	const char *name;                    //节点的名字
	const char *type;                    //device_type属性的值
	phandle phandle;                     //对应该节点的phandle属性 
	const char *full_name;               //节点的名字, node-name[@unit-address]从“/”开始的,表示该node的full path 
	struct fwnode_handle fwnode;
 
	struct	property *properties;        // 节点的属性
	struct	property *deadprops;	/* removed properties 如果需要删除某些属性,kernel并非真的删除,而是挂入到deadprops的列表 */
	struct	device_node *parent;         // 节点的父亲
	struct	device_node *child;          // 节点的孩子(子节点)
	struct	device_node *sibling;        // 节点的兄弟(同级节点)
#if defined(CONFIG_OF_KOBJ)              // 在sys文件系统表示
	struct	kobject kobj;        
#endif
	unsigned long _flags;
	void	*data;
#if defined(CONFIG_SPARC)
	const char *path_component_name;
	unsigned int unique_id;
	struct of_irq_controller *irq_trans;
#endif
;

3、struct property结构体

struct property 
	char	*name;                //属性名字
	int	length;                   //value的长度
	void	*value;               //属性值
	struct property *next;        //指向统一节点的下一个属性
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
	unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
	unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
	struct bin_attribute attr;
#endif

;

4、转换过程的函数调用关系

unflatten_device_tree()	//解析dtb格式成struct device node结构体
	__unflatten_device_tree()
		unflatten_dt_nodes()	//计算解析出的struct device node结构体所需要的内存大小
			dt_alloc()	//申请上面计算出来的需要的内存
			unflatten_dt_nodes()	//将dtb数据解析成device node结构体,保存在上面申请的内存中
		
	of_alias_scan()	//处理aliases节点,根据节点的别名找到对应节点并保存到aliases_lookup链表中

5、__unflatten_device_tree()函数

5.1、函数调用

__unflatten_device_tree(initial_boot_params, NULL, &of_root,early_init_dt_alloc_memory_arch, false);
传参含义
initial_boot_paramsdtb数据的所在地址
of_root保存将来解析的struct device_node结构体的根节点
early_init_dt_alloc_memory_arch用于申请内存的函数
false觉得是否设置根节点的OF_DETACHED标志

5.2、函数源码

	__unflatten_device_tree(initial_boot_params, NULL, &of_root,
				early_init_dt_alloc_memory_arch, false);

static void *__unflatten_device_tree(const void *blob,
				     struct device_node *dad,
				     struct device_node **mynodes,
				     void *(*dt_alloc)(u64 size, u64 align),
				     bool detached)

	int size;
	void *mem;

	pr_debug(" -> unflatten_device_tree()\\n");

	if (!blob) 
		pr_debug("No device tree pointer\\n");
		return NULL;
	

	//打印dtb的相关信息
	pr_debug("Unflattening device tree:\\n");
	pr_debug("magic: %08x\\n", fdt_magic(blob));
	pr_debug("size: %08x\\n", fdt_totalsize(blob));
	pr_debug("version: %08x\\n", fdt_version(blob));

	//校验dtb的数据头
	if (fdt_check_header(blob)) 
		pr_err("Invalid device tree blob header\\n");
		return NULL;
	

	/* 第一次调用:计算解析出的struct device_node结构体所占内存大小 */
	size = unflatten_dt_nodes(blob, NULL, dad, NULL);
	if (size < 0)
		return NULL;

	//将内存大小4字节对齐
	size = ALIGN(size, 4);
	pr_debug("  size is %d, allocating...\\n", size);

	/* 申请解析设备树dtb数据需要的内存 */
	mem = dt_alloc(size + 4, __alignof__(struct device_node));
	if (!mem)
		return NULL;

	memset(mem, 0, size);

	//将申请内存空间的下一个地址处赋值为0xdeadbeef
	*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);

	pr_debug("  unflattening %p...\\n", mem);

	/* 第二次调用:解析dtb数据成device node结构体,保存在上面申请的内存中*/
	unflatten_dt_nodes(blob, mem, dad, mynodes);

	//检查解析的device_node结构体所占内存是否越界
	if (be32_to_cpup(mem + size) != 0xdeadbeef)
		pr_warning("End of tree marker overwritten: %08x\\n",
			   be32_to_cpup(mem + size));

	if (detached && mynodes) 
		of_node_set_flag(*mynodes, OF_DETACHED);
		pr_debug("unflattened tree is detached\\n");
	

	pr_debug(" <- unflatten_device_tree()\\n");
	return mem;
		

(1)unflatten_dt_nodes()会被调用两次,传参不同该函数会有不同的功能;第一次是计算所需内存大小,第二次是真正解析dtb数据成device_node格式;
(2)of_root变量保存的是根节点对应的struct device_node结构体

6、struct device_node *of_root变量

(1)无论是dtb格式还是struct device_node格式,里面表达的数据是没变的,只是组织形式不同,解析的方法就不同。dtb格式和struct device_node格式都有专门的解析函数,dtb格式下是需要知道dtb数据所在内存地址,struct device_node格式是需要知道根节点的struct device_node结构体;
(2)of_root就是保存的根节点的struct device_node结构体,后续解析设备树的信息就是利用of_root根节点和专门的解析函数即可;

7、struct device_node格式下如何解析出信息

7.1、相关文件和操作函数

(1)在struct device_node格式下内核提供相关的操作函数,具体查看"drivers/of/base.c"文件;
(2)我们调用相关的函数,可以通过节点路径、节点名字、父节点等方式去查找需要的device_node结构体;

7.2、of_alias_scan()函数

void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))

	struct property *pp;

	//通过节点的路径查看aliases节点
	of_aliases = of_find_node_by_path("/aliases");
	
	//通过节点的路径查看chosen节点
	of_chosen = of_find_node_by_path("/chosen");
	if (of_chosen == NULL)
		of_chosen = of_find_node_by_path("/chosen@0");

	if (of_chosen) 
		/* linux,stdout-path and /aliases/stdout are for legacy compatibility */
		const char *name = of_get_property(of_chosen, "stdout-path", NULL);
		if (!name)
			name = of_get_property(of_chosen, "linux,stdout-path", NULL);
		if (IS_ENABLED(CONFIG_PPC) && !name)
			name = of_get_property(of_aliases, "stdout", NULL);
		if (name)
			of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
	

	if (!of_aliases)
		return;

	for_each_property_of_node(of_aliases, pp) 
		const char *start = pp->name;
		const char *end = start + strlen(start);
		struct device_node *np;
		struct alias_prop *ap;
		int id, len;

		/* Skip those we do not want to proceed */
		if (!strcmp(pp->name, "name") ||
		    !strcmp(pp->name, "phandle") ||
		    !strcmp(pp->name, "linux,phandle"))
			continue;

		np = of_find_node_by_path(pp->value);
		if (!np)
			continue;
		······
	

(1)of_alias_scan()函数主要是处理aliases节点,处理节点的别名,方便后续访问;
(2)查找aliases节点对应的device_node结构体就是通过绝对路径进行查找;
(3)of_find_node_by_path( )函数内部会根据of_root节点进行查找,of_root节点就是根节点;

8、dts示例源码

/dts-v1/;
/memreserve/ 0x4ff00000 0x100000;
/ 
    model = "YIC System SMDKV210 based on S5PV210";
    compatible = "yic,smdkv210", "samsung,s5pv210";
 
    #address-cells = <1>;
    #size-cells = <1>;
        
    chosen 
        bootargs = "console=ttySAC2,115200n8 root=/dev/nfs nfsroot=192.168.0.101:/home/run/work/rootfs/";
    ;  
 
    memory@30000000 
        device_type = "memory";
        reg = <0x30000000 0x20000000>;
    ;  
;

9、dts文件和struct device_node的转换图

以上是关于所有dtb对应啥芯片的主要内容,如果未能解决你的问题,请参考以下文章

Rockchip RK808-D是啥芯片

用啥芯片能将 BT1120 信号转换成MIPI DSI 信号?

设备树——dtb格式到struct device node结构体的转换

spec上损耗功率Ta,Tc有啥区别

STM32标准库函数是否所有的都能用

存储器2