4. 设备树基础
在 DRM 驱动移植过程中,设备树是内核与硬件之间的“硬件说明书”。它把 SoC 内部控制器、外部显示桥、面板、背光、电源等连接关系,以可读的树形结构描述出来。驱动通过 of_* 接口读取这些描述,完成资源申请、时钟使能、中断注册和显示链路绑定。理解 DTS/DTSI 语法与显示相关属性,是后续调试链路能否走通的前提。
一、DTS 与 DTSI:源文件组织与编译关系
DTS(Device Tree Source)是具体板级的设备树源文件,DTSI 是被包含的公共描述文件,通常由 SoC 厂商提供,描述 CPU、总线、GPIO、时钟、中断控制器等 SoC 级资源。板级 DTS 通过 #include 引入 DTSI,再对节点进行覆盖或追加,形成最终设备树。编译流程为:DTS/DTSI 经 DTC 编译为 DTB,由 Bootloader 传给内核并展开为 /proc/device-tree 或 /sys/firmware/devicetree。
// 典型板级 DTS 结构
#include "soc.dtsi"
#include "display-panel.dtsi"
/ {
model = "Demo Board V1";
compatible = "vendor,demo-board", "vendor,soc";
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm0 0 20000 0>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
};
};
DTSI 中常使用 /delete-node/、/delete-property/ 或标签覆盖来修改默认配置。板级文件应尽量只描述“与参考设计不同”的部分,避免整段复制,否则后续 SoC DTSI 升级会带来大量冲突。
二、节点与属性:设备树的基本语法单元
节点用 node-name@unit-address 表示,unit-address 通常取寄存器基地址,用于区分同一节点名下的多个实例。属性是键值对,值可以是字符串、u32 数组、字节序列或 phandle。常见标准属性包括:
compatible:驱动匹配的关键,格式为 "厂商,型号",可多个按优先级排列。reg:寄存器地址与长度,格式为 <地址 长度>,地址和长度单元格数由父节点#address-cells、#size-cells决定。status:"okay"或"disabled",用于使能/关闭节点。interrupts、interrupt-parent:中断号与中断控制器引用。clocks、clock-names:时钟引用与名称对应关系。power-domains、resets:电源域与复位资源。
三、phandle 引用:把分散的硬件连成链路
phandle 是设备树中节点的唯一数字标识。给节点加标签(label)后,其他节点可用 &label 引用它,DTC 编译时自动生成 phandle。显示链路中,CRTC、编码器、桥、面板、背光之间正是通过 phandle 建立连接。
panel: panel@0 {
compatible = "vendor,panel-1080p";
reg = <0>;
backlight = <&backlight>;
power-supply = <&vcc_lcd>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
&dsi {
status = "okay";
port {
dsi_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
驱动侧通过 of_parse_phandle()、of_find_node_by_phandle() 或 of_graph_get_remote_endpoint() 解析引用,从而拿到对端设备节点。若 phandle 指向的节点 status = "disabled",链路绑定会失败,这是显示不亮的常见原因之一。
四、地址与中断描述:reg、ranges 与 interrupts
地址描述依赖父节点的 #address-cells 和 #size-cells。例如 32 位地址、32 位长度时,reg = <0xfe0e0000 0x1000> 表示从 0xfe0e0000 起 4KB 寄存器空间。若存在地址转换,还需 ranges 描述子总线到父总线的映射。中断描述则通过 interrupt-parent 指定中断控制器,interrupts 给出中断号和触发类型,如 <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>。
| 属性 | 作用 | 显示场景示例 |
|---|---|---|
| reg | 寄存器基址与长度 | DSI 控制器 0xfe0e0000,长度 0x1000 |
| interrupts | 中断号与触发方式 | VBlank 中断、DSI 错误中断 |
| clocks / clock-names | 时钟引用与命名 | "pclk"、"hsclk"、"dsi_phy" |
| phys | PHY 引用 | MIPI D-PHY / C-PHY |
| ports / endpoint | 显示链路连接 | CRTC → DSI → Panel |
五、显示相关常用属性与链路绑定
DRM 显示子系统普遍使用 OF graph 描述链路:每个设备节点下用 port 和 endpoint 表示输入/输出端口,remote-endpoint 指向对端 endpoint。驱动通过 drm_of_find_panel_or_bridge() 找到面板或桥,再注册到 DRM 框架。常见显示属性还包括:
data-lanes:MIPI DSI 通道数,如<1 2 3 4>。lane-polarities:差分对极性翻转。panel-timing或display-timings:像素时钟、H/V 前后沿、同步脉宽。backlight:背光 phandle,供 panel 驱动调节亮度。enable-gpios、reset-gpios:面板使能与复位引脚。
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hfront-porch = <88>;
hback-porch = <148>;
hsync-len = <44>;
vfront-porch = <4>;
vback-porch = <36>;
vsync-len = <5>;
};
};
六、误区与复盘:设备树调试的常见坑
第一,compatible 拼写错误或与驱动 of_match_table 不一致,导致驱动根本不 probe。第二,reg 地址与 SoC 手册不符,或 #address-cells 配置错误,导致地址解析偏移。第三,phandle 引用指向 disabled 节点,链路绑定失败。第四,status 未从 disabled 改为 okay,节点被内核忽略。第五,endpoint 的 remote-endpoint 未成对出现,OF graph 无法闭环。排查时可用 ls /proc/device-tree、cat /sys/kernel/debug/device_component 或 dmesg | grep -i drm 观察绑定结果。
掌握以上语法与属性后,设备树就不再是“看不懂的文本”,而是可以按图索骥的硬件连接图。后续调试显示链路时,先看设备树节点是否完整、phandle 是否闭环、时序是否匹配,再结合驱动日志定位问题,效率会显著提升。