2. DTS 文件结构:标准节点写法详解
设备树源文件(.dts)以树形结构描述硬件拓扑。本章逐一拆解 /dts-v1/ 头部、根节点、别名节点、chosen、memory 和 cpus 节点的标准写法与工程约束。
2.1 /dts-v1/ 版本标识
每个 .dts 文件的第一行必须是版本声明,告诉编译器使用设备树 v1 规范。
/dts-v1/;
该行之后可紧跟 /include/ 或 #include 导入头文件。若省略此声明,dtc 编译器会报错或默认使用旧版格式,导致节点解析异常。
工程建议: 始终将
/dts-v1/; 放在文件首行,且分号不可省略。多文件项目中每个 .dts 和 .dtsi 都应包含此声明。
2.2 根节点(Root Node)
根节点是设备树的顶层容器,使用 / 表示。所有外设、总线、CPU、内存等节点都挂在根节点下。
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
#address-cells = <1>;
#size-cells = <1>;
/* 子节点 */
chosen { ... };
memory { ... };
cpus { ... };
ocp { ... };
};
| 属性 | 含义 | 是否必须 |
|---|---|---|
model |
板级名称字符串,用于区分硬件变体 | 强烈建议 |
compatible |
兼容性列表,从具体到通用,内核据此匹配 machine_desc | 必须 |
#address-cells |
子节点 reg 属性中地址字段的 32 位字个数 | 必须(有地址空间时) |
#size-cells |
子节点 reg 属性中长度字段的 32 位字个数 | 必须(有地址空间时) |
关键规则: 根节点的
compatible 字符串必须与内核 arch/arm/mach-xxx/board.c 中的 DT_MACHINE_START 匹配,否则内核无法加载对应板级初始化函数。
2.3 别名节点(aliases)
别名节点为其他节点提供简短、固定的符号名称,常用于 bootloader 或早期启动代码快速查找设备。
aliases {
serial0 = &uart0;
serial1 = &uart1;
mmc0 = &mmc1;
i2c0 = &i2c0;
ethernet0 = &cpsw_emac0;
};
| 别名 | 引用节点 | 典型用途 |
|---|---|---|
serial0 |
&uart0 |
内核早期打印(earlycon) |
mmc0 |
&mmc1 |
根文件系统挂载设备 |
ethernet0 |
&cpsw_emac0 |
网络设备索引 |
避坑提示: 别名节点中的
&label 引用必须在同一 .dts 或 .dtsi 中有对应的 label: 定义。别名值必须是唯一的,重复定义会导致 dtc 警告或覆盖。
2.4 chosen 节点
chosen 节点不描述硬件,而是传递系统运行时参数给内核,由 bootloader 动态填充。
chosen {
bootargs = "console=ttyO0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4";
stdout-path = &uart0;
linux,initrd-start = <0x82000000>;
linux,initrd-end = <0x82800000>;
};
| 属性 | 说明 | 是否必须 |
|---|---|---|
bootargs |
内核命令行参数,与 CONFIG_CMDLINE 拼接 |
推荐 |
stdout-path |
早期控制台设备路径,用于 earlycon | 推荐 |
linux,initrd-start/end |
initramfs 在内存中的物理地址范围 | 使用 initramfs 时必填 |
调试技巧: 在开发阶段,可在
.dts 中硬编码 bootargs 作为默认值,U-Boot 可通过 fdt chosen 命令覆盖。若内核未收到预期参数,优先检查 chosen 节点是否存在且被正确覆盖。
2.5 memory 节点
memory 节点描述系统物理内存的起始地址和大小。U-Boot 通常会在启动时动态更新此节点。
memory {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 起始 0x80000000,大小 512 MB */
};
| 属性 | 值示例 | 说明 |
|---|---|---|
device_type |
"memory" |
固定值,内核据此识别内存节点 |
reg |
<0x80000000 0x20000000> |
地址 + 长度,字宽由根节点 #address-cells 和 #size-cells 决定 |
多段内存写法: 若物理内存不连续,可在
reg 中列出多组地址-长度对:reg = <0x80000000 0x10000000>, <0x90000000 0x10000000>;
2.6 cpus 节点
cpus 节点是 CPU 核心的容器,每个 CPU 核心作为一个子节点,必须包含 #address-cells 和 #size-cells。
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a8";
device_type = "cpu";
reg = <0>;
clocks = <&dpll_mpu_ck>;
clock-latency = <300000>; /* 纳秒 */
};
cpu@1 {
compatible = "arm,cortex-a8";
device_type = "cpu";
reg = <1>;
clocks = <&dpll_mpu_ck>;
clock-latency = <300000>;
};
};
| 属性 | 说明 | 多核时必须 |
|---|---|---|
#address-cells |
CPU 核心编号的 32 位字个数,通常为 1 | 是 |
#size-cells |
CPU 节点无长度字段,固定为 0 | 是 |
reg |
CPU 核心 ID,与 MPIDR 寄存器低位数对应 | 是 |
device_type |
固定为 "cpu" |
是 |
clocks |
CPU 主时钟 phandle,用于 cpufreq 调频 | 推荐 |
2.7 节点标准写法总结
| 节点 | 核心属性 | 常见错误 |
|---|---|---|
/dts-v1/ |
版本声明 | 遗漏分号或放在 #include 之后 |
根节点 / |
compatible, #address-cells, #size-cells |
compatible 字符串与内核不匹配 |
aliases |
别名 = &label |
引用未定义的 label,别名重复 |
chosen |
bootargs, stdout-path |
bootloader 未覆盖导致参数失效 |
memory |
device_type = "memory", reg |
地址/长度与硬件实际不符 |
cpus |
#address-cells, #size-cells = <0> |
#size-cells 不为 0,reg 跳号 |
工程检查清单:
✅
✅ 根节点
✅
✅ chosen 节点
✅ memory 节点
✅ cpus 节点 reg 从 0 开始连续,无跳号
✅
/dts-v1/; 在文件首行✅ 根节点
compatible 与内核 machine_desc 一致✅
#address-cells 和 #size-cells 在根节点和 cpus 节点正确设置✅ chosen 节点
bootargs 包含控制台和根文件系统参数✅ memory 节点
reg 地址范围在硬件手册范围内✅ cpus 节点 reg 从 0 开始连续,无跳号