linux kernel dts分析

一、DTS的来源

在linux内核源码的3.1版本之前,linux内核都是通过大量的platfrom-device文件来描述板级配置信息,这使得内核人员维护很困难,因此设备树(Device Tree)被采用

二、DTS的介绍

        DTS可以看成一个描述板级硬件信息的树状结构,这棵树上有多个枝干,每一个树干都可以表示一个板级子设备信息

        设备树文件目录一般位于kernel/arch/arm64/boot/dts/下,该目录含有多个厂商的DTS信息

        DTS:DTS即Device Tree Source,是一个文本形式的文件,用于描述硬件信息。一般都是硬件的固定信息部分,不需要修改

        DTSI:SoC公用的部分或者多个设备共同的部分一般提炼为.dtsi,类似于C语言头文件

        DTB:dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核

00783cb6ec1eec6744ef195a6cfe34c7.png

、DTS的介绍

下面是一个设备树文件的基本结构

/{    #表示设备树根节点
        node1@address{  #node1表述节点名,address表示节点对应的寄存器地址
            byte-property=<0xFF>;
            string-property = "string";
            string-list-property="string one","string two";
            child-node{
                child-byte-property=<0xFF>;
                child-string-property = "child-string";
            }   
        }
        
        node2:node2@address{ #这里node2表示node2@address的别名
            byte-property=<0xFF>;
            string-property = "string";
            string-list-property="string one","string two";
        }
}

四、DTS的常用属性

compatible:用于驱动模块和节点硬件信息的匹配

reg:表示i2s模块的寄存器地址从oxff000000起始,长度为0x1000

interrupts:表示i2s模块上使用的中断类型和中断号

clocks:使用的时钟

clocks-name:时钟名称

dmas:使用的dma通道号

status:okay表示设备正常运行;disabled设备不可操作,但是后面可能恢复工做;fail发生了严重错误;fail-sss发生了严重错误,sss表示错误信息

五、DTS的资源获取的相关函数

       struct device_node定义

 /include/linux/of.h

 struct device_node {
     const char *name;  //节点名
     const char *type;  //设备类型
     phandle phandle;
     const char *full_name; //完整名字
     struct fwnode_handle fwnode;
    
     struct  property *properties; //属性
     struct  property *deadprops; 
     struct  device_node *parent; //父节点
     struct  device_node *child;  //子节点
     struct  device_node *sibling;
 #if defined(CONFIG_OF_KOBJ)
     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
 };

1、struct device_node *of_find_node_by_path(struct device_node *from,const char *path);

说明:根据路径找到节点

from:开始查找的节点,NULL表示从根节点开始查找

path:查找的节点名

返回值:

成功:device_node表示的节点

失败:NULL

2、struct device_node of_find_compatible_node(struct device_node *from,const char *type, const char *compat);

说明:根据compatible查找节点

from:开始查找的节点,NULL表示从根节点开始查找

type:指定 device_type 属性值

compat:指定 compatible 属性值

返回值:

成功:device_node表示的节点

失败:NULL

3、struct property *of_find_property(const struct device_node *np,const char *name,int *lenp);

说明:查找节点中的属性

np:device_node表示的节点

name:查找的属性名字

lenp:属性值的字节数

返回值:

成功:property表示的属性

失败:NULL

4、static inline int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value);

说明: 读取节点中一个32位无符号整数

np:device_node表示的节点

propname:查找的属性名字

out_value:属性值的整数值

返回值:

成功:0

失败:负值

5、int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_values,size_t sz);

说明: 从节点中读取32位无符号整数数组

np:device_node表示的节点

name:查找的属性名字

out_value:读取到的数组值

sz :要读取的数组元素数量

返回值:

成功:0

失败:负值

6、int of_property_read_string(struct device_node *np,const char *propname,const char **out_string);

说明:从节点中读取字符串

np:device_node表示的节点

propname:查找的属性名字

out_string:读取到的数组值

返回值:

成功:0

失败:负值

六、dts-node被转换为platform_device的步骤

        编译内核时通过DTC工具将DTS编译成二进制文件*.dtb,dtb结构由一个小的报头和三个大小可变的部分组成:内存预留块,结构块和字符串块,当以地址载入内存时,将类似于下图(较低的地址位于图的顶部):

        c1c7660bf95d45df097842d9d839be61.png

        

dtb->platfrom_device的规则如下:

1.该device_node 必须含有 compatible属性。

2.该device_node 是根节点的子节点(必须有compatible属性)。

3.如果孙子节点或者孙孙子节点也想要转换成platfrom_device,则它的父节点device_node的compatible属性必含有如下特殊字符串:“simple-bus” ,“simple-mfd”,“isa”,“arm,amba-bus”.(只要compatilbe中含有其中任一即可,没有则被转换为对应框架的抽象设备,如struct i2c client)

        

dtb->device_node解析的流程如下:

setup_arch(&command_line) ->

        //__atags_pointer为uboot传递给kernel的dtb文件的内存地址

        setup_machine_fdt(__atags_pointer)->

        dt_virt = fixmap_remap_fdt(dt_phys)

        early_init_dt_scan(dt_virt) ->

                //校验dtb和解析部分节点属性值

                early_init_dt_verify(params)

//继续解析剩余节点和属性值

        unflatten_device_tree()->

        //数据保存到struct device_node结构中,并赋值给of_root(根节点),至此,dts文件在内内核中的解析完成

                __unflatten_device_tree(initial_boot_params, &of_root,

                early_init_dt_alloc_memory_arch)->

                        unflatten_dt_node

dtb->device_node解析的流程图如下:

device_node->platfrom_device的流程如下:

如果从start_kernel进行追溯,是找不到node->platform device的转换源头,(arm64)这个转换过程是由arch_initcall_sync(arm64_device_init)开始,调用 of_platform_populate开启

static int __init arm64_device_init(void)
{
    ...
    of_platform_populate(NULL, of_default_bus_match_table,NULL, NULL);
    ...
}
arch_initcall_sync(arm64_device_init);

下面进入到of_platform_populate中,查看node->platfrom_device的转换过程:

of_platform_populate(NULL, of_default_bus_match_table,NULL, NULL)->

        for_each_child_of_node(root, child)

        of_platform_bus_create(child, matches, lookup, parent, true) ->

        //据节点创建出对应的platform_device

               of_platform_device_create_pdata(bus, bus_id, platform_data, parent)>

        //为device匹配driver

                        bus_probe_device->device_initial_probe->__device_attach->

                                __device_attach_driver->driver_probe_device->really_probe->

                                        drv->probe(dev)

device_node->platfrom_device的流程图如下:

猜你喜欢

转载自blog.csdn.net/QQ135102692/article/details/125192238