1.概念
linux设备树是用于描述硬件及部分启动指令的文件,由bootloader传递给内核(U-boot需要在config文件中加入"#define CONFIG_OF_LIBFDT"),
内核分析此文件而对硬件使用不同的参数。
比如两块开发板仅仅是内存容量不一样,那么就只需要修改设备树中对内存容量的描述即可,
而不需要重新编译内核。
与设备树相关的文件有如下几种:
DTS(device tree source)
.dts文件,就是ASCII字符串形式的文本文件,直接由开发人员修改。
对于ARM架构而言,这些文件位于:arch/arm/boot/dts 目录下。
DTSI(device tree source include)
.dtsi文件,用于被.dts文件所包含。并且.dtsi文件也可以包含.dtsi文件。与c/c++ 包含头文件一个道理。
此文件包含了很多设备下所共有的许多配置。
在.dts文件下,使用"#include "file.dtsi"" 或"/include/ "file.dtsi""来包含。
DTB(device tree blob)
通过工具提前将DTS文件编译为.dtb二进制文件,bootloader传递此文件给内核,这样内核的解析速度才快。
DTC(device tree compiler)
将.dts文件编译为.dtb的工具,其源码位于scripts/dtc目录下,此工具根据用户设定的SOC来确定编译哪种目标板。
Binding
对于设备树中的节点及属性具体描述文档,位于Document/devicetree/bindings,、
需要仔细阅读!需要仔细阅读!需要仔细阅读!
2.规则
设备树的结构是由节点和节点中的属性构成的,这就如同c/c++中结构体名称和元素名称及元素值的关系一样。
复制代码
#include "skelston.dtsi" /*包含*/
/{
node{
a-string-property = "string";
};
};
/*
"/" 代表根节点,根节点是设备树的起始节点,一个设备文件中必须且仅有一个根节点,"node"是一个子节点名,
"a-string-property"是一个属性名,"string"是属性值。
*/
复制代码
2.1 节点
2.1.1节点命名及路径
节点命名可以有如下几种方式:
1、以"设备名"为节点名
比如设备DM9000,对应的节点路径为:/dm9000
复制代码
/{
...
dm9000{
...
};
...
};
复制代码
2、以"设备名@I/O地址"为节点名:
比如设备DM9000位于I/O地址为0x8000 0000,对应的节点路径为:/dm9000@80000000
注意:这种方式下,若两个节点具有相同的设备名和不同的I/O地址,也同样代表两个不同的设备!
复制代码
/{
...
dm9000@80000000{
...
};
...
};
复制代码
2.1.2节点引用
如同linux中可以为命令命名别名(alias)一样,节点也可以先命名别名再引用。
注意:在节点引用的同时,其内容等同于被引用过来了。
复制代码
/{
...
dm9000:dm9000@80000000{
...
};
...
&dm9000{
};
};
/*
&dm9000就等价于 dm9000@80000000
*/
复制代码
2.1.3节点合并
若同一设备树中有相同的节点名及地址时,节点的内容会合并。
若节点内容中出现了相同的属性,则新属性值替换掉老的属性值。
比如在petalinux中可以修改顶层的设备树文件,将新的设置信息与老的合并或替换。而不用关心以前默认的设定值。
2.2属性
2.2.1属性的内容
属性的内容比较灵活,可以为:
1、空(比如:an-empty-proerty;)
2、字符串(比如:a-string-property = "A string";)
3、字符串数组(比如:a-string-list-property = "first string","second string";)
4、整数(比如:a-cell-property = <1234>;)
5、16进制数(比如:a-byte-data-property = [0x01 0x02 0x03 0x04];)
2.2.2常用的属性名及内容的意义
有关属性名及内容更为具体的意义和使用方式,需要仔细反复阅读Documentation/devicetree/目录下的相关文件!
下面列出一些常用的属性:
1、compatible(兼容)
compatible的内容为字符串数组,其形式为:<manufacturer>,<model>。
其意义代表设备"厂商和哪个具体的型号"或者"具体设备名称和兼容设备",linux内核中的解析代码,通过节点此属性来确定这个具体的驱动匹配,
比如在zynq-7000.dtsi中根节点属性:
compatible = "xlnx,zynq-7000"
在zynq-zed.dts中qspi结点中flash子节点的属性:
复制代码
/{
...
&qspi{
...
flash@0{
compatible = "n25q128a11";
...
}
};
...
};
复制代码
2、reg(设备地址)
reg的内容一般为16进制数,其形式为:<address 1 length 1 [address 2 length 2] [address 3 length 3] ...>,
address代表此设备相对于父节点的偏移地址
length代表设备可以操作的地址范围,也就是地址大小
reg中的address和length数量的多少,是由#address-cells和#size-cells两个属性来决定子节点的reg内容。
比如:
在zynq-70000.dtsi文件中 cpus节点定义#address-cells = 1,#size-cells=0,代表子节点的reg属性中地址1位,大小位为空。
复制代码
/{
...
cpus{
#address-cells = <1>;
#size-cells = <0>;
cpu@0{
....
reg = <0>;
....
};
cpu@1{
....
reg = <1>;
....
};
};
};
复制代码
在ambs节点中定义#address-cells = 1,#size-cells = 1,代表子节点reg属性中地址和大小都为1位。
复制代码
/{
amba:amba{
....
#address-cells = <1>;
#size-cells = <1>;
....
adc:adc@f8007100{
....
reg = <0xf8007100 0x20>;
....
};
gpio0:gpio@e000a000{
...
reg = <0xe000a000 0x1000>;
...
};
};
};
复制代码
3、interrupt-controller(中断控制器)
此属性为空,通过此属性以表明此设备具有中断相关功能。
4、#interrupt-cells(表明interrupts属性中地址大小)
与#size-cells相似
5、interrupt-parent(指明此控制器所依附的中断控制器)
若子节点中没有指明此属性,则从父节点中继承。
比如zynq-70000.dtsi中的gpio控制器节点:
复制代码
/{
....
gpio0:gpio@e00a000{
compatible = "xlnx,zynq-gpio-1.0";
#gpio-cells = <2>;
#interrupt-cells = <2>;
clocks = <&clkc 42>;
gpio-controller;
interrupt-controller;
interrupt-parent = <&intc>;
interrupts = <0 20 4>;
reg = <0xe00a000 0x1000>;
};
....
};