2. 设备树基础:设备树语法、节点与属性详解

设备树(Device Tree,DT)是嵌入式 Linux 系统中用于描述硬件拓扑结构和资源配置的机制。在 RK3399 平台中,设备树是连接内核驱动与硬件外设的桥梁。本章将系统讲解设备树的语法结构、节点定义、关键属性(reg、interrupts、compatible)以及它们在 RK3399 显示驱动中的应用。

2.1 设备树基本语法与结构

设备树采用树形层次结构,以 .dts(Device Tree Source)文件编写,经过 dtc 编译器生成 .dtb(Device Tree Blob)二进制文件,由 Bootloader 传递给内核解析。其核心语法如下:

  • 节点(Node):以 / 为根节点,每个节点代表一个硬件设备或总线。
  • 属性(Property):键值对形式,描述设备的特性,如地址、中断、兼容性等。
  • 标签(Label):用于引用节点,格式为 label: node-name。
  • 包含文件:使用 #include 引入 .dtsi 公共头文件。
关键点:设备树不是可执行代码,而是静态数据结构。内核通过 of_* 系列 API 在运行时解析设备树,获取硬件资源信息。

2.1.1 设备树层次结构示例

以下是一个简化的 RK3399 设备树片段,展示根节点、CPU 节点、内存节点和 I2C 控制器的层次关系:

/dts-v1/;
#include "rk3399.dtsi"

/ {
    model = "RK3399 Evaluation Board";
    compatible = "rockchip,rk3399";

    chosen {
        stdout-path = &uart2;
    };

    memory@00200000 {
        device_type = "memory";
        reg = <0x0 0x00200000 0x0 0x7fe00000>;
    };

    cpus {
        #address-cells = <2>;
        #size-cells = <0>;

        cpu0: cpu@0 {
            device_type = "cpu";
            compatible = "arm,cortex-a72", "arm,armv8";
            reg = <0x0 0x0>;
            enable-method = "psci";
        };

        cpu1: cpu@1 {
            device_type = "cpu";
            compatible = "arm,cortex-a72", "arm,armv8";
            reg = <0x0 0x1>;
            enable-method = "psci";
        };
    };

    i2c0: i2c@ff3c0000 {
        compatible = "rockchip,rk3399-i2c", "rockchip,rk3288-i2c";
        reg = <0x0 0xff3c0000 0x0 0x1000>;
        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
        clock-names = "i2c", "pclk";
        status = "disabled";
    };
};
提示:RK3399 的 rk3399.dtsi 文件定义了 SoC 内部所有外设的默认节点,板级 .dts 文件通过 &label 引用并覆盖属性(如 status = "okay")来启用外设。

2.2 节点与属性详解

设备树中的每个节点都包含一组标准属性和特定于设备的属性。以下是最核心的三个属性:

属性名 作用 格式 RK3399 示例
compatible 指定设备兼容的驱动名称,用于内核匹配驱动 字符串列表,按优先级从高到低排列 "rockchip,rk3399-i2c", "rockchip,rk3288-i2c"
reg 描述设备在总线上的地址空间(基地址 + 长度) 由 #address-cells 和 #size-cells 决定单元数 <0x0 0xff3c0000 0x0 0x1000>
interrupts 描述设备使用的中断号、触发类型 中断控制器相关,通常包含中断类型、编号、标志 <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>

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

compatible 是设备树中最关键的属性,它告诉内核该设备应该由哪个驱动程序控制。内核的 of_match_table 机制会遍历设备树节点的 compatible 字符串列表,与驱动注册的匹配表进行比对。

  • 格式:"厂商,型号" 或 "厂商,型号", "通用型号"。
  • 匹配优先级:列表中的第一个字符串优先级最高,内核按顺序匹配。
  • RK3399 实践:显示控制器 VOP 的 compatible 为 "rockchip,rk3399-vop-big" 和 "rockchip,rk3399-vop-lit",分别对应大核和小核 VOP。
/* RK3399 VOP 节点 compatible 示例 */
vopb: vop@ff900000 {
    compatible = "rockchip,rk3399-vop-big";
    reg = <0x0 0xff900000 0x0 0x3efc>;
    interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
    /* ... */
};

vopl: vop@ff8f0000 {
    compatible = "rockchip,rk3399-vop-lit";
    reg = <0x0 0xff8f0000 0x0 0x3efc>;
    interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
    /* ... */
};

2.2.2 reg 属性:地址空间描述

reg 属性用于描述设备在总线上的地址范围。其格式由父节点的 #address-cells 和 #size-cells 决定:

  • #address-cells:地址字段占用的 32 位单元数(RK3399 通常为 2,支持 64 位地址)。
  • #size-cells:长度字段占用的 32 位单元数(通常为 2 或 1)。

对于 RK3399 的显示控制器,reg 通常包含三个区域:

  1. 寄存器基地址:控制寄存器映射。
  2. MMU 或 AHB 地址:用于 DMA 或显示缓冲区。
  3. 保留区域:某些 IP 核的额外配置空间。
