大家好,欢迎来到IT知识分享网。
一、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引导程序加载到内核
三、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结构由一个小的报头和三个大小可变的部分组成:内存预留块,结构块和字符串块,当以地址载入内存时,将类似于下图(较低的地址位于图的顶部):
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的流程图如下:
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/135807.html