4. 设备树节点与属性详解:compatible、reg、interrupts、status等核心属性的含义与用法

设备树(Device Tree)的核心价值在于通过节点(Node)与属性(Property)的层级结构,将板级硬件信息以标准化的方式传递给操作系统内核。本章将深入解析最常用的核心属性,包括它们的语法、语义、典型用法以及常见陷阱。

学习提示:设备树属性是驱动与硬件之间的“契约”。理解每个属性的确切含义,是正确编写设备树源文件(.dts)和驱动代码的前提。

4.1 节点与属性的基础结构

设备树是一个树形结构,每个节点代表一个硬件设备或总线,节点内包含若干属性来描述其特性。一个典型的节点结构如下:

device_name@address {
    compatible = "vendor,device";
    reg = <base_addr size>;
    interrupts = <interrupt_spec>;
    status = "okay";
    // 其他属性...
};

节点名称通常由通用名称和单元地址(@后面的部分)组成,单元地址一般对应设备的起始寄存器地址,用于区分同一总线上的多个相同设备。

设备树节点结构图 设备树节点结构 根节点 "/" 子节点 "soc" 设备节点 "uart@1f000" compatible = "vendor,uart"; reg = <0x1f000 0x1000>; interrupts = <0 33 4>; status = "okay"; 节点结构说明: • 节点名称:uart@1f000(设备名@寄存器基址) • 属性以键值对形式存在,分号结尾 • 每个节点描述一个完整的硬件设备 • 子节点继承父节点的总线环境 • 属性值可以是字符串、32位整数数组、字节数组等

4.2 compatible 属性:设备驱动匹配的关键

compatible 属性是设备树中最重要的属性之一,它建立了硬件设备与内核驱动之间的匹配关系。其值是一个字符串列表,格式为 "厂商,设备型号"。

4.2.1 语法与规范

compatible = "vendor,device", "fallback_device";

第一个字符串是精确匹配,后续字符串是兼容匹配(回退方案)。内核在匹配驱动时,会按照列表顺序依次尝试。

匹配方式 示例 说明
精确匹配 "fsl,imx6ull-uart" 仅匹配 i.MX6ULL 的 UART 驱动
兼容匹配 "ns16550" 回退到标准 16550 UART 驱动
多级兼容 "ti,am3359-uart", "ti,omap3-uart" 先匹配 AM3359,再回退到 OMAP3
常见错误:compatible 字符串中不要使用空格、大写字母或特殊字符。厂商前缀必须使用内核维护的 vendor-prefixes.txt 中定义的规范名称。

4.2.2 驱动匹配流程

当内核启动时,设备树解析器会遍历所有节点,并将节点的 compatible 属性与驱动注册的 of_device_id 表进行匹配。匹配成功则调用驱动的 probe 函数。

compatible 属性驱动匹配流程 compatible 属性驱动匹配流程 设备树节点 compatible = "A","B" 匹配驱动 of_device_id 表 匹配成功 → 调用 probe 匹配失败 → 跳过节点 说明:内核按 compatible 列表顺序尝试匹配,第一个匹配成功即停止。如果所有字符串都匹配失败,该设备将无法被驱动。 驱动中通过 of_match_table 注册支持的设备列表。

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

reg 属性用于描述设备在总线上的地址空间,包括寄存器基地址和地址范围。其格式依赖于父节点的 #address-cells 和 #size-cells 属性。

4.3.1 地址单元与大小单元

// 父节点定义地址格式
soc {
    #address-cells = <1>;  // 地址用 1 个 32 位整数表示
    #size-cells = <1>;     // 大小用 1 个 32 位整数表示
    
    uart@1f000 {
        reg = <0x1f000 0x1000>;  // 基址 0x1f000,范围 0x1000
    };
};

// 64 位地址示例
bus {
    #address-cells = <2>;  // 地址用 2 个 32 位整数(64 位)
    #size-cells = <2>;     // 大小用 2 个 32 位整数(64 位)
    
    dma@0x100000000 {
        reg = <0x1 0x00000000 0x0 0x10000000>;
        // 地址 = 0x100000000,大小 = 0x10000000
    };
};
属性 含义 典型值
#address-cells 地址字段占用的 32 位整数个数 1(32位地址)、2(64位地址)
#size-cells 大小字段占用的 32 位整数个数 0(无大小)、1(32位大小)、2(64位大小)
reg 地址和大小交替排列的数组 <addr1 size1 addr2 size2 ...>

4.3.2 多段地址空间

一个设备可能拥有多个不连续的地址段,例如 FIFO 和控制寄存器分离:

ethernet@10000000 {
    compatible = "vendor,gmac";
    reg = <0x10000000 0x1000   // 控制寄存器
           0x20000000 0x2000>; // DMA 描述符区
};
实战要点:驱动中通过 of_iomap() 或 platform_get_resource() 获取 reg 属性定义的地址资源。多段地址通过索引号(0、1、2...)区分。

4.4 interrupts 属性:中断资源描述

interrupts 属性描述设备使用的中断资源,其格式由父节点的 #interrupt-cells 属性定义。中断控制器节点(如 GIC)负责解释这些值。

