4. 设备树(DT)基础回顾:设备树语法、节点与属性
设备树(Device Tree, DT)是嵌入式系统中用于描述硬件拓扑结构的数据结构,它使得同一份内核镜像能够支持多种硬件平台。在从 ARM 向 RISC-V 移植驱动时,设备树是解耦硬件描述与内核代码的关键桥梁。本节将系统回顾设备树的核心语法、节点与属性定义,以及 .dts、.dtsi、.dtb 文件之间的关系。
4.1 设备树语法基础
设备树源文件(.dts)采用树形结构描述硬件,每个硬件设备对应一个节点(node),节点内包含若干属性(property)描述设备的配置信息。其基本语法规则如下:
- 节点定义:
node-name@unit-address,其中unit-address通常为设备基地址。 - 属性赋值:
property-name = <value>;或property-name = "string";。 - 标签(label):
label: node-name@address,用于在其它位置引用节点。 - 包含文件:
#include "filename.dtsi",用于复用通用硬件描述。
4.1.1 节点与属性示例
/dts-v1/;
/ {
compatible = "acme,coyote-revenge";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
device_type = "cpu";
};
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB at 0x80000000 */
};
serial@101f1000 {
compatible = "ns16550";
reg = <0x101f1000 0x1000>;
interrupts = <5>;
interrupt-parent = <&gic>;
};
};
#address-cells 和 #size-cells 定义子节点中 reg 属性的地址和长度字段宽度。在 RISC-V 平台上,这两个值通常为 <2> 和 <2>,以支持 64 位地址空间。
4.2 标准属性详解
设备树规范定义了一组标准属性,用于描述设备的核心特征。以下三个属性在驱动移植中最为关键:
| 属性名 | 作用 | 格式 | 示例 |
|---|---|---|---|
compatible |
指定设备兼容的驱动名称,内核通过此属性匹配驱动 | "manufacturer,model" |
"ti,am3352-uart" |
reg |
描述设备在总线上的地址空间(基地址 + 长度) | <address length> |
<0x10000000 0x1000> |
interrupts |
描述设备使用的中断号及触发类型 | <interrupt-specifier> |
<0 3 4>(SPI 中断号 3,高电平触发) |
4.2.1 compatible 属性与驱动匹配
compatible 是驱动与设备绑定的核心依据。内核的 of_match_table 会遍历设备树节点的 compatible 字符串列表,找到匹配的驱动。在 ARM 到 RISC-V 移植中,通常需要修改 compatible 字符串以反映新平台的厂商和型号。
/* ARM 平台 */
compatible = "arm,pl011", "arm,primecell";
/* RISC-V 平台 */
compatible = "sifive,uart0", "sifive,uart";
4.2.2 reg 属性与地址映射
reg 属性定义了设备的物理地址范围。驱动通过 of_iomap() 或 platform_get_resource() 获取该地址并建立映射。在 RISC-V 平台上,由于地址空间可能更大,#address-cells 通常设为 2。
reg 中的地址值是否与 RISC-V 平台的 memory 节点和 soc 总线地址空间一致。错误的地址映射会导致内核 panic。
4.2.3 interrupts 属性与中断控制器
interrupts 属性指定设备连接的中断线。其格式由父中断控制器(interrupt-parent)的 #interrupt-cells 决定。ARM 平台常用的 GIC(Generic Interrupt Controller)与 RISC-V 平台常用的 PLIC(Platform-Level Interrupt Controller)在中断描述上存在显著差异:
| 中断控制器 | #interrupt-cells | 中断描述格式 | 示例 |
|---|---|---|---|
| ARM GIC | 3 | <中断类型 中断号 触发方式> | <0 42 4>(SPI, 中断号42, 高电平触发) |
| RISC-V PLIC | 1 | <中断号> | <10>(中断号10) |
4.3 dts / dtsi / dtb 文件关系
设备树源文件通过编译生成二进制 .dtb 文件,供内核在启动时解析。理解三种文件类型的关系是高效管理设备树的基础。
4.3.1 文件组织最佳实践
- 分层设计:将 SoC 级通用描述放在
.dtsi中,板级差异放在.dts中,避免重复。 - 覆盖机制:
.dts可以覆盖.dtsi中定义的节点属性,实现板级定制。 - 多级包含:RISC-V 平台常采用
soc.dtsi→board.dtsi→my-board.dts的层级结构。
/* riscv-soc.dtsi - 通用 RISC-V SoC 描述 */
/ {
cpus { ... };
soc {
plic: interrupt-controller@c000000 {
compatible = "sifive,plic-1.0.0";
reg = <0x0 0xc000000 0x0 0x4000000>;
interrupt-controller;
#interrupt-cells = <1>;
};
uart0: serial@10010000 {
compatible = "sifive,uart0";
reg = <0x0 0x10010000 0x0 0x1000>;
interrupt-parent = <&plic>;
interrupts = <3>;
};
};
};
/* my-board.dts - 板级文件 */
/dts-v1/;
#include "riscv-soc.dtsi"
/ {
model = "My RISC-V Board";
compatible = "mycompany,myboard";
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x20000000>; /* 512 MB */
};
&uart0 {
status = "okay";
clock-frequency = <3686400>;
};
};
4.4 设备树在驱动移植中的核心作用
在 ARM 到 RISC-V 的驱动移植过程中,设备树承担以下关键职责:
- 硬件描述解耦:将硬件配置信息从内核代码中剥离,使同一份驱动可适配不同平台。
- 中断控制器抽象:通过
interrupt-parent和interrupts属性,驱动无需关心底层中断控制器类型(GIC vs PLIC)。 - 地址空间映射:
reg属性提供物理地址,驱动通过platform_get_resource()获取,无需硬编码。 - 时钟与复位管理:通过
clocks、resets等属性描述设备依赖关系。
compatible 字符串是否被目标 RISC-V 平台驱动支持;若不支持,需在驱动中新增匹配项。同时,确保 reg 地址和 interrupts 格式与 RISC-V 中断控制器规范一致。