目录
概念
- 设备树是一种描述硬件资源的数据结构。它通过 bootloader将硬件资源传给内核使得内核和硬件资源描述相对独立。
- 简单来说就是将前面的dev.c变成一个设备树文件,都是描述硬件资源的数据结构,但他不需要重新编译内核,只需要将设备树文件编译成二进制文件然后通过bootloader传递给内核,内核再对其进行解析和展开得到一个关于硬件的拓扑图
设备树起源
平台总线起源
- 前面学了字符和杂项设备,都是有一个框架,按需填空就好,这样很简单容易
- 但是很不容易扩展,当写了很多驱动之后就会发现前面很多都相同,到了后面初始化硬件部分不一样,其他的都相同
- 于是我们将通用的代码和有差异的代码分离出来,来增强我们驱动代码的移植性
- 分离是把一些不相似的东西放到了 dev.c,把相似的东西放在了 dri.c,
- 如果有很多相似的设备或者平台,我们只要修改 dev.c就可以了,这样重复性的工作就大大的减少了
- 这个就是平台总线的由来。
平台总线弊端
- 当底板不换,换了芯片,换了一个平台,都要修改C文件,并且要重新编译
- 这样子会留下大量关于以前芯片细节的代码
- 雨水linux就研究出了设备树,用来剔除相对内核来说的“垃圾代码
设备树作用
- 即用设备树文件来描述这些设备信息,也就是代替dev.c文件,
- 虽然拿到了内核外面,但 platform 匹配上基本不变,并且相比于之前的方法,
- 使用设备树不仅可以去掉大量“垃圾代码”,并且采用文本格式,方便阅读和修改,
- 如果需要修改部分资源,我们也不用在重新编译内核了,只需要把设备树源文件编译成二进制文件,在通过 bootloader 传递给内核就可以了。
- 内核在对其进行解析和展开得到一个关于硬件的拓扑图。
- 我们通过内核提供的接口获取设备树的节点和属性就可以了。
- 即内核对于同- soc的不同主板,只需更换设备树文件dtb 即可实现不同主板的无差异支持,而无需更换内核文件。
设备树基本框架
- 设备树从根节点开始,每个设备都是一个节点。
- 节点和节点之间可以互相嵌套,形成父子关系。
- 设备的属性用 key-value 对(键值对)来描述,每个属性用分号结束
设备树语法
节点
举例,根节点和子节点和子子节点
/{ //根节点
node1//子节点 node1
{
child-node1 //子子节点
{
};
};
node2//子节点 node2
{
};
};
节点名称
格式
- <名称>[@<设备地址>]
- 名称要以设备的类型来取,不能简单随便,要看得出什么设备
- 设备地址是用来区分设备的,不是操作过程中的基地址
注意
- 同一级的节点只要地址不一样,名字是可以不唯一的。
- 设备地址是一个可选选项,可以不写。但为了容易区分和理解,一般是都写的。
节点别名
当我们找一个节点的时候,我们必须书写完整的节点路轻,如果我们的节点名很长,那么我们在引用的时候就十分不方便,所以,设备树允许我们用下面的形式为节点标注引用
举例
- uart8: serial@02288000
- uart8:别名
- serial@02288000:节点名称
节点的作用
一般往一个节点里面添加内容的时候,不会直接把添加的内容写到节点里面,而是通过节点的引用来添加。
举例
&uart8 {
pinctrl-name = "default",
pinctrl-0 = <&pinctrl_uart8>;
status = "okay";
};
- 直接&加别名就表示向别名的节点添加东西
- 添加三个值,用节点标志圈起来
注意
- 在dts底下有两个根节点,会合并成一个根节点,表示相同的节点的不同属性信息会合并
属性
- reg属性
- 作用:属性用来描述一个设备的地址范围
- 格式:reg = <add1 length1 [add2 length2] ......>
- 举例:其中101F2000就是起始地址,0x1000是长度
serial@02288000{ reg = <101F2000 0x1000>; };
- #address-cells和#size-cells属性
- #address-cells:用来设置子节点中reg地址的数量
- #size-cells:用来设置子节点中reg地址长度的数量
- 举例:
cpu{ #address-cells = <1>; #size-cells = <1>; serial@101F2000{ compatible = "serial"; reg = <101F2000 0x1000>; }; };
- 其中#address-cells 和#size-cell 均为1,也就是说我们子节点里面的 reg 属性里这个寄存器组的起始地址只有一个,长度也只有一个。所以101F2000 是起始地址,0x1000 是长度。
- compatible属性
- compatible 是一个字符串列表,可以在代码中进行匹配driver.c里的name
- 举例:
compatible = “led";
- status属性
- status 属性的值类型是字符串,这里我们只要记住俩个常用的即可,一
- 个是 okay,表示设备可以正常使用
- 一个是 disable,表示设备不能正常使用
大致查看设备树文件
在 源码根目录/arch/arm/boot/dts/中
头函数
和c语言一样,可以#include "xxx.dts"包含其他设备树文件
寻找根节点
如果该设备树文件没有 /{ } 开头的节点,就去包含的头文件去找,先找到根节点
分析根节点
- 会有一个model 变量字符串,一般作用是告诉我们这个设备树文件对应什么平台
- compatible:有几个字符串,作用是可以匹配多个驱动,但会按第一个字符串来先匹配
- chosen:设置uboot环境变量
- 包含各个的子节点
dtsi文件
如果在根目录中又包含了一个dtsi文件,进去这个dtsi文件后,就又会看到一个根节点,这就是我上面说的,dtsi里面的根节点会于我们第一个找到的根节点合并成一个根节点
查看方法
找到根节点,从左往右,从上往下