设备树基础:语法、节点/属性/标签与标准属性

设备树(Device Tree,DT)是描述硬件拓扑与资源配置的静态数据结构,在骁龙平台相机驱动中,MIPI CSI 物理层(PHY)、时钟控制器(GCC/CAMCC)、电源管理芯片(PMIC)以及传感器本身均通过设备树节点进行描述。本节将系统讲解设备树的语法结构、节点/属性/标签的编写规则,以及 compatible、reg、interrupts、clocks 四个标准属性的含义与用法,为后续 CSI 信号调试中的时钟配置与 DTS 修改打下基础。

1. 设备树语法基础

设备树源文件(.dts)采用树形层级结构,每个硬件设备对应一个节点(node),节点内包含若干属性(property)用于描述设备特征。基本语法规则如下:

  • 节点定义:node-name@unit-address,其中 unit-address 通常为寄存器基地址。
  • 属性赋值:property-name = <value> 或 property-name = "string"。
  • 标签(label):在节点前添加 label:,便于在其它位置引用。
  • 包含文件:使用 #include 导入 .dtsi 头文件,实现 SoC 级与板级设备树分离。
  • 注释:C 风格 /* */ 与 C++ 风格 // 均支持。
关键点:设备树不是可执行代码,而是静态描述;驱动通过 of_ 系列 API 在运行时解析设备树,获取硬件资源信息。

1.1 节点与属性示例

/* 骁龙 SM8250 平台 MIPI CSI 接收控制器节点示例 */
csi_receiver: csi@acb40000 {
    compatible = "qcom,sm8250-csi", "qcom,csi-v2";
    reg = <0x0 0xacb40000 0x0 0x1000>;
    interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&camcc CAM_CC_CSI0_CLK>,
             <&camcc CAM_CC_CSI0_AHB_CLK>;
    clock-names = "csi", "ahb";

    /* 子节点:CSI 通道配置 */
    port {
        csi0_ep: endpoint {
            remote-endpoint = <&sensor_ep>;
            data-lanes = <1 2 3 4>;
            link-frequencies = /bits/ 64 <480000000>;
        };
    };
};

上述代码展示了节点 csi@acb40000 的完整结构:标签 csi_receiver、标准属性 compatible/reg/interrupts/clocks,以及子节点 port 与 endpoint 用于描述 CSI 数据链路拓扑。

2. 节点、属性与标签详解

元素 语法形式 作用与说明 CSI 调试场景示例
节点 node-name@addr { }; 表示一个硬件设备或总线,可嵌套子节点 csi@acb40000 描述 CSI 接收器
属性 name = value; 描述设备特性,值可为整数、字符串、数组、phandle data-lanes = <1 2>; 指定 CSI 数据通道
标签 label: node-name@addr 为节点起别名,便于跨文件引用 csi_receiver: 供 &csi_receiver 引用
phandle &label 引用已定义节点的句柄 &camcc 引用时钟控制器节点
包含 #include "file.dtsi" 导入 SoC 级或板级通用定义 #include "sm8250-cam.dtsi"
调试提示:在 CSI 信号调试中,经常需要修改 data-lanes 属性来适配不同传感器(如从 4-lane 改为 2-lane),或通过 &csi_receiver 标签在板级 DTS 中覆盖 SoC 级默认配置。

3. 标准属性详解

设备树规范定义了若干标准属性,驱动依赖这些属性获取硬件资源。以下四个属性在骁龙 MIPI CSI 调试中最为关键:

3.1 compatible —— 设备驱动匹配

compatible 属性是一个字符串列表,用于操作系统将设备节点与驱动绑定。匹配顺序从左到右,越靠前的字符串优先级越高。

compatible = "qcom,sm8250-csi", "qcom,csi-v2";
  • 格式:"厂商,型号",推荐使用倒置域名风格。
  • 匹配机制:驱动中的 of_match_table 与设备树的 compatible 进行字符串精确匹配。
  • CSI 调试场景:当更换不同型号的 CSI 桥接芯片或 ISP 时,需同步修改 compatible 以加载正确的驱动。

3.2 reg —— 地址与内存映射

reg 属性描述设备占用的寄存器地址空间,格式为 <地址 长度> 对,支持多个地址段。

reg = <0x0 0xacb40000 0x0 0x1000>;
/* 解释:64位地址 0xacb40000,长度 0x1000(4KB) */
参数 含义 CSI 调试中的典型值
address-cells 父节点中地址字段的 32 位字数量 2(64位地址空间)
size-cells 父节点中长度字段的 32 位字数量 2
reg 实际地址与长度对 <0 0xacb40000 0 0x1000>
常见错误:地址或长度字段的 cells 数量与父节点 #address-cells/#size-cells 不匹配,导致驱动 ioremap 失败。在骁龙平台中,soc 节点通常使用 #address-cells = <2>,#size-cells = <2>。

3.3 interrupts —— 中断资源配置

interrupts 属性描述设备使用的中断号、触发类型等信息,依赖父节点 interrupt-parent 指定中断控制器。

interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
/* GIC_SPI: 共享外设中断类型,256: 中断号,LEVEL_HIGH: 高电平触发 */
  • 中断类型:GIC_SPI(共享外设中断)、GIC_PPI(私有外设中断)。
  • 触发方式:IRQ_TYPE_LEVEL_HIGH(高电平)、IRQ_TYPE_EDGE_RISING(上升沿)等。
  • CSI 调试场景:CSI 控制器中断用于帧同步、错误检测;中断号错误会导致无法捕获图像或无法检测 MIPI 协议错误。

3.4 clocks —— 时钟输入与频率控制

clocks 属性列出设备所需的所有时钟源,配合 clock-names 属性按名称索引。时钟由时钟控制器节点(如 camcc)提供。

clocks = <&camcc CAM_CC_CSI0_CLK>,
         <&camcc CAM_CC_CSI0_AHB_CLK>;
clock-names = "csi", "ahb";
时钟名称 时钟 ID(宏定义) 作用 典型频率
csi CAM_CC_CSI0_CLK CSI 核心时钟,驱动 MIPI D-PHY 逻辑 200~600 MHz
ahb CAM_CC_CSI0_AHB_CLK AHB 总线接口时钟,用于寄存器访问 100~200 MHz
csiphy CAM_CC_CSIPHY0_CLK CSI PHY 参考时钟,影响 MIPI 数据速率 19.2 MHz / 26 MHz
调试要点:时钟频率配置错误是 MIPI CSI 信号异常的常见原因。使用 clk_summary 或 debugfs 检查时钟是否使能、频率是否达标,是信号调试的第一步。

4. 设备树层级与 CSI 时钟拓扑

下图展示了骁龙平台中 CSI 时钟相关的设备树层级关系,从时钟控制器到 CSI 接收器再到传感器子节点:

骁龙平台 CSI 时钟设备树层级拓扑 / (根节点) soc@0 camcc@ad00000 时钟控制器 csi@acb40000 CSI 接收器 sensor@10 图像传感器 (I2C) clocks MIPI CSI 时钟配置关键路径 camcc 通过 clocks 属性向 csi 提供核心时钟与 AHB 时钟 csi 节点通过 clock-names 区分不同时钟用途 csi@acb40000 节点关键属性 compatible = "qcom,sm8250-csi", "qcom,csi-v2"; reg = <0 0xacb40000 0 0x1000>; interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>; clocks = <&camcc CAM_CC_CSI0_CLK>, <&camcc CAM_CC_CSI0_AHB_CLK>;

5. 设备树覆盖与 CSI 调试实践

在骁龙平台相机驱动调试中,通常不直接修改 SoC 级 .dtsi 文件,而是在板级 .dts 中使用 &label 语法进行覆盖(overlay)。以下是一个典型的 CSI 时钟配置覆盖示例:

/* 板级 DTS:覆盖 CSI 接收器时钟与通道配置 */
&csi_receiver {
    /* 修改时钟频率:使用更高频率的 CSI 核心时钟 */
    clocks = <&camcc CAM_CC_CSI0_CLK>,
             <&camcc CAM_CC_CSI0_AHB_CLK>,
             <&camcc CAM_CC_CSIPHY0_CLK>;
    clock-names = "csi", "ahb", "csiphy";

    /* 覆盖端口子节点:配置 2-lane 模式 */
    port {
        csi0_ep: endpoint {
            remote-endpoint = <&sensor_ep>;
            data-lanes = <1 2>;  /* 从 4-lane 改为 2-lane */
            link-frequencies = /bits/ 64 <480000000>;
        };
    };
};

/* 添加传感器节点 */
&i2c5 {
    sensor@10 {
        compatible = "sony,imx586";
        reg = <0x10>;
        clocks = <&camcc CAM_CC_MCLK0_CLK>;
        clock-names = "xvclk";
        /* 其他属性... */
    };
};
调试技巧:使用 dtc -I dtb -O dts 反编译已加载的设备树二进制(/sys/firmware/devicetree/base),验证覆盖是否生效。重点关注 clocks 属性中的 phandle 是否指向正确的时钟控制器。

6. 常见设备树错误与排查方法

错误类型 现象 根因 排查方法
compatible 不匹配 驱动 probe 失败,dmesg 显示 "No driver found" 设备树与驱动字符串不一致 检查 of_match_table 与设备树 compatible
reg 地址错误 ioremap 返回 NULL,寄存器读写异常 地址或长度 cells 数量错误 核对父节点 #address-cells/#size-cells
interrupts 配置错误 中断无法触发,或触发类型错误 中断号或触发标志错误 查看 /proc/interrupts 确认中断号
clocks phandle 无效 时钟获取失败,clk_prepare_enable 返回 -EINVAL 引用的时钟控制器节点不存在或时钟 ID 错误 使用 clk_summary 检查时钟树
语法错误 dtc 编译报错,无法生成 .dtb 缺少分号、括号不匹配、属性值格式错误 使用 dtc -I dts -O dtb -o /dev/null 检查语法
重要提醒:在修改设备树后,务必重新编译并烧录 dtb 或 dtbo(设备树覆盖)。在骁龙平台中,boot.img 包含 dtb,而 vendor_boot.img 可能包含 dtbo,需根据分区表确认烧录位置。

7. 本节小结