3. 设备树节点与属性:标准节点与关键属性详解

设备树(Device Tree)的核心是描述硬件拓扑的节点(Node)与属性(Property)。节点代表硬件设备或总线,属性则描述节点的具体特征。理解标准节点与关键属性是编写和调试设备树的基础。

3.1 标准节点:硬件骨架

设备树根节点(/)下必须包含若干标准节点,它们构成了系统硬件的顶层骨架。下表列出了最核心的四个标准节点及其作用:

节点路径 节点名称 作用与说明 是否必须
/ 根节点 设备树的入口,所有其他节点的父节点。包含 model、compatible 等顶层属性。 是
/chosen chosen 传递引导参数,如 bootargs(内核命令行)、stdout-path(控制台设备路径)。不描述硬件。 推荐
/memory memory 描述系统物理内存的起始地址与大小,通过 reg 属性定义。 是
/cpus cpus 包含所有 CPU 核心的子节点,每个核心用 cpu@<id> 表示,描述频率、缓存等信息。 是
实战提示: 在覆盖(overlay)中,/chosen 节点常用于动态修改内核启动参数,例如在调试阶段追加 earlyprintk 或 initcall_debug。

3.2 关键属性详解:硬件描述语言

属性是设备树的“词汇”。以下三个属性是嵌入式开发中最常用、最关键的属性,它们直接决定了驱动与硬件的匹配方式。

3.2.1 compatible:驱动匹配的钥匙

compatible 属性是一个字符串列表,用于将设备节点与内核驱动进行匹配。格式为 "厂商,型号",优先级从前往后递减。

// 示例:I2C控制器节点
i2c@ff010000 {
    compatible = "snps,designware-i2c", "generic-i2c";
    reg = <0x0 0xff010000 0x0 0x1000>;
    interrupts = <0 56 4>;
};
  • 匹配规则: 内核驱动通过 of_match_table 查找第一个匹配的字符串。
  • 回退机制: 第一个字符串不匹配时,尝试第二个(如 "generic-i2c"),提高兼容性。
  • 命名规范: 厂商名小写,型号使用连字符,避免下划线。

3.2.2 reg:地址与内存映射

reg 属性定义设备的地址空间,格式为 <地址 长度> 的数组。对于内存映射设备,它指定了总线上的基地址和映射范围。

// 单地址段示例
memory@80000000 {
    device_type = "memory";
    reg = <0x0 0x80000000 0x0 0x40000000>;  // 起始0x80000000,大小1GB
};

// 多地址段示例(如带内部SRAM的网卡)
ethernet@ff020000 {
    compatible = "cadence,gem";
    reg = <0x0 0xff020000 0x0 0x1000>,  // MAC寄存器
          <0x0 0xff030000 0x0 0x2000>;  // 描述符RAM
};
常见错误: 在 64 位系统中,reg 的地址和长度必须使用两个 32 位单元表示(如 <0x0 0x80000000 0x0 0x40000000>),否则会导致地址截断。

3.2.3 interrupts:中断连接

interrupts 属性描述设备的中断信号,其格式由父节点的 #interrupt-cells 决定。最常用的 ARM GIC(通用中断控制器)使用 3 个 cell:

Cell 位置 含义 常见值
Cell 1 中断类型 0 = SPI(共享外设中断),1 = PPI(私有外设中断)
Cell 2 中断编号 SPI 范围 32~1019,PPI 范围 16~31
Cell 3 触发方式 1 = 上升沿,2 = 下降沿,4 = 高电平,8 = 低电平
// 中断控制器定义
gic: interrupt-controller@ff100000 {
    compatible = "arm,gic-400";
    reg = <0x0 0xff100000 0x0 0x1000>;
    interrupt-controller;
    #interrupt-cells = <3>;
};

// 使用中断的设备
uart@ff200000 {
    compatible = "ns16550a";
    reg = <0x0 0xff200000 0x0 0x1000>;
    interrupts = <0 33 4>;  // SPI 33号,高电平触发
    interrupt-parent = <&gic>;
};

3.3 自定义属性:扩展硬件描述

除了标准属性,设备树允许开发者定义私有属性,用于传递板级特定参数。这些属性通常以厂商前缀开头,避免命名冲突。

// 自定义属性示例
gpio-keys {
    compatible = "gpio-keys";
    button@0 {
        label = "power";
        gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
        linux,code = <KEY_POWER>;
        debounce-interval = <50>;  // 自定义属性:去抖时间
        poll-interval = <100>;     // 自定义属性:轮询间隔
    };
};
  • 命名规则: 使用 厂商,属性名 格式(如 fsl,clock-frequency),避免与内核标准属性冲突。
  • 数据类型: 支持 <u32>、<u64>、字符串、prop-encoded-array、phandle 等。
  • 驱动读取: 内核驱动通过 of_property_read_u32()、of_property_read_string() 等 API 获取自定义属性值。

3.4 节点与属性关系:SVG 结构图

下图展示了标准节点、关键属性与自定义属性在设备树中的层级关系:

设备树节点与属性层级结构 / (根节点) chosen memory cpus soc (总线) 关键属性组(每个节点可包含) compatible reg interrupts 自定义属性 uart@ff200000 i2c@ff010000 gpio-keys 节点与属性关系说明 • 每个设备节点必须包含 compatible 属性,用于驱动匹配 • reg 属性定义地址空间,interrupts 属性定义中断连接

3.5 属性使用对比:标准 vs 自定义

对比维度 标准属性(compatible/reg/interrupts) 自定义属性
定义位置 设备树规范(ePAPR) 厂商私有或板级特定
驱动支持 内核通用解析框架 需驱动显式调用 of_property_* API
命名约束 固定名称,不可更改 建议加厂商前缀,避免冲突
覆盖兼容性 覆盖时需严格匹配父节点 覆盖时更灵活,可新增或修改
典型用途 设备识别、地址映射、中断路由 GPIO 极性、时钟频率、去抖时间
核心要点: 标准属性是设备树的“语法规则”,自定义属性是“方言”。在设备树覆盖中,修改标准属性需要谨慎(可能影响驱动匹配),而自定义属性可以自由扩展,是传递板级参数的首选方式。