3. 设备树常用属性详解:compatible、reg、interrupts、status、phandle 等核心属性

设备树(Device Tree)通过节点(node)和属性(property)来描述硬件拓扑。属性是设备树中最基本的“键-值”对,每个属性承载一种硬件特征或配置参数。本章深入剖析 compatible、reg、interrupts、status、phandle 等最常用的核心属性,帮助你在编写或修改设备树时准确表达硬件信息。

3.1 compatible 属性:驱动匹配的“身份证”

compatible 是设备树中最重要的属性之一,它指定了设备与驱动之间的匹配关系。内核通过该属性查找对应的驱动程序。

3.1.1 语法与规范

compatible = "manufacturer,model";

推荐格式为 "厂商,型号",例如:

compatible = "ti,am335x-uart", "ns16550";

多个字符串表示兼容性列表,内核按顺序匹配,优先使用第一个匹配成功的驱动。

3.1.2 匹配优先级

匹配顺序 compatible 值 说明
1 "ti,am335x-uart" 最精确的芯片型号匹配
2 "ns16550" 通用兼容型号匹配
实战建议:编写设备树时,始终将最精确的 compatible 字符串放在最前面,通用兼容字符串放在后面。这样既能支持专用驱动优化,又能保证通用驱动兜底。

3.1.3 驱动匹配流程 SVG

compatible 属性驱动匹配流程 设备树节点 compatible = "ti,am335x-uart" 内核 OF 匹配层 of_match_table 遍历 驱动 probe 调用 匹配成功 匹配失败 返回 -ENODEV 说明:内核按 compatible 字符串顺序匹配,优先使用最精确的驱动 多个字符串时,第一个匹配成功即停止搜索

3.2 reg 属性:描述设备地址空间

reg 属性用于描述设备在总线上的地址范围,包括起始地址和长度。它是内存映射设备、SPI/I2C 设备等硬件资源定位的核心依据。

3.2.1 基本语法

reg = <address1 length1 [address2 length2 ...]>;

每个 address,length 对描述一段连续的地址空间。例如:

uart@44e09000 {
    compatible = "ti,am335x-uart", "ns16550";
    reg = <0x44e09000 0x2000>;
};

表示 UART 设备从物理地址 0x44e09000 开始,占用 0x2000 字节的地址空间。

3.2.2 多段地址空间

当设备需要多个不连续的地址区域时,可以包含多组地址:

reg = <0x40000000 0x10000
       0x50000000 0x20000>;

第一段:0x40000000 起始,0x10000 长度;第二段:0x50000000 起始,0x20000 长度。

3.2.3 #address-cells 与 #size-cells

reg 的解析依赖于父节点的 #address-cells 和 #size-cells 属性:

属性 含义 常见值
#address-cells 地址字段占用的 32 位单元数 1(32位地址)或 2(64位地址)
#size-cells 长度字段占用的 32 位单元数 1(32位长度)或 2(64位长度)
示例解析:若父节点定义 #address-cells = <1>; #size-cells = <1>;,则 reg = <0x44e09000 0x2000> 表示地址 0x44e09000,长度 0x2000。

3.2.4 reg 属性结构 SVG

reg 属性地址空间结构 父节点(总线) #address-cells = <1> #size-cells = <1> uart@44e09000 reg = <0x44e09000 0x2000> 物理地址空间 0x44e09000 ~ 0x44e0afff 多段地址空间示例:reg = <0x40000000 0x10000 0x50000000 0x20000> 第一段:0x40000000-0x4000ffff | 第二段:0x50000000-0x5001ffff

3.3 interrupts 属性:中断资源描述

interrupts 属性描述设备使用的中断资源,包括中断号、触发类型等信息。它是设备与中断控制器之间的桥梁。

3.3.1 基本语法

interrupts = <interrupt-specifier>;

中断描述符的格式由父节点的 #interrupt-cells 决定。常见 ARM GIC 中断控制器使用 3 个 cell:

interrupts = <0 30 4>;
Cell 位置 含义 常见值
Cell 0 中断类型 0 = SPI(共享外设中断),1 = PPI(私有外设中断)
Cell 1 中断号 SPI 中断号(32~1019),PPI 中断号(16~31)
Cell 2 触发类型 1 = 上升沿触发,4 = 高电平触发

3.3.2 interrupt-parent 属性

当设备的中断控制器不是其父节点时,需要使用 interrupt-parent 显式指定中断控制器:

device@1000 {
    compatible = "my,device";
    reg = <0x1000 0x100>;
    interrupt-parent = <&gic>;
    interrupts = <0 42 4>;
};

