RK3568系列5——Device Tree配置语法

  Device Tree(设备树)是一种树型数据结构,用来描述计算机上的硬件信息。使得开发人员可以无需修改系统、驱动、内核代码来适配不同的硬件设备。这篇文章带你5分钟了解DTS文件的配置语法。该文为RK3568平台Android开发从零到上市系列配置实录,请订阅后输入密码查看,订阅方式请见系列目录。

文件类型

  • .dts:板级的DTS配置文件,一块板子(只要硬件上有一点差异)对应一个.dts文件
  • .dtb:编译后的二进制dts文件,真正包含在固件中的DTS配置文件,编译内核时自动编译
  • .dtsi:可被引用的DTS配置文件,前面说到一块板子对应一个.dts文件,我们可以将公共部分提取出来放在一个.dtsi文件里,供板级配置文件引用

DTS语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 声明DTS文件语法版本
/dts-v1/;

// 引用CPU厂商已经编写好的公共配置
#include "rk3568.dtsi"
#include "rk3568-evb.dtsi"

// 根节点以:“/ {”开始,“};”结束
/ {
// 每个节点compatible均有此属性,用来表示该载入哪个驱动
compatible = "";

// [label:]name[@address]
// label -> 可选字段,不能重复,如果别的节点需要引用这个节点就可以使用&label的方式引用
// name -> 节点名称,要保证name@address不能重复
// address -> 节点地址,一块板子可能有多个相同类型的设备,比如串口,这里就可以使用不同地址来区分这些设备
label: name@address {
// 这里为节点的公共属性
status = "okay"; // 可选,设备是否使能,okay->启用,disabled->禁用,不加默认启用
compatible = ""; // 设备类型,每个节点必备
power-supply = <&vcc5v0_sys>; // 可选,设备的电源域,一般硬件开始工作时,驱动会通知供电组件开启供电
pinctrl-names = "default"; // 定义设备在不同状态下pin脚的功能
pinctrl-0 = <&bluetooth>; // 声明状态0下pin脚使用的功能
pinctrl-1 = <&uart> // 声明状态1下pin脚使用的功能


// 这里为节点的私有属性,根据驱动程序来定义
// 节点的属性使用键值对的方式给出
string-key = "value"; // 字符串类型的值使用引号包裹
number-key = <0>; // 数字类型的值使用尖括号包裹

// 节点可以包含更多子节点(树形结构)
// label一般用下划线分割
// name一般用横线分割
sub_label: sub-node@address {
// 如果子节点只是描述某些属性,不用加载某个驱动,可以没有compatible字段
};
};

// 具有地址空间的节点,详见下文解析
label: name@address {
#address-cells = <1>; // 用于表示子节点的“地址空间的地址”(reg)所占的长度
#size-cells= <0>; // 用于表示子节点的“地址空间的大小”(reg)所占的长度

port@0 {
reg = <0>;
};
port@1 {
reg = <1>;
};
};
};

地址空间举例

1
2
3
4
5
6
7
soc {
#address-cells = <x>;
#size-cells = <y>;
serial {
reg = <0x0 0x100 0x0 0x200>;
}
};
  • 如果x=1, y=1,那么子节点中reg解析为:addr1 = 0x0, size1 = 0x100; addr2 = 0x0, size2 = 0x200
  • 如果x=2, y=2,那么子节点中reg解析为:addr1 = 0x100, size1 = 0x200
  • 如果x=2, y=0,那么子节点中reg解析为:addr1 = 0x100, addr2 = 0x200

配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/dts-v1/;

#include "rk3568.dtsi"
#include "rk3568-evb.dtsi"

/ {
model = "Project Alpha";
// 根节点的compatible中"rockchip,rk3568"不能删除,否则会无法载入CPU信息
compatible = "Kuretru,rk3568-alpha", "rockchip,rk3568";

cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a55";
reg = <0x0 0x0>;
};
cpu1: cpu@1 {
compatible = "arm,cortex-a55";
reg = <0x0 0x100>;
};
};
};

删除节点或属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 删除节点中的属性
&node1 {
/delete-property/ pinctrl-names;
/delete-property/ pinctrl-0;
};

// 删除节点中的子节点
&node2 {
/delete-node/ ir_key1;
/delete-node/ ir_key2;
/delete-node/ ir_key3;
};

// 删除根节点中的节点,两种方式都可以
/delete-node/ &rk809_sound;
/delete-node/ mxc6655xa@15;

如何查找某个设备该配置哪些属性

  1. 查找其他配置好的DTS文件中是否有定义过类似的设备
1
2
3
4
# 这两个目录一个是32位的芯片一个是64位的芯片,32位里的配置一般会旧一点
cd kernel/arch/arm/boot/dts/
cd kernel/arch/arm64/boot/dts/rockchip/
grep -n "es8316" *.dtsi
  1. 查找驱动程序的文档
1
2
cd kernel/Documentation/devicetree/bindings/
find . -name "*.txt" -exec grep -n -H "es8316" {} \;
  1. 直接查看对应驱动程序的probe函数
1
2
3
cd kernel/drivers/
cd kernel/sound/ # 声音相关驱动在此目录下
find . -name "*.c" -exec grep -n -H "rockchip,remotectl-pwm" {} \;

编译DTS文件

1
2
3
4
5
# 编译DTS文件
dtc alpha.dts > alpha.dtb

# 反编译DTB文件
dtc alpha.dtb > alpha.dts