设备树的理解
个人理解
设备树是一种设备信息结构体,在一个嵌入式系统中,存在各种设备,CPU,RAM,ROM,IIC,定时器,SPI等等都是一种设备,在系统构建时,为了方便设备驱动开发,将各种设备的信息以树状结构整合到一起,在编写驱动时,从设备树上获取设备基础信息,进行设备的配置和操作。
在设备树中根节点为设备树的根,设备以树干-树枝-树叶的结构链接,设备信息包含:兼容性,寄存器地址,设备类型等信息。
设备树的生成
设备树文件格式为.dtb格式,有dtsi文件通过dtb编译器编译而来。我们通常通过修改dtsi文件,编译生成设备树文件。
根据具体电路原理图及数据手册修改设备树文件后,编译加载设备树,即可在系统中发现修改后的设备文件,然后在编写底层驱动时,根据提取设备文件的描述信息,对设备进行初始化和读写操作。
设备树语法
设备树组成
- demo
/*--------------------第一部分----------------*/
#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi" ---------------①
/*--------------------第二部分----------------*/
/ { --------------------②
model = "Seeed i.MX6 ULL NPi Board";
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
aliases {
pwm0 = &pwm1;
pwm1 = &pwm2;
pwm2 = &pwm3;
pwm3 = &pwm4;
};
chosen {
stdout-path = &uart1;
};
memory {
reg = <0x80000000 0x20000000>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
linux,cma {
compatible = "shared-dma-pool";
reusable;
size = <0x14000000>;
linux,cma-default;
};
};
/*-------------以下内容省略=-------------*/
};
/*--------------------第三部分----------------*/
&cpu0 { --------------------③
dc-supply = <®_gpio_dvfs>;
clock-frequency = <800000000>;
};
&clks { --------------------④
assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
assigned-clock-rates = <786432000>;
};
&fec1 { --------------------⑤
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
status = "okay";
};
/*-------------以下内容省略=-------------*/
-
头文件
设备树可以包含头文件。经常讲一款MPU的设备树信息写成一个dts文件,其它板子使用时,只需要包含这个头文件就把MPU信息加进来了。 -
根节点
/{…}中’/'代表根节点,所有信息都是在根节点之下,一个dts文件只能有一个根节点,不同的头文件中的根节点会合并在一起。 -
追加节点信息
&cpu0中为节点cpu0追加信息。节点可以为本文件中的子节点,也可以是不同的头文件包含的子节点。 -
节点定义
node-name@unit-address{
属性1 = …
属性2 = …
属性13= …
子节点…
}
node-name为节点名,@为分隔符,unit-address为节点reg属性首地址,若无reg属性可直接省略@unit-address。同级子节点节点名唯一,节点名相同,unit-address不同也可以。
- 节点别名
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
}
其中cpu0为节点别名,方便直接通过&cpu0对其追加信息。为此产生一个特殊节点:别名子节点,作用是为其他节点定义别名。
aliases {
can0 = &flexcan1;
can1 = &flexcan2;
ethernet0 = &fec1;
ethernet1 = &fec2;
gpio0 = &gpio1;
gpio1 = &gpio2;
gpio2 = &gpio3;
gpio3 = &gpio4;
gpio4 = &gpio5;
i2c0 = &i2c1;
i2c1 = &i2c2;
/*----------- 以下省略------------*/
}
- choosen 子节点
不代表实际硬件,用于向内核传递参数。
节点属性
- compatible
通常由一个或多个字符串组成,定义了设备编程模型,用于设备和驱动匹配。
intc: interrupt-controller@a01000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xa01000 0x1000>,
<0xa02000 0x100>;
};
-
model
用于指定设备的制造商和型号,推荐使用“执照商, 型号”的格式。 -
status
用于指示设备操作状态,状态值如下
状态值 | 描述 |
---|---|
“okay” | 设备正常运行 |
“disabled” | 设备目前尚未运行,但是未开可能运行(比如热插拔) |
“fail” | 表示设备不可操作 |
“fail-sss” | 设备不可操作,因为检测到严重错误。 |
-
#address-cells和#size-cells
二者同时存在,用于设置子节点的“reg”属性的“书写格式”。size指定子节点reg属性地址字段所占长度。 -
reg
格式reg = <0x900000 0x4000>,表示起始地址为0x900000长度为0x4000的一段空间。 -
ranges
属性值类型:任意数量的 <子地址、父地址、地址长度>编码