设备树基础:语法、节点/属性/标签与标准属性
设备树(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" |
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> |
#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 |
clk_summary 或 debugfs 检查时钟是否使能、频率是否达标,是信号调试的第一步。
4. 设备树层级与 CSI 时钟拓扑
下图展示了骁龙平台中 CSI 时钟相关的设备树层级关系,从时钟控制器到 CSI 接收器再到传感器子节点:
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,需根据分区表确认烧录位置。