3.3.3 中断映射关系 SVG

interrupts 属性中断映射关系 外设设备 interrupts = <0 42 4> interrupt-parent 指向中断控制器 GIC 中断控制器 #interrupt-cells = <3> 中断描述符解析(以 GIC 为例) Cell 0 = 0(SPI 类型) | Cell 1 = 42(中断号) | Cell 2 = 4(高电平触发) 实际物理中断号 = 32 + 42 = 74(SPI 中断号偏移 32)

3.4 status 属性:设备状态控制

status 属性用于控制设备是否启用。它是设备树覆盖和动态加载中最常用的属性之一。

3.4.1 可选值

值 含义 说明
"okay" 设备启用 驱动正常 probe,设备可用
"disabled" 设备禁用 驱动不会 probe,设备不可用
"reserved" 保留状态 设备被固件保留,操作系统不应使用
"fail" 设备故障 设备检测到错误,驱动不应 probe

3.4.2 覆盖场景示例

// 基础设备树中禁用
&uart0 {
    status = "disabled";
};

// 设备树覆盖中启用
&uart0 {
    status = "okay";
};
常见陷阱:设备树覆盖时,如果只修改 status 而不重新提供其他必要属性(如 clocks、pinctrl),可能导致设备 probe 失败。覆盖时建议同时提供所有运行时必需的属性。

3.5 phandle 属性:节点引用机制

phandle(指针句柄)是设备树中实现节点间引用的核心机制。每个节点可以有一个唯一的 phandle 值,其他节点通过该值引用它。

3.5.1 隐式 phandle 与显式 phandle

现代设备树通常使用 隐式 phandle,由 DTC 编译器自动分配:

// DTS 源文件
gic: interrupt-controller@f0001000 {
    compatible = "arm,gic-400";
    reg = <0xf0001000 0x1000>;
    interrupt-controller;
    #interrupt-cells = <3>;
};

// 引用方式
device@1000 {
    interrupt-parent = <&gic>;
    interrupts = <0 42 4>;
};

编译后,DTC 自动为 gic 节点生成唯一的 phandle 值,&gic 被替换为对应的数值。

3.5.2 显式 phandle 定义

my_node: node@100 {
    phandle = <0x1234>;
    compatible = "my,device";
};
最佳实践:除非有特殊需求(如与旧版 bootloader 兼容),否则始终使用隐式 phandle。显式指定 phandle 容易导致冲突,且不利于设备树复用。

3.5.3 phandle 引用关系 SVG

phandle 节点引用关系 gic: interrupt-controller phandle = 自动分配(如 0x0001) #interrupt-cells = <3> uart@1000 interrupt-parent = <&gic> dma@2000 interrupt-parent = <&gic> 多个设备可以通过 phandle 引用同一个中断控制器,实现资源共享

3.6 其他常用属性速查

属性名 用途 示例
clock-names 时钟名称列表,与 clocks 属性对应 clock-names = "uart_clk", "baud_clk";
clocks 时钟 phandle 列表 clocks = <&clk_uart &clk_baud>;
pinctrl-names 引脚控制状态名称列表 pinctrl-names = "default", "sleep";
pinctrl-0 引脚控制配置 phandle pinctrl-0 = <&uart0_pins>;
dma-names DMA 通道名称列表 dma-names = "rx", "tx";
dmas DMA 通道 phandle 列表 dmas = <&edma0 2 &edma0 3>;
power-domains 电源域 phandle power-domains = <&pd_core>;
resets 复位控制器 phandle resets = <&rst 10>;

3.7 属性组合实战案例

以下是一个完整的 UART 设备节点,综合运用了本章介绍的核心属性:

uart0: serial@44e09000 {
    compatible = "ti,am335x-uart", "ns16550";
    reg = <0x44e09000 0x2000>;
    interrupts = <0 72 4>;
    interrupt-parent = <&gic>;
    status = "okay";
    clock-names = "uart_clk", "baud_clk";
    clocks = <&clk_uart &clk_baud>;
    pinctrl-names = "default";
    pinctrl-0 = <&uart0_pins>;
    dma-names = "rx", "tx";
    dmas = <&edma 2 &edma 3>;
};
关键点总结:
  • compatible:驱动匹配的唯一标识,精确在前,通用在后
  • reg:描述设备地址空间,受 #address-cells / #size-cells 影响
  • interrupts:中断资源描述,格式由中断控制器的 #interrupt-cells 决定
  • status:设备启用/禁用控制,覆盖操作中最常用的属性
  • phandle:节点引用机制,实现设备树内部的资源关联