设备树简介
设备树的组成
设备树:由1个dts文件+n个dtsi文件组成,它们编译而成dtb(二进制的可执行文件)
dts: 在ARM Linux在,一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录
dtsi: soc厂商会把soc公共的特性和多块开发板公用的特性提炼为dtsi,而dts则负责描述某个具体的产品(开发板)的特性。dts直接或间接的包含多个dtsi(类似于c语言的头文件,使用include包含),就体现了一个完整的产品(开发板)所有的特性
dtb: dtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核。所以Bootloader需要支持设备树才行;Kernel也需要加入设备树的支持
常用节点
/{ // "/{" 表示 根节点 ,dts最开始的地方,可以理解为程序的main入口
//子节点
cpu{ // cpu节点
name = val; // 属性名name,val是属性值。
//val形式:
//1 值
//2)"string"(双引号括起来);
//3)<u32 u32 u32> (尖括号,有多少个32位就放多少个,空格间隔);
//4) [12 34 56](16进制单字节)。
// val可以是这3种形式组合,如<0x123>,"abcd",[34]
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
};
cpu@1 {
compatible = "arm,cortex-a9";
reg = <1>;
};
};
//子节点
memory{ // 内存节点
};
//子节点
I2C{ // I2C控制器节点
};
};
注意cpus和cpus的2个cpu子结点的命名,它们遵循的组织形式为:
name(必选项)@unit-address(可选项)
name(必选项):是一个ASCII字符串,用于描述结点对应的设备类型
如3com Ethernet适配器对应的结点name宜为ethernet,而不是3com509。
unit-address(可选项)
如果一个结点描述的设备有地址,则应该给出**@unit-address**。
多个相同类型设备结点的name可以一样,只要unit-address不同即可,
如本例中含有cpu@0、cpu@1以及serial@101f0000与serial@101f2000这样的同名结点。
常用属性
例子
/ {
compatible = "acme,coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
};
cpu@1 {
compatible = "arm,cortex-a9";
reg = <1>;
};
};
serial@101f0000 {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
interrupts = < 1 0 >;
};
serial@101f2000 {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
interrupts = < 2 0 >;
};
gpio@101f3000 {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
interrupts = < 3 0 >;
};
intc: interrupt-controller@10140000 {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
interrupt-controller;
#interrupt-cells = <2>;
};
spi@10115000 {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
interrupts = < 4 0 >;
};
external-bus {
#address-cells = <2>
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
ethernet@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
interrupts = < 5 2 >;
};
i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
interrupts = < 6 2 >;
rtc@58 {
compatible = "maxim,ds1338";
reg = <58>;
interrupts = < 7 3 >;
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
};
reg
设备的unit-address地址也经常在其对应结点的reg属性中给出。ePAPR标准给出了结点命名的规范:
reg:
//reg的组织形式
reg = <地址1 长度1>, // 起始地址,范围长度
<地址2 长度2>,
<地址3 长度3>,
...
其中的每一组address length表明了设备使用的一个地址范围。
#address-cells: 为1个或多个32位的整型(即cell),基地址、片选号等绝对起始地址所占字长
#size-cells:寄存器地址所占字长
#address-cells = 1
#size-cells = 0
reg = <address1>
#address-cells = 1
#size-cells = 1
reg = <address1 size1>
#address-cells = 2
#size-cells = 1
reg = <address1 address2 size1>
interrupt属性
Device Tree中还可以中断连接信息,对于中断控制器而言,它提供如下四个属性:
- interrupt-controller : 这个属性为空,中断控制器应该加上此属性表明自己的身份;
- #interrupt-cells : 与#address-cells 和 #size-cells相似,它表明连接此中断控制器的设备的interrupts属性的cell大小。
在整个Device Tree中,与中断相关的属性还包括: - interrupt-parent : 设备结点透过它来指定它所依附的中断控制器的phandle,当结点没有指定interrupt-parent 时,则从父级结点继承。对于本例而言,root结点指定了interrupt-parent = <&intc>;其对应于intc: interrupt-controller@10140000,而root结点的子结点并未指定interrupt-parent,因此它们都继承了intc,即位于0x10140000的中断控制器。
- interrupts :用到了中断的设备结点透过它指定中断号、触发方法等,具体这个属性含有多少个cell,由它依附的中断控制器结点的#interrupt-cells属性决定。而具体每个cell又是什么含义,一般由驱动的实现决定,而且也会在Device Tree的binding文档中说明。如果有两个,第一个是中断号,第二个是中断类型,如高电平、低电平、边缘触发等触发特性。对于给定的中断控制器,应该仔细阅读相关文档来确定其中断标识该如何解析。
2个cell
第一个值: 中断号
第二个值: 触发方式
固定的取值如下:
1 = 上升沿触发
2 = 下降沿触发
4 = 高电平触发
8 = 低电平触发
3个cell
第一个值:中断号
第二个值:触发的类型
第三个值:优先级,0级是最高的,7级是最低的;其中0级的中断系统当做 FIQ处理。
在dts中引用其他节点
//label:node-name@unit-address的别名,在其他dts中被引用使为&label
[label:] node-name[@unit-address] { //冒号前的label是为了方便引用给节点起的别名,此label一般使用为&label
[properties definitions] //就是属性定义,对当前节点描述,将硬件信息提供给内核处理
[child nodes] //子节点
}
PIC2: pic@11000000 {
interrupt-controller;
};
another-device-node {
interrupt-parent = <&PIC>; // 使用label来引用上述节点,
interrupt-parent = <&PIC2>; // 使用label来引用上述节点,
// 使用lable时实际上也是使用phandle来引用,
// 在编译dts文件为dtb文件时, 编译器dtc会在dtb中插入phandle属性
};
&PIC: pic@10000000 {
interrupt-controller;
};
覆盖规则:
同一层次的节点,后面的会覆盖前面的节点。
memory@30000000 {
device_type = "memory";
reg = <0x30000000 0x20000000>;
};
memory@30000000 {
reg = <0x30000000 0x10000000>;
};
直接引用方式覆盖(增加)节点属性:
假设下面节点定义在dtsi文件中
xusbxti: oscillator@1 {
compatible = "fixed-clock";
reg = <1>;
clock-frequency = <0>;
clock-output-names = "xusbxti";
#clock-cells = <0>;
};
某个dts文件包含了该dtsi文件,并定义了如下内容
&xusbxti {
clock-frequency = <24000000>;
};
编译设备树
将设备树文件拷贝到内核源码的arch/(处理器平台)/boot/dts/(厂家)/目录下
第一种方式:make dtbs
第二种方式:dtc -I dts -O dtb my.dts > my.dtb
设备树反编译
dtc -I dtb -O dts my.dtb -o my.dts
如果觉得对你有帮助,请意思意思
点击赞助