什么是DTS
设备树(dt:device tree)是linux内核采用的参数表示和传递技术,在系统引导启动阶段进行设备初始化的时候,将设备树中描述的硬件信息传递给操作系统。
(1)dts(device tree source):设备树源文件,描述设备信息的;
(2)dtc(device tree compiler):设备树编译/反编译/调试工具;
(3)dtb(device tree binary):二进制设备树镜像;
(4)dtsi(device tree source include):功能类似设备树文件的头文件,可以被dts文件通过include引用,dtsi文件一般是描述共性部分;
DTS解决什么问题
在设备驱动源码中,分为驱动代码和设备代码,驱动代码是操作硬件的方法,设备代码是硬件资源、数据,当驱动代码和设备代码匹配时就会调用驱动的probe函数,probe函数会利用设备代码的资源去初始化设备;
设备树之前,设备代码都是直接写在内核源码中的,以platform_device结构体的形式存在,驱动代码和设备代码也是在platform总线上匹配,当需要修改设备资源时,就需要修改内核源码;
设备树技术将设备的硬件资源信息就写在dts文件中,需要修改就修改dts文件,不必在修改内核源码;
不采用设备树技术:内核源码中会充斥大量设备硬件描述信息,导致内核源码不停增多,但是增多的硬件描述信息代码和内核功能并不相关;
采用设备树技术之后:设备的硬件描述信息都在dts文件中,修改方便,但是内核要增加解析dts文件格式的代码;
DTS怎么工作
dtsi/dts源码文件------>dtc编译器--------->dtb二进制镜像
驱动开发者根据硬件编写/修改dts文件,使得将来驱动代码能匹配到合适的设备硬件信息;
编译内核时,kernel会先编译出dtc,然后再用dtc将dts文件编译成dtb;
uboot启动kernel时,将内核镜像和dtb都重定位到内存,并告诉内核dtb的所在内存地址;
内核启动初期调用内部函数解析dtb,得到硬件信息后再组装成硬件函数,最后去和驱动代码进行匹配;
设备树源码dts文件格式讲解
arm架构的dts文件在内核源码中的存放位置:arch/arm/boot/dts目录中
注释用/* */,注意#开头的不是注释
分号是段落块之间的分隔符,{}和[]和<>是段落块的封装符号,和C语言语言类似
/dts-v1/节点,表示dts的版本号,目前都是v1
/{}是根节点root node,理论上只应该有一个根节点,有说法dtc会合并所有root node为同一个
dts是树状的多节点组织,基本单元是node,除root外其他node都有parent,还可以有child
节点解析
格式定义
![](https://img-blog.csdnimg.cn/img_convert/c1024db30e8da60f232fe3a030b932d0.png)
[]:表示该项可以省略,<>:表示不可省略;
[label:]:label是标签名,为了方便访问节点,后面可以直接通过&label来访问该节点。
node-name:节点名称。根节点的名称必须是/
[@unit-address]:unit-address是设备地址,如cpu node就是0、1这种,reg node就是0x12010000这种;
![](https://img-blog.csdnimg.cn/img_convert/9da3fc4506b15357d30d830e2d0259e1.png)
cpus是cpu的父节点,从形式来能直观的看出来,cpu节点是被cpus节点的大括号括起来的;
cpus节点省略了标签名和设备地址,只有节点名称;
GPIO属性格式
![](https://img-blog.csdnimg.cn/img_convert/fffc93805a6d67e3e6e26112328f7e9f.png)
在上面例子dts片段例子中,这句话的解析是:
sp_reset_gpio :管脚名字,随便取,和driver代码对应即可。
&pio:指向哪个GPIO控制器
PB:哪组GPIO
7:pin bank(内偏移,就是PB组内的第7个IO口)
1:gpio功能类型(复用类型):0输入,1输出,6外部中断,7关闭功能(具体查手册)
1:驱动力,电流等级(0-3),级别越高,输出电流越大
2:上下拉:0关闭功能,1上啦,2下拉,3保留
0:表示有效电平,0低电平有效,1高电平有效
所以上面那句话的完整意思是:
配置sp_reset_gpio为PIO控制器的PB组的第7脚为 输出 功能,驱动电流等级为1,默认下拉,低电平有效。
compatible属性格式
![](https://img-blog.csdnimg.cn/img_convert/f1b0fd73582c64d828fc24eb017906f6.png)
compatible属性是用于设备节点和设备驱动匹配用的,在内核描述驱动的structdevice_driver结构体中,compatible变量中就会保存用于匹配的字符串,当设备节点和驱动的compatible相同时就匹配成功;
compatible后面可以有多个字符串,优先匹配靠前的字符串,靠前的字符串匹配不上才会匹配后面的字符串;
model属性格式
![](https://img-blog.csdnimg.cn/img_convert/f9c3fba97450e0b6c5bcee49e0857184.png)
model是描述模块信息的,一般只有根节点才有,标明设备树文件对应的开发板的名称;
在内核的启动打印中可以看到model的值:“OF: fdt:Machine model: Tyr DEMO Board”;
status属性格式
![](https://img-blog.csdnimg.cn/img_convert/2bf8a1877fc0a83948ccca9a1f122258.png)
![](https://img-blog.csdnimg.cn/img_convert/22cac2d748af2c6254ec2ac6a910993c.png)
status描述设备信息状态,在设备树文件中可以根据需求设置模块的状态,功能就是开启/关闭某个模块;
在dtsi文件中,默认都是关闭模块的,在开发板对应的dts文件中自己去打开需要的模块;
reg属性格式
![](https://img-blog.csdnimg.cn/img_convert/1fd730aa34f68340c1e11eb4fb36bd68.png)
(1)reg属性:配置某个硬件模块对应的地址范围信息;
(2)#address-cells属性:表示reg里面的数据address占用的字长,注意字长不是字节;
(3)#size-cells:表示reg里面的数据size占用的字长,注意字长不是字节;
(4)reg = <address1 length1 address2 length2 …>:address一般用来表示起始地址,length一般表示持续长度;
中断属性格式
![](https://img-blog.csdnimg.cn/img_convert/40d7eff274e68d818ac2deeb60fc9d43.png)
(1)interrupt-controller:无值属性,表示这是个中断控制器node
(2)#interrupt-cells:这是中断控制器节点的属性,用来标识这个控制器需要几个cell做中断描述符
(3)interrupt-parent:标识此设备节点属于哪一个中断控制器,如果没有这个属性,会自动依附父节点
(4)interrupts :一个中断标识符列表,表示每一个中断输出信号
aliases子节点
![](https://img-blog.csdnimg.cn/img_convert/c28da6098ad912ea6f0e56d60280fb12.png)
aliases就是别名的意思,aliases节点主要功能就是给节点定义别名,为了方便访问节点。不过我们在节点命名的时候可以加上label标签,直接通过&label引用标签来访问也很方便,aliases节点内部其实也是通过引用标签名来定义别名;