/* reg 属性解析示例 */
vopb: vop@ff900000 {
    reg = <0x0 0xff900000 0x0 0x3efc>,
          <0x0 0xff904000 0x0 0x1000>;
    reg-names = "vop", "vop-mmu";
};
注意:在 RK3399 中,reg 的地址值必须与 SoC 数据手册中的物理地址一致。如果地址配置错误,驱动访问寄存器时将导致系统崩溃(MMU 未映射或访问非法地址)。

2.2.3 interrupts 属性:中断资源配置

interrupts 属性描述设备使用的中断线。RK3399 使用 GIC(Generic Interrupt Controller)v3,中断类型包括:

中断类型 宏定义 说明
SPI(Shared Peripheral Interrupt) GIC_SPI 共享外设中断,多个 CPU 可接收
PPI(Private Peripheral Interrupt) GIC_PPI 私有外设中断,仅绑定到特定 CPU
触发类型 IRQ_TYPE_LEVEL_HIGH / IRQ_TYPE_EDGE_RISING 电平触发或边沿触发

RK3399 VOP 显示控制器使用 SPI 中断,中断号分别为 118(VOPB)和 119(VOPL),触发类型为高电平有效:

interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;

2.3 设备树关键属性关系图

以下 SVG 图展示了设备树节点、compatible、reg、interrupts 属性与内核驱动、硬件资源之间的映射关系:

设备树关键属性与驱动映射关系 设备树关键属性与驱动映射关系 设备树节点 compatible = "rockchip,rk3399-vop-big" reg = <0xff900000 0x3efc> interrupts = <GIC_SPI 118 ...> 匹配 内核驱动 of_match_table 匹配 platform_get_resource() platform_get_irq() 映射 硬件资源 寄存器物理地址 中断控制器 GIC 时钟 / 复位 / 电源 说明: 设备树通过 compatible 属性匹配驱动,驱动通过 reg 获取寄存器基地址,通过 interrupts 注册中断处理函数,最终实现对硬件资源的控制。

2.4 设备树中的其他重要属性

除了上述三个核心属性,RK3399 显示驱动中常用的属性还包括:

属性 用途 RK3399 显示示例
clocks 指定设备使用的时钟源 clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>;
clock-names 为时钟指定名称,便于驱动获取 clock-names = "aclk", "dclk";
status 控制设备启用或禁用 status = "okay"; 或 "disabled"
pinctrl-* 配置引脚复用功能 pinctrl-0 = <&edp_hpd>;
ports 描述显示输出端口(如 HDMI、DP、MIPI) 包含 endpoint 子节点,连接显示控制器和外部接口

2.4.1 显示端口(ports)属性详解

在 RK3399 显示驱动中,ports 属性用于描述 VOP 与外部显示接口(如 HDMI、DP、MIPI DSI)之间的连接关系。每个 port 代表一个显示输出通道,endpoint 子节点定义具体的连接目标。

/* VOPB 显示端口示例 */
vopb: vop@ff900000 {
    compatible = "rockchip,rk3399-vop-big";
    reg = <0x0 0xff900000 0x0 0x3efc>;
    interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
    clock-names = "aclk", "dclk", "hclk";
    status = "disabled";

    ports {
        #address-cells = <1>;
        #size-cells = <0>;

        port@0 {
            reg = <0>;
            #address-cells = <1>;
            #size-cells = <0>;

            vopb_out_edp: endpoint@0 {
                reg = <0>;
                remote-endpoint = <&edp_in_vopb>;
            };

            vopb_out_hdmi: endpoint@1 {
                reg = <1>;
                remote-endpoint = <&hdmi_in_vopb>;
            };
        };
    };
};
实践要点:在调试 RK3399 显示驱动时,如果某个显示接口无输出,首先检查 ports 中的 remote-endpoint 是否正确连接,以及对应的外部接口节点(如 hdmi、edp)的 status 是否为 "okay"。

2.5 设备树编译与调试

在 RK3399 平台开发中,设备树的编译和调试是日常操作。以下是常用命令和注意事项:

操作 命令 说明
编译 .dts 为 .dtb dtc -I dts -O dtb -o rk3399.dtb rk3399.dts 使用设备树编译器
反编译 .dtb 为 .dts dtc -I dtb -O dts -o rk3399.dts rk3399.dtb 用于查看实际加载的设备树
查看系统当前设备树 ls /proc/device-tree/ 内核导出的设备树文件系统
检查设备树节点状态 cat /proc/device-tree/vopb/status 返回 "okay" 或 "disabled"
常见错误:设备树语法错误(如缺少分号、括号不匹配)会导致编译失败;地址或中断号错误会导致驱动 probe 失败或系统崩溃。建议每次修改后使用 dtc -I dts -O dtb 验证语法正确性。

2.6 本章小结

设备树是 RK3399 平台硬件描述的核心机制。本章重点讲解了:

  • 设备树语法:树形层次结构、节点定义、标签引用。
  • 关键属性:compatible 用于驱动匹配,reg 用于地址映射,interrupts 用于中断注册。
  • 显示驱动相关属性:clocks、ports、status 等。
  • 编译与调试方法:使用 dtc 工具和 /proc/device-tree 文件系统。