【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
Linux设备树的规范 - DTS
1. 语法总览
注释: 结点 = 节点
Devicetree node格式:(设备树节点格式)
[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
};
解释:
字段 | 解释 |
---|---|
[label:] | 可以写, 也可以不写, 写的话可以方便别人引用你这个节点. |
node-name | 节点的名字 |
[@unit-address] | 节点名后面可以加上一个地址(组合起来就是这个节点的名字, 如 led@0x120D6100), 用于防止节点的重名.(不同级别下的重名, 不属于重名. 即任意两个节点的全路径不能相同) |
[properties definitions] | 该节点属性的定义(如compatible属性: compatible = “ybk_led”; 如reg属性: reg = <0x120D6100 1>;) |
[child nodes] | 设备树的结点, 用于描述这个板子的硬件资源. |
{ }; | 代表一个节点的始末, 跟在[label:] node-name[@unit-address]之后. (如果是 / { }, 那么它是一个根节点, 是和我们Linux中的根目录同等地位的) |
举个例子:
/ {
model = "Hisilicon HI3516CV500 DEMO Board";
compatible = "hisilicon,hi3516cv500";
memory {
device_type = "memory";
reg = <0x82000000 0x20000000>;
};
led@0x120D6100 {
compatible = "ybk_led";
reg = <0x120D6100 1>;
};
};
2. 语法细说
2.1 [label:]
uart0: uart@120a0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x120a0000 0x1000>;
interrupts = <0 6 4>;
clocks = <&clock HI3516CV500_UART0_CLK>;
clock-names = "apb_pclk";
status = "disabled";
};
aliases {
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
/* 修改引用节点的个别属性 */
&uart0 {
status = "okay";
};
讲解: (label为uart0)
由上可见, 第一个节点为uart的定义, 它的label为uart0, 在aliases节点中, 使用&uart0引用uart节点. 故label的作用是方便其它节点来引用它.
如果不使用label, 引用该节点的方式是怎么样的呢? 如下:
uart@120a0000 {
phandle = <1>;
compatible = "arm,pl011", "arm,primecell";
reg = <0x120a0000 0x1000>;
interrupts = <0 6 4>;
clocks = <&clock HI3516CV500_UART0_CLK>;
clock-names = "apb_pclk";
status = "disabled";
};
aliases {
serial0 = <1>;
serial1 = &uart1;
serial2 = &uart2;
};
由上可见, 我们使用了节点中的phandle属性来标明自己, 其它节点引用时只需要<1>就可以了, 但是缺陷也很明显, 不直观, 可读性差.
使用phandle属性时需要注意, 它的取值必须是唯一的(不要跟其他的phandle值一样).
2.1 [properties definitions]
Property的格式:
- property-name = value; /* 有值 */
- property-name; /* 没有值 */
Property的值:
- arrays of cells(1个或多个32位数据, 64位数据使用2个32位数据表示) (cell就是一个32位的数据)
- string(字符串)
- bytestring(1个或多个字节)
举个例子:
/* 1. arrays of cells */
interrupts = <17 0xc>; // 0xc可能表示中断的出发类型
clock-frequency = <0x00000001 0x00000000>; //64bit数据使用2个cell来表示:(使用两个32位数来表示)
/* 2. string(字符串), A null-terminated string (有结束符的字符串) */
compatible = "ybk_led"; //长度为8, 包含一个'0'
/* 3. bytestring(字节序列), 0不能被忽略! */
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";
3. DTS的文件布局(layout)
/dts-v1/; /* 表示dts文件的版本 */
/**
* 表示保留的内存区域
* (假设你的DDR有64M, 但是你不想完全给内核使用, 那么你可以使用这个选项将它保留下来供自己使用)
* 格式为: /memreserve/ <address> <length>;
*/
[memory reservations]
/* '/'表示根, 这个是设备树的起点 */
/ {
[property definitions] /* 属性定义, 用于描述这个设备树属于哪一块板子. */
eg:
model = "Hisilicon HI3516CV500 DEMO Board";
compatible = "hisilicon,hi3516cv500";
[child nodes] /* 设备树的结点, 用于描述这个板子的硬件资源. */
};
4. DTS特殊的、默认的属性
4.1 根节点(根节点必须有的属性):
字段 | 解释 |
---|---|
#address-cells | 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address) |
#size-cells | 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) |
compatible | 定义一系列的字符串, 用来指定内核中哪个machine_desc可以支持本设备, 即这个板子兼容哪些平台. ( 每一种单板在内核里面都有一个machine_desc结构体, 里面有不同的初始化函数, 你需要指定这里的compatible属性, 来指导内核选择正确的machine_desc结构体. 也就是说这里的作用是使内核执行正确的初始化函数 ) |
model | 这个板子是什么, 比如有2款板子配置基本一致, 它们的compatible是一样的, 那么就通过model来分辨这2款板子 |
对设备树中的#address-cells和#size-cells举个例子:
扫描二维码关注公众号,回复:
11135395 查看本文章
/ {
#address-cells = <0x1>; /* 使用1个u32来代表address */
#size-cells = <0x0>; /* 使用0个u32来代表size */
memory {
device_type = "memory";
reg = <0x82000000>; /* 0x82000000是存取memory的address */
};
}
/ {
#address-cells = <0x1>; /* 使用1个u32来代表address */
#size-cells = <0x1>; /* 使用0个u32来代表size */
memory {
device_type = "memory";
/**
* 0x82000000是存memory的address
* 0x20000000是存memory的size
*/
reg = <0x82000000 0x20000000>;
};
}
4.2 /memory:
字段 | 解释 |
---|---|
device_type | 必须等于: “memory” |
reg | 用来指定内存的地址、大小 |
举个例子:
memory {
device_type = "memory";
reg = <0x82000000 0x20000000>;
};
4.3 /chosen:
chosen节点不描述一个真实设备, 而是用于firmware传递一些数据给OS, 比如bootloader传递内核启动参数给内核. 示例代码如下:
chosen {
bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc";
console="ttySAC0, 115200";
};
4.4 /cpus:
/cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu. 所以 /cpus 中有以下2个属性:
字段 | 解释 |
---|---|
#address-cells | 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address) |
#size-cells | 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size), 必须设置为0 |
4.4 /cpus/cpu*:
字段 | 解释 |
---|---|
device_type | “cpu” |
reg | 表明自己是哪一个cpu |
官方文档: https://www.devicetree.org/specifications/