4.4.1 中断描述格式

// ARM GIC 中断控制器示例
gic: interrupt-controller@1e00000 {
    compatible = "arm,cortex-a7-gic";
    #interrupt-cells = <3>;  // 每个中断用 3 个 32 位整数描述
    interrupt-controller;     // 标记本节点为中断控制器
};

// 设备节点使用中断
uart@1f000 {
    compatible = "vendor,uart";
    reg = <0x1f000 0x1000>;
    interrupts = <0 33 4>;  // 类型  SPI,中断号 33,触发方式 4
    interrupt-parent = <&gic>;  // 指定中断控制器
};
字段 含义 常见值
中断类型 0=PPI(私有外设中断),1=SPI(共享外设中断) 0 或 1
中断号 相对于中断控制器的中断编号 32~1019(SPI)
触发方式 1=上升沿,2=下降沿,4=高电平,8=低电平 1、2、4、8

4.4.2 中断映射与级联

当系统中有多个中断控制器时,通过 interrupt-map 和 interrupt-parent 实现中断的层级映射。

中断映射关系图 中断映射关系图 CPU 核心 GIC 中断控制器 (interrupt-controller) UART 设备 interrupts = <0 33 4> GPIO 设备 interrupts = <0 67 1> DMA 设备 interrupts = <0 89 4> 关键点: • 所有设备的中断都通过 interrupt-parent 指向 GIC • #interrupt-cells = 3 表示每个中断描述占用 3 个 32 位整数

4.5 status 属性:设备状态控制

status 属性用于控制设备是否启用,是板级配置中最常用的属性之一。它允许 SoC 级 .dtsi 文件中定义所有外设,然后在板级 .dts 文件中选择性启用或禁用。

状态值 含义 使用场景
"okay" 设备启用,驱动正常加载 板级文件中启用 SoC 定义的外设
"disabled" 设备禁用,驱动不加载 SoC 级文件中默认关闭未使用的外设
"reserved" 设备保留,操作系统不管理 固件或安全世界使用的设备
"fail" 设备检测失败 硬件探测后由 Bootloader 设置

4.5.1 典型用法:分层覆盖

// imx6ull.dtsi(SoC 级,默认关闭)
uart1: serial@1f000 {
    compatible = "fsl,imx6ull-uart", "fsl,imx6q-uart";
    reg = <0x1f000 0x1000>;
    interrupts = <0 33 4>;
    status = "disabled";  // 默认关闭
};

// my-board.dts(板级,按需启用)
#include "imx6ull.dtsi"

&uart1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart1>;
    status = "okay";  // 板级启用
};
最佳实践:SoC 级 .dtsi 文件中将所有外设的 status 设为 "disabled",板级 .dts 文件中只将实际使用的外设设为 "okay"。这样可以避免未使用的外设占用中断、时钟等资源。

4.6 其他常用属性

除了上述核心属性外,设备树中还有大量标准属性用于描述设备的特定功能:

属性 用途 示例
clock 指定设备使用的时钟源 clocks = <&clk IMX6ULL_CLK_UART1>;
pinctrl 引脚复用配置 pinctrl-0 = <&pinctrl_uart1>;
dmas DMA 通道配置 dmas = <&sdma 1 2>;
power-domains 电源域管理 power-domains = <&pd_core>;
resets 复位信号控制 resets = <&rst 10>;
memory-region 保留内存区域 memory-region = <&vdev0buffer>;

4.7 属性使用综合示例

以下是一个完整的 I2C 控制器及其从设备节点的示例,展示了多个核心属性的协同使用:

// I2C 控制器节点
i2c1: i2c@21a0000 {
    compatible = "fsl,imx6ull-i2c", "fsl,imx6q-i2c";
    reg = <0x021a0000 0x4000>;
    interrupts = <0 36 4>;
    clocks = <&clks IMX6ULL_CLK_I2C1>;
    status = "disabled";
    
    #address-cells = <1>;
    #size-cells = <0>;
    
    // I2C 从设备:温度传感器
    temp_sensor: temperature@48 {
        compatible = "ti,tmp102";
        reg = <0x48>;  // I2C 从设备地址
        interrupts = <5 2>;  // GPIO 中断
        interrupt-parent = <&gpio1>;
        status = "okay";
    };
    
    // I2C 从设备:EEPROM
    eeprom@50 {
        compatible = "atmel,24c02";
        reg = <0x50>;
        pagesize = <16>;
        status = "okay";
    };
};
关键总结:
  • compatible:驱动匹配的核心,格式为 "厂商,设备型号"
  • reg:描述地址空间,格式由父节点的 #address-cells 和 #size-cells 决定
  • interrupts:中断资源描述,格式由中断控制器的 #interrupt-cells 决定
  • status:设备状态控制,"okay" 启用,"disabled" 禁用
  • 所有属性共同构成完整的硬件描述,驱动通过标准 API 解析这些属性
设备树核心属性关系总览 设备树节点 标识属性 compatible model device_type 资源属性 reg interrupts dmas 控制属性 status power-domains resets 配置属性 pinctrl clocks gpios 属性分类说明: • 标识属性: