2. 设备树节点与属性:节点命名规则、标准属性详解

设备树(Device Tree)是嵌入式 Linux 中描述硬件拓扑结构的核心机制。本章深入解析设备树节点的命名规范与五大标准属性,帮助开发者准确编写与解读设备树源文件(.dts)。

核心认知:设备树节点对应硬件实体(如 CPU、UART、GPIO 控制器),属性则描述该实体的配置参数(如地址、中断、状态)。节点与属性的组合构成了硬件描述语言。

2.1 节点命名规则

每个设备树节点必须遵循固定的命名格式,以确保内核能够正确解析。节点名由 节点名称 和可选的 单元地址(unit-address) 组成。

2.1.1 基本格式

node-name@unit-address
  • node-name:描述设备类型,如 uart、gpio、i2c。通用名优先,如 serial 优于 ns16550。
  • unit-address:设备的寄存器起始地址或总线编号,使用十六进制小写。若节点无地址(如 chosen),可省略 @unit-address。

2.1.2 命名规范对比

节点示例 是否合法 说明
uart@ff010000 ✅ 合法 标准格式,地址为寄存器基址
my_device@0x1000 ❌ 不合法 地址不应包含 0x 前缀
cpu@0 ✅ 合法 CPU 节点,地址为核编号
chosen ✅ 合法 特殊节点,无地址
LED ❌ 不合法 节点名应全小写
常见错误:节点名中混入大写字母、地址包含 0x 前缀、或遗漏 @ 符号。这些错误会导致内核无法匹配节点,驱动加载失败。

2.1.3 节点命名与路径

设备树通过 全路径 唯一标识节点,路径以根节点 / 开始,各级节点名用 / 分隔。例如:

/soc/uart@ff010000

路径中的节点名必须与定义时的名称完全一致,包括 @unit-address 部分。

设备树节点命名结构 / (根节点) soc (总线节点) chosen (特殊节点) uart@ff010000 gpio@ff020000 节点名 = 通用名 + @地址 地址为十六进制,无 0x 前缀

2.2 标准属性详解

设备树定义了若干标准属性,用于描述硬件的关键特性。以下逐一解析 compatible、reg、interrupts、status 四大核心属性。

2.2.1 compatible 属性:驱动匹配的关键

compatible 属性是设备树与驱动之间的“握手协议”。它指定了设备所兼容的驱动列表,内核通过该属性查找对应的 platform_driver。

compatible = "vendor,device", "fallback_device";
  • 格式:字符串列表,优先使用第一个匹配项。
  • 命名规范:"厂商,设备型号",如 "fsl,imx6q-uart"。
  • 回退机制:若第一个不匹配,依次尝试后续字符串。
最佳实践:始终提供至少两个兼容字符串:一个精确匹配(含厂商前缀),一个通用回退(如 "ns16550")。这提高了设备树的可移植性。

2.2.2 reg 属性:地址与大小描述

reg 属性定义设备的寄存器地址空间,由 地址 和 大小 组成的元组列表构成。

reg = <address1 length1 address2 length2 ...>;
字段 含义 示例值
address 寄存器基址或总线地址 0xFF010000
length 地址空间大小(字节) 0x1000

地址与大小的宽度由父节点的 #address-cells 和 #size-cells 决定。例如:

soc {
    #address-cells = <1>;  // 地址用 1 个 32 位单元表示
    #size-cells    = <1>;  // 大小用 1 个 32 位单元表示

    uart@ff010000 {
        compatible = "fsl,imx6q-uart", "ns16550";
        reg = <0xFF010000 0x1000>;  // 基址 0xFF010000,大小 4KB
    };
};

2.2.3 interrupts 属性:中断连接描述

interrupts 属性描述设备的中断请求线,其格式依赖于 中断控制器 的 #interrupt-cells 属性。

interrupts = <interrupt-specifier>;

常见 ARM GIC(通用中断控制器)使用 3 个 cell:

Cell 位置 含义 典型值
Cell 0 中断类型 0 = SPI(共享外设中断),1 = PPI(私有外设中断)
Cell 1 中断编号 32~1019(SPI),16~31(PPI)
Cell 2 触发方式 1 = 上升沿触发,4 = 高电平触发
uart@ff010000 {
    compatible = "fsl,imx6q-uart", "ns16550";
    reg = <0xFF010000 0x1000>;
    interrupts = <0 58 4>;  // SPI 类型,中断号 58,高电平触发
    interrupt-parent = <&gic>;  // 引用中断控制器节点
};
易错点:忘记指定 interrupt-parent 或引用的中断控制器节点不存在,会导致中断无法注册,驱动 probe 失败。

2.2.4 status 属性:设备启用控制

status 属性控制设备是否被内核启用。常用值如下:

值 含义 使用场景
"okay" 设备启用 默认启用状态
"disabled" 设备禁用 硬件存在但暂不使用,或通过覆盖启用
"fail" 设备检测失败 硬件初始化出错时由固件设置
"reserved" 保留给其他用途 固件或安全世界使用
// 在 .dtsi 中默认禁用
uart3: uart@ff030000 {
    compatible = "fsl,imx6q-uart", "ns16550";
    reg = <0xFF030000 0x1000>;
    status = "disabled";
};

// 在 .dts 中通过覆盖启用
&uart3 {
    status = "okay";
};
标准属性与驱动匹配流程 设备树节点 compatible = "vendor,uart" reg = <0xFF010000 0x1000> interrupts = <0 58 4> status = "okay" 内核解析阶段 1. 读取 compatible 2. 解析 reg 映射内存 3. 注册中断 4. 检查 status 驱动匹配 of_match_table 匹配成功 → probe 调用 status = "disabled" ? 跳过驱动加载 继续 probe 关键流程:compatible 决定驱动匹配 → reg 提供内存资源 → interrupts 连接中断控制器 → status 控制启用/禁用 任一属性缺失或错误,都可能导致驱动 probe 失败

2.3 属性组合实战示例

以下是一个完整的 UART 设备树节点,综合运用了上述所有标准属性:

/dts-v1/;

/ {
    model = "Example Board";
    compatible = "vendor,example-board";

    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        gic: interrupt-controller@ffa00000 {
            compatible = "arm,gic-400";
            reg = <0xFFA00000 0x1000>;
            interrupt-controller;
            #interrupt-cells = <3>;
        };

        uart0: serial@ff010000 {
            compatible = "vendor,uart", "ns16550";
            reg = <0xFF010000 0x1000>;
            interrupts = <0 58 4>;
            interrupt-parent = <&gic>;
            clock-frequency = <24000000>;
            status = "okay";
        };
    };
};
调试技巧:使用 dtc -I dtb -O dts 反编译 DTB 文件,检查属性是否被正确覆盖。重点关注 status 和 compatible 的值。

2.4 属性常见错误与排查

错误类型 现象 解决方案
compatible 拼写错误 驱动不匹配,probe 不调用 核对驱动 of_match_table 中的字符串
reg 地址与大小不匹配 ioremap 失败或访问越界 检查 #address-cells / #size-cells 配置
interrupts 格式错误 中断无法注册,设备无响应 确认 interrupt-controller 的 #interrupt-cells
status 未设置或错误 设备被跳过 显式设置 status = "okay"