4. 设备树绑定规范:标准属性与自定义属性

设备树绑定规范是连接硬件描述与驱动代码的契约。内核通过绑定规范解析设备树节点中的标准属性(compatible、reg、interrupts)和自定义属性,完成设备识别、资源分配与驱动匹配。本章深入剖析这三类属性的语法规则、内核解析机制及厂商前缀管理方法。

核心观点:绑定规范的本质是“硬件描述语言”的语法定义。标准属性保证跨平台兼容性,自定义属性提供硬件特定扩展,厂商前缀避免命名冲突。

4.1 标准属性:compatible / reg / interrupts

标准属性是设备树规范中强制或推荐使用的属性,内核在启动阶段直接解析它们完成设备枚举与资源映射。

4.1.1 compatible 属性:驱动匹配的钥匙

compatible 属性是一个字符串列表,用于标识设备的具体型号和兼容性。内核通过它查找匹配的驱动。

  • 格式:"厂商前缀,设备型号",可包含多个字符串,按优先级从高到低排列。
  • 匹配规则:驱动中的 of_match_table 与设备树中的 compatible 字符串进行精确匹配。
  • 最佳实践:第一个字符串必须是精确的“厂商,型号”,后续字符串可以是更通用的兼容型号。
// 设备树节点示例
uart0: serial@10000000 {
    compatible = "fsl,imx6q-uart", "fsl,imx21-uart";
    reg = <0x10000000 0x4000>;
    interrupts = <0 58 4>;
};

