![](https://i-blog.csdnimg.cn/blog_migrate/1d15646f3f69b2ba40d948ef86fee0f5.png)
xx.dts:device tree source设备树源文件
xx.dtb:device tree binary 设备树二进制文件
xx.dtc:device tree compiler 设备树编译器,作用:将dts转为dtb
dtc文件的Makefile如下:它在目录scripts\dtc\Makefile下
![](https://i-blog.csdnimg.cn/blog_migrate/e0d16fb098618f1cd132a0922e584272.png)
在linux的源码目录下输入make或make all会编译出all依赖的所有目标,包括zImage,.ko文件和驱动,输入 make tdbs只编译目标dtbs对应的文件也就是所有的设备树文件
而设备树文件是众多的,一个板子就对应一个设备树文件,如何编译我们想要的设备树文件呢,那当然是看设备树文件对应的makefile,在目录arch\arm\boot\dts\Makefile如下:
![](https://i-blog.csdnimg.cn/blog_migrate/c9bfeb7d5a36f85d8784b4a813581238.png)
以后为我们要自己做一块板子时,将板子设备树写好后,将对应的dtb文件名字加入进来,在编译设备树时自然就会编译它
DTS语法
设备树也支持头文件,设备树的头文件后缀名为:.dtsi
设备树文件永include可以包含的头文件包括.h,.dtsi,.dts三种
一般来说,.dtsi文件用于描述soc的内部外设信息,如:cpu架构,主频,I2C,我们不需要改变。比如I.mx6ull.dtsi,要看懂它先得学一下dts语法
/ 它表示根节点
节点命名法则:
![](https://i-blog.csdnimg.cn/blog_migrate/bcd8b5e22b7412e7b2d49446eba42e3c.png)
node-name:节点名字,是ASCLL字符串
unit-address是节点地址,没有可以省略
可以用标签代替节点名字,避免节点名字太长不方便使用,用法如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6e175aeaf2ac32ea960c656f07a79240.png)
访问该节点时,用&label访问,不用标签则需使用全路径
![](https://i-blog.csdnimg.cn/blog_migrate/c0471364daf1f23f72db5d6ed03fa387.png)
属性
属性的名字可以随便取,但是属性的值却有三种取值
![](https://i-blog.csdnimg.cn/blog_migrate/3c5ba07fd598b75d4ea0eb02edc473a1.png)
compatiable:兼容属性,属性值为字符串列表,字符串值之间以逗号隔开,它的值是优先匹配到的字符串
rag属性表示设备的起始地址和大小
#adress-cells和#size-cells属性
一个cell表示一个32位数据,adress与size属性是用来设置子节点的rag属性
eg:
![](https://i-blog.csdnimg.cn/blog_migrate/6768ff1512f56ac7882795f8ba8fe70d.png)
它表示子节点的起始地址是一个用32位数据表示的数,大小也是。
status属性
要用到的模块值设置为“ok";不用设置为”disable“。fail与fail-ss一般不用
e.chosen属性
chosen节点下面的bootargs属性下面保存的便是我们设置uboot的该参数值,具体如下
![](https://i-blog.csdnimg.cn/blog_migrate/c4c2502fc9e0a8d37e02bfe6bcde1811.png)
f.model 属性
它的值也一个字符串,一般 model 属性描述设备模块信息,比如名字什么的
如何编写dts
.dtsi文件是对用这个芯片一系列板子所共用的头文件,一般不会更改,它里面也是设备树的一系列描述,主要是片内外设资源的描述。
我们通常是通过追加的方式去更改或者写设备树:&label
设备树文件存在的形式是:proc/device-tree/目录下,如图
![](https://i-blog.csdnimg.cn/blog_migrate/05bd45afd28d36a958efa7890be9bfc2.png)
属性的存在形式是文件,图中白色
子节点的存在形式是目录,图中蓝色
Linux内核解析dtb文件
![](https://i-blog.csdnimg.cn/blog_migrate/6ba12125e511e3fdff60368d414a0486.png)
具体实现不用管,知道在启动内核后,unflatten_dt_node函数会去解析设备节点即可
设备树常用操作函数:of函数集
linux用device_node结构体来描述一个设备节点
![](https://i-blog.csdnimg.cn/blog_migrate/66e7d6791f08074a2b0f023e1a1f1d37.png)
节点查找函数,定义在linux内核源码的include/linux/of.h中
of_find_node_by_name()
作用:通过节点名字查找节点
![](https://i-blog.csdnimg.cn/blog_migrate/646b4b3b49fe030b33c24ab6da8f5337.png)
参数1:开始查找的节点位置,NULL表示从根节点开始查找
参数2:节点名字
返回值:成功:找到的节点;失败:NULL
of_find_node_by_type()
![](https://i-blog.csdnimg.cn/blog_migrate/e07832408b935d21764061ad1d6bc4f6.png)
参数1:开始查找的节点位置
参数2:要查找的节点对应的 type 字符串,也就是 device_type 属性
返回值:查找成功返回找到的节点,失败为NULL
of_find_compatible_node()
![](https://i-blog.csdnimg.cn/blog_migrate/8300236cff74e51273d02242ee4f5590.png)
from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示
忽略掉 device_type 属性。
compatible:要查找的节点所对应的 compatible 属性列表。
返回值:找到的节点,如果为 NULL 表示查找失败
of_find_matching_node_and_match()
![](https://i-blog.csdnimg.cn/blog_migrate/7a9b2046373ab82d405dacc08bf8b1aa.png)
from:开始查找的节点,如果为 NULL 表示从根节点开始查找这个设备。
matches:of_device_id 匹配表,也就是在此匹配表里面查找节点。
match:找到的匹配的 of_device_id。
返回值:找到的节点,如果为 NULL 表示查找失败
of_find_node_by_path ()
![](https://i-blog.csdnimg.cn/blog_migrate/ec213788aaa9d8d4679dff9efeafafc0.png)
path:带有全路径的节点名,可以使用节点的别名
返回值:找到的节点,如果为 NULL 表示查找失败
查找父/子节点的 OF 函数
of_get_parent ()
作用:于获取指定节点的父节点
![](https://i-blog.csdnimg.cn/blog_migrate/5a41036a8eae358e654255d858ca9f61.png)
参数:要查找的父节点的节点。
返回值:找到的父节点。
b.of_get_next_child()
作用:于获取指定节点的子节点(迭代查找)
![](https://i-blog.csdnimg.cn/blog_migrate/97685760228c01b7d4aeab1a57f5df68.png)
node:父节点。
prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为
NULL,表示从第一个子节点开始。
返回值:找到的下一个子节点。
提取属性值的 OF 函数
of_find_property()
作用:查找指定的属性
![](https://i-blog.csdnimg.cn/blog_migrate/89299d48ca436acdb08054ba32e19137.png)
np:设备节点。
name: 属性名字。
lenp:属性值的字节数
返回值:找到的属性。
b.of_property_count_elems_of_size()
作用:查找元素属性数量
![](https://i-blog.csdnimg.cn/blog_migrate/fe512cf5ec3891ec8a94c4cc994b97f6.png)
np:设备节点。
proname: 需要统计元素数量的属性名字。
elem_size:元素长度。
返回值:得到的属性元素数量。
c.of_property_read_u32_index()
作用:从属性中获取指定标号的 u32 类型数据值
![](https://i-blog.csdnimg.cn/blog_migrate/0c1df5e01a09b2e0bb9d7ae35b43e6a9.png)
np:设备节点。
proname: 要读取的属性名字。
index:要读取的值标号。
out_value:读取到的值
返回值:0 读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有
要读取的数据,-EOVERFLOW 表示属性值列表太小。
d.of_property_read_u8_array ()
of_property_read_u16_array ()
of_property_read_u32_array ()
of_property_read_u64_array ()
其他常用的 OF 函数
of_device_is_compatible()
作用:查找compatiable属性之中是否含有compat指定的字符串
![](https://i-blog.csdnimg.cn/blog_migrate/465cd27e2f5a8bc283683df8024e9fa7.png)
参数:device:设备节点。
compat:要查看的字符串。
返回值:0,节点的 compatible 属性中不包含 compat 指定的字符串;正数,节点的 compatible
属性中包含 compat 指定的字符串
b.of_get_address()
作用:获取地址相关属性,如reg,assigned-addresses属性
![](https://i-blog.csdnimg.cn/blog_migrate/91d38028f0a7d47c1703a10113a753a2.png)
dev:设备节点。
index:要读取的地址标号。
size:地址长度。
flags:参数,比如 IORESOURCE_IO、IORESOURCE_MEM 等
返回值:读取到的地址数据首地址,为 NULL 的话表示读取失败
c.of_translate_address()
作用:将从设备树读到的虚拟地址转换为物理地址
![](https://i-blog.csdnimg.cn/blog_migrate/b185e1c81a47bd8d6acd7dd107743f49.png)
dev:设备节点。
in_addr:要转换的地址。
返回值:得到的物理地址,如果为 OF_BAD_ADDR 的话表示转换失败。
d.of_address_to_resource()
linux内核使用resource结构体来描述一段内存空间
![](https://i-blog.csdnimg.cn/blog_migrate/41d11a0e8d09bbb50fc6f8fa082fee42.png)
对于 32 位的 SOC 来说,resource_size_t 是 u32 类型的,
start:内存起始地址
end:内存结束地址
name:资源名字
flags:资源标志位,一般表示资源的类型
作用:将reg属性值转化为resource结构体
对于of_address_to_resource:
![](https://i-blog.csdnimg.cn/blog_migrate/87e61d162eee811b8b4d416fb36daf4f.png)
dev:设备节点。
index:地址资源标号。
r:得到的 resource 类型的资源值。
返回值:0,成功;负值,失败。
e.of_iomap()
作用:of_iomap 函数用于直接内存映射,以前的ioremap也可以,但是在设备树中习惯用of_iomap函数来完成内存映射。
![](https://i-blog.csdnimg.cn/blog_migrate/50cc588724bcc61ce6819f27bfbb5e1c.png)
np:设备节点。
index:reg 属性中要完成内存映射的段,如果 reg 属性只有一段的话 index 就设置为 0。
返回值:经过内存映射后的虚拟内存首地址,如果为 NULL 的话表示内存映射失败。