目录
1 引言
由于在参与的某个项目中涉及到修改dts的相关参数,所以对dts进行整体的学习了解。Linux内核从3.x版本之后开始支持使用设备树,这样做的意义重大,可以实现驱动代码与设备的硬件信息相互的隔离,减少了代码中的耦合性DTS。
2 dts加载
如果要使用Device Tree,首先用户要了解自己的硬件配置和系统运行参数,并把这些信息组织成Device Tree source file。通过DTC(Device Tree Compiler),可以将这些适合人类阅读的Device Tree source file变成适合机器处理的Device Tree binary file(有一个更好听的名字,DTB,device tree blob)。在系统启动的时候,u-boot可以将保存在flash中的DTB copy到内存,并把DTB的起始地址传递给kernel。
2.1 dts中相关符号的含义
- / - 根节点
- @ - 如果设备有地址,则由此符号指定
- & - 引用节点
- : - 冒号前的label是为了方便引用给节点起的别名,此label一般使用为&label
- , - 属性名称中可以包含逗号。如compatible属性的名字 组成方式为”[manufacturer], [model]”,加入厂商名是为了避免重名。自定义属性名中通常也要有厂商名,并以逗号分隔。
- # - #并不表示注释。如 #address-cells ,#size-cells 用来决定reg属性的格式。
- - 空属性并不一定表示没有赋值。如 interrupt-controller 一个空属性用来声明这个node接收中断信号数据类型
- ”” - 引号中的为字符串,字符串数组:”strint1”,”string2”,”string3”
- < > - 尖括号中的为32位整形数字,整形数组<12 3 4>
- [ ] - 方括号中的为32位十六进制数,十六机制数据[0x11 0x12 0x13] 其中0x可省略
2.2 dts的描述信息
Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi,类似于C语言的头文件。其他的machine对应的.dts就include这个.dtsi。
并且,对于同一个节点的设置情况,dts
中的配置会覆盖dtsi
中的配置。具体如下图所示(status的状态):
2.3 dts的结构
device tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address。如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。unit-address的具体格式是和设备挂在那个bus上相关。例如对于cpu,其unit-address就是从0开始编址,以此加一。而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。root node的node name是确定的,必须是“/”。
2.4 dts中的 reg 理解
设备的地址特性根据一下几个属性来控制:
reg #address-cells #size-cells
reg意为region,区域。格式为:
reg = <address1length1 [address2 length2] [address3 length3]>;
父类的address-cells和size-cells决定了子类的相关属性要包含多少个cell,如果子节点有特殊需求的话,可以自己再定义,这样就可以摆脱父节点的控制。
address-cells决定了address1/2/3包含几个cell,size-cells决定了length1/2/3包含了几个cell。例如:
spi@10115000{
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
};
位于0x10115000的SPI设备申请地址空间,起始地址为0x10115000,长度为0x1000,即属于这个SPI设备的地址范围是0x10115000~0x10116000
实际应用中,有另外一种情况,就是通过外部芯片片选激活模块。例如,挂载在外部总线上,需要通过片选线工作的一些模块:
external-bus {
#address-cells = <2>
#size-cells = <1>;
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>;
rtc@58 {
compatible = "maxim,ds1338";
reg = <58>;
interrupts = < 7 3 >;
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
};
external-bus使用两个cell来描述地址,一个是片选序号,另一个是片选序号上的偏移量。而地址空间长度依然用一个cell来描述。 所以以上的子设备们都需要3个cell来描述地址空间属性——片选、偏移量、地址长度。在上个例子中,有一个例外,就是i2c控制器模块下的rtc模块。 因为I2C设备只是被分配在一个地址上,不需要其他任何空间,所以只需要一个address的cell就可以描述完整,不需要size-cells。
3 参考文献:
https://blog.csdn.net/u010632165/article/details/89847843
《DTS 基本知识交流.ppt》