// 驱动匹配表
static const struct of_device_id imx_uart_dt_ids[] = {
    { .compatible = "fsl,imx6q-uart", .data = &imx6q_data },
    { .compatible = "fsl,imx21-uart", .data = &imx21_data },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
匹配优先级:内核遍历 of_match_table 时,按设备树中 compatible 字符串的顺序依次匹配。第一个匹配成功的驱动将被绑定。

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

reg 属性描述设备在总线上的地址空间,由一组“地址+大小”对组成。内核通过它完成内存映射和资源分配。

属性字段 含义 示例值
#address-cells 地址字段占用的 32 位单元数 1(32位地址)或 2(64位地址)
#size-cells 大小字段占用的 32 位单元数 1(32位大小)或 0(无大小)
reg 地址与大小交替排列的数组 <0x10000000 0x4000>
// 64位地址空间示例
memory@80000000 {
    device_type = "memory";
    reg = <0x00000000 0x80000000 0x00000000 0x80000000>;
    // 地址:0x00000000_80000000,大小:0x00000000_80000000(2GB)
};

// 多段地址空间示例
dma-controller@1e000000 {
    compatible = "snps,dma-spear1340";
    reg = <0x1e000000 0x1000>,
          <0x1e001000 0x1000>;
    // 两段连续的寄存器空间
};

4.1.3 interrupts 属性:中断描述

interrupts 属性描述设备的中断请求线,需要与 interrupt-parent 配合使用。中断描述符的格式由中断控制器定义。

  • 标准格式:<中断类型 中断号 触发方式>
  • 中断类型:0(SPI,共享外设中断)、1(PPI,私有外设中断)
  • 触发方式:1(上升沿触发)、2(下降沿触发)、4(高电平触发)、8(低电平触发)
// GIC 中断控制器示例
gic: interrupt-controller@2c001000 {
    compatible = "arm,cortex-a9-gic";
    #interrupt-cells = <3>;
    interrupt-controller;
    reg = <0x2c001000 0x1000>,
          <0x2c002000 0x1000>;
};

// 使用中断的设备节点
ethernet@18000000 {
    compatible = "smsc,lan9115";
    reg = <0x18000000 0x100>;
    interrupts = <0 42 4>;
    interrupt-parent = <&gic>;
};
常见错误:忘记设置 interrupt-parent 或 #interrupt-cells 不匹配,会导致中断无法正确路由。务必检查中断控制器的 #interrupt-cells 值。

4.2 自定义属性:硬件特定扩展

自定义属性允许 SoC 厂商描述标准属性无法覆盖的硬件特性。内核通过 of_property_read_* 系列 API 读取这些属性。

4.2.1 自定义属性定义规则

  • 命名规范:使用厂商前缀作为命名空间,如 fsl,uart-has-rtscts。
  • 数据类型:支持 u32、u64、string、boolean、phandle 等。
  • 文档要求:必须在绑定文档中明确定义,否则视为未公开接口。
// 自定义属性示例
spi@10014000 {
    compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi";
    reg = <0x10014000 0x4000>;
    interrupts = <0 46 4>;
    fsl,spi-num-chipselects = <4>;          // 自定义:片选数量
    fsl,spi-32bit-mode;                      // 自定义:布尔属性,启用32位模式
    cs-gpios = <&gpio1 0 0>,
               <&gpio1 1 0>,
               <&gpio1 2 0>,
               <&gpio1 3 0>;               // 自定义:片选GPIO列表
};

4.2.2 内核读取自定义属性 API

API 函数 功能 返回值
of_property_read_u32 读取 32 位整数属性 0 成功,负值错误
of_property_read_string 读取字符串属性 0 成功,负值错误
of_property_read_bool 检查布尔属性是否存在 true/false
of_get_named_gpio 读取 GPIO 属性 GPIO 编号或负值错误
// 驱动中读取自定义属性示例
static int imx_ecspi_probe(struct platform_device *pdev)
{
    struct device_node *np = pdev->dev.of_node;
    u32 num_cs;
    bool mode_32bit;
    int ret;

    // 读取 u32 属性
    ret = of_property_read_u32(np, "fsl,spi-num-chipselects", &num_cs);
    if (ret) {
        dev_err(&pdev->dev, "missing fsl,spi-num-chipselects\n");
        return ret;
    }

    // 读取布尔属性
    mode_32bit = of_property_read_bool(np, "fsl,spi-32bit-mode");

    // 读取 GPIO 属性
    for (int i = 0; i < num_cs; i++) {
        int gpio = of_get_named_gpio(np, "cs-gpios", i);
        if (gpio < 0) {
            dev_err(&pdev->dev, "invalid cs-gpios at index %d\n", i);
            return gpio;
        }
    }

    return 0;
}
设计原则:自定义属性应遵循“最小必要”原则。能用标准属性表达的硬件特性,绝不使用自定义属性。自定义属性必须附带完整的绑定文档。

4.3 厂商前缀管理

厂商前缀是设备树命名空间的核心机制,确保不同厂商的同名设备不会冲突。Linux 内核维护一个官方前缀列表。

4.3.1 前缀注册与查询

所有厂商前缀必须在 Documentation/devicetree/bindings/vendor-prefixes.yaml 中注册。内核社区通过补丁审核机制管理前缀的添加。

前缀 厂商全称 应用场景
fsl Freescale Semiconductor / NXP i.MX 系列 SoC
brcm Broadcom Corporation BCM 系列网络芯片
ti Texas Instruments OMAP / AM 系列处理器
allwinner Allwinner Technology Sunxi 系列 SoC
rockchip Rockchip Electronics RK 系列 SoC

4.3.2 前缀使用规范

  • 唯一性:每个厂商只能注册一个前缀,避免使用缩写歧义。
  • 稳定性:已注册的前缀不得更改,废弃前缀需标记为 deprecated。
  • 兼容性:新设备必须使用已注册的前缀,未注册前缀的补丁将被拒绝。
# vendor-prefixes.yaml 示例片段
%YAML 1.2
---
$id: http://devicetree.org/schemas/vendor-prefixes.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

maintainers:
  - Devicetree Specification Mailing List <devicetree-spec@vger.kernel.org>

properties:
  fsl:
    description: Freescale Semiconductor Inc. (now NXP Semiconductors)
    type: string
    pattern: "^fsl,.*$"

  brcm:
    description: Broadcom Corporation
    type: string
    pattern: "^brcm,.*$"
合规检查:提交设备树补丁前,务必使用 scripts/checkpatch.pl 检查厂商前缀是否已注册。未注册前缀会导致补丁被自动拒绝。

4.4 绑定规范综合架构

下图展示了设备树绑定规范在驱动架构中的完整作用链路:从设备树源文件到驱动匹配、资源获取、硬件初始化。

设备树绑定规范架构图 设备树绑定规范架构图 设备树源文件 (.dts / .dtsi) 设备树节点 compatible + reg + interrupts + 自定义属性 内核解析层 of_match_table → 驱动匹配 of_iomap / of_irq_map / of_property_read_* → 资源获取 驱动初始化 probe() → 寄存器映射 → 中断注册 → 自定义配置 硬件操作层 绑定规范关键点 • compatible:驱动匹配 • reg:地址空间映射 • interrupts:中断路由 • 自定义属性:硬件扩展 • 厂商前缀:命名空间 输入输出 输入:.dts 源文件 输出:.dtb 二进制 运行时:设备节点

4.5 绑定规范最佳实践

清单检查:每次编写设备树节点时,对照以下清单确保绑定规范合规:
  1. compatible 字符串是否包含已注册的厂商前缀?
  2. reg 属性的 #address-cells 和 #size-cells 是否与父节点一致?
  3. interrupts 属性的格式是否与中断控制器的 #interrupt-cells 匹配?
  4. 自定义属性是否在绑定文档中定义?
  5. 厂商前缀是否在 vendor-prefixes.yaml 中注册?

4.5.1 绑定文档编写规范

每个设备树绑定必须包含 YAML 格式的文档,描述所有属性的类型、约束和默认值。内核社区已全面迁移到 YAML 绑定格式。

# Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml
%YAML 1.2
---
$id: http://devicetree.org/schemas/serial/fsl-imx-uart.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Freescale i.MX UART

maintainers:
  - Shawn Guo <shawnguo@kernel.org>

properties:
  compatible:
    items:
      - enum:
          - fsl,imx6q-uart
          - fsl,imx21-uart
      - const: fsl,imx21-uart

  reg:
    maxItems: 1

  interrupts:
    maxItems: 1

  fsl,uart-has-rtscts:
    description: Indicates that the UART has RTS/CTS hardware flow control
    type: boolean

required:
  - compatible
  - reg
  - interrupts

additionalProperties: false

4.5.2 常见绑定错误与修复

错误类型 错误示例 正确做法
前缀未注册 mycompany,uart 使用已注册前缀,如 fsl,uart
compatible 顺序错误 "fsl,imx21-uart", "fsl,imx6q-uart" 精确型号在前,通用型号在后
reg 地址单元不匹配 父节点 #address-cells = <2>,子节点只写一个地址 确保地址单元数与父节点一致
中断描述符格式错误 interrupts = <42 4>(缺少中断类型) 根据 #interrupt-cells 填写完整
总结:设备树绑定规范是驱动架构设计的基石。标准属性保证跨平台兼容性,自定义属性提供硬件特定扩展,厂商前缀确保命名空间隔离。掌握这三类属性的语法和内核解析机制,是编写高质量设备树和驱动代码的前提。