简介
DTS文件
用来描述设备树文件,也就是开发板上的设备信息
设备树的引用原因
以LED驱动为例,如果你要更换LED所用的GPIO引脚,需要修改驱动程序源码、重新编译驱动、重新加载驱动。
在内核中,使用同一个芯片的板子,它们所用的外设资源不一样,比如A板用GPIO A,B板用GPIO B。而GPIO的驱动程序既支持GPIO A也支持GPIO B,你需要指定使用哪一个引脚,怎么指定?在.c文件中指定。
随着ARM芯片的流行,内核中针对这些ARM板保存有大量的、没有技术含量的文件(上述的指定资源的.c文件)。
Linus大发雷霆:“this whole ARM thing is a f*cking pain in the ass”。
于是,Linux内核开始引入设备树。设备树并不是重新发明出来的,在Linux内核中其他平台如PowerPC,早就使用设备树来描述硬件了。
Linus发火之后,内核开始全面使用设备树来改造,神人就神人。
/sys/firmware/devicetree目录下是以目录结构程现的dtb文件, 根节点对应base目录, 每一个节点对应一个目录, 每一个属性对应一个文件。
这些属性的值如果是字符串,可以用cat命令把它打印出来;对于数值,可以用hexdump把它打印出来。
一个单板启动时,u-boot先运行,它的作用是启动内核。U-boot会把内核和设备树文件都读入内存,然后启动内核。在启动内核时会把设备树在内存中的地址告诉内核。
设备树名词关系
DTS:设备树源码文件
DTB:DTS编译得到的二进制文件
DTS —> DTB 需要用到DTC编译工具
DTC 工具源码在 Linux 内核的 scripts/dtc 目录下.另外dtsi就相当于C语言的.h文件的概念
dtsi文件:设备树模板,一般 dts 文件可以 include 包含 dtsi 文件,类似于头文件
设备树语法
Device格式
DTS文件格式
/dts-v1/; // 表示版本
[memory reservations] // 格式为: /memreserve/ <address> <length>;
/ {
[property definitions]
[child nodes]
};
node格式
设备树中的基本单元,被称为“node”,其格式为:
[label:] node-name[@unit-address] { // unit-address 寄存器/设备地址
[properties definitions]
[child nodes]
};
label是标号,可以省略,作用是方便引用node,比如:
/dts-v1/;
/ {
uart0: uart@fe001000 {
compatible="ns16550";
reg=<0xfe001000 0x100>;
};
};
可以使用下面 2 种方法来修改 uart@fe001000 这个 node:
- 标签
- 全路径
// 在根节点之外使用 label 引用 node:
&uart0 {
status = “disabled”; // 状态设为 disabled 那么这个节点的定义就会失效
};
或在根节点之外使用全路径:
&{/uart@fe001000} {
status = “disabled”;
};
常用属性(propertics)
value表示
properties就是“property-name = value”,value有多种取值方式
property格式1:
[label:] property-name = value;
property格式2(没有值):
[label:] property-name
property的取值只有4种
1. arrays of cells(1 个或多个 32 位数据, 64 位数据使用 2 个 32 位数据表示),
2. string(字符串),
3. bytestring(1 个或多个字节)
4. 各种值的组合
-
arrays of cells (cell就是一个32位数据,64位数据用两个cell表示)
用尖括号包围起来
interrupts = <17 0xc> // 两个32位数据 interrupts = <0x00000001 0x00000000> // 一个64位数据
-
A null-terminated string (有结束符的字符串),用双引号包围起来
compatible = "simple-bus";
-
A bytestring(字节序列) ,用中括号包围起来
local-mac-address = [00 00 12 34 56 78]; // 每个 byte 使用 2 个 16 进制数来表示 local-mac-address = [000012345678]; // 每个 byte 使用 2 个 16 进制数来表示
-
可以是各种值的组合, 用逗号隔开
compatible = "ns16550", "ns8250"; example = <0xf00f0000 19>, "a strange property format";
1.#address-cells、size-cells
cell指一个32位的数值
address-cells:address要用多少个32位数来表示
size-cells:size要用多少个32位数来表示
表示这个节点下一级节点的地址属性要如何表示
/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
reg = <0x80000000 0x20000000>;
};
};
// reg中第一个32位数据表示这块内存的起始地址
// 第二个32位数据表示这块内存的大小
2.compatible
“ compatible ” 表示 " 兼容 ",对于某个LED,内核中可能有A、B、C三个驱动都支持它,那就可以这么写:
led {
compatible = “A”, “B”, “C”;
};
内核启动时,就会为这个LED按这样的优先顺序为它找到驱动程序:A、B、C
根节点下也有compatible属性,用来选择哪一个“machine desc”:一个内核可以支持machine A,也支持machine B,内核启动后会根据根节点的compatible属性找到对应的machine desc结构体,执行其中的初始化函数。
compatible的值,建议取这样的形式:“manufacturer,model”,即“厂家名,模块名”。
比如:compatibl