4. 设备树配置基础:设备树语法回顾、RK3588显示设备树节点、LVDS panel节点定义
设备树(Device Tree)是嵌入式Linux系统中描述硬件拓扑结构的核心机制。在RK3588平台上进行LVDS显示驱动移植,首先需要理解设备树的语法规则、RK3588显示相关的设备树节点结构,以及如何正确定义LVDS panel节点。本章将系统梳理这些基础知识,为后续的驱动移植打下坚实基础。
4.1 设备树语法回顾
设备树使用一种树形结构来描述硬件设备,其基本语法包括节点(node)、属性(property)和值(value)。每个节点代表一个硬件设备或总线,属性则描述设备的配置参数。
4.1.1 基本语法规则
- 节点定义:使用
node-name@unit-address格式,其中unit-address通常为设备基地址。 - 属性赋值:属性名后跟
=和值,值可以是字符串、整数、字节数组等。 - 标签(label):用于引用节点,格式为
label: node-name@address。 - 包含文件:使用
#include指令引入头文件或dtsi文件。
// 设备树基本语法示例
/dts-v1/;
#include "rk3588.dtsi"
/ {
model = "RK3588 EVB1 LP4X Board";
compatible = "rockchip,rk3588-evb1-lp4x", "rockchip,rk3588";
chosen {
stdout-path = &uart2;
};
lvds_panel: lvds-panel {
compatible = "boe,tv080wum-nl0";
// ... 属性定义
};
};
4.1.2 常用属性类型
| 属性类型 | 语法格式 | 示例 | 说明 |
|---|---|---|---|
| 字符串 | "string" |
compatible = "boe,tv080wum-nl0"; |
用于标识设备兼容性 |
| 32位整数 | <value> |
reg = <0x0 0x100>; |
地址、大小、配置值 |
| 64位整数 | <high low> |
reg = <0x0 0x0 0x0 0x100000>; |
64位地址空间 |
| 字节数组 | [byte1 byte2 ...] |
mac-address = [00 11 22 33 44 55]; |
MAC地址、UUID等 |
| 布尔值 | 仅属性名 | status = "okay"; |
存在即为true |
| 引用 | &label |
pinctrl-0 = &lvds_pins; |
引用其他节点 |
compatible 属性是驱动匹配的核心,驱动通过该属性值与设备树节点建立绑定关系。在LVDS panel定义中,compatible 必须与驱动中 of_device_id 表完全一致。
4.1.3 设备树层级结构
设备树的层级结构反映了硬件的总线拓扑。根节点 / 下包含CPU、内存、总线控制器等,显示相关节点通常挂在 display-subsystem 或 vop 节点下。
4.2 RK3588显示设备树节点
RK3588的显示子系统在设备树中由多个节点协同描述,主要包括 display-subsystem、vop(Video Output Processor)、hdmi-tx、dp、dsi 和 lvds 等节点。LVDS显示驱动主要涉及 vop 和 lvds 相关节点。
4.2.1 display-subsystem 节点
display-subsystem 是显示子系统的顶层节点,负责协调各个显示输出接口。它通常包含 ports 子节点,用于描述显示链路的连接关系。
display_subsystem: display-subsystem {
compatible = "rockchip,display-subsystem";
ports = <&vop_out>;
status = "disabled";
route {
// 路由配置,指定输出接口与显示控制器的绑定关系
route_lvds: route-lvds {
status = "disabled";
connect = <&vop_out_lvds>;
};
};
};
4.2.2 VOP(Video Output Processor)节点
VOP是RK3588的显示控制器,负责从内存中读取帧缓冲数据,进行格式转换、缩放等处理,最终输出到显示接口。RK3588通常包含多个VOP实例(如vop0、vop1),每个VOP支持不同的输出接口。
vop: vop@fdd90000 {
compatible = "rockchip,rk3588-vop";
reg = <0x0 0xfdd90000 0x0 0x200>, <0x0 0xfdd90200 0x0 0x200>;
reg-names = "vop", "gamma-lut";
interrupts = ;
clocks = <&cru ACLK_VOP0>, <&cru HCLK_VOP0>;
clock-names = "aclk_vop", "hclk_vop";
status = "disabled";
vop_out: ports {
#address-cells = <1>;
#size-cells = <0>;
vop_out_lvds: endpoint@0 {
reg = <0>;
remote-endpoint = <&lvds_in_vop>;
};
vop_out_hdmi: endpoint@1 {
reg = <1>;
remote-endpoint = <&hdmi_in_vop>;
};
};
};
4.2.3 LVDS控制器节点
RK3588的LVDS控制器节点负责配置LVDS接口的时序参数、数据映射模式等。该节点通常包含 ports 子节点,用于与VOP和panel建立连接。
lvds: lvds@fdfc0000 {
compatible = "rockchip,rk3588-lvds";
reg = <0x0 0xfdfc0000 0x0 0x1000>;
clocks = <&cru PCLK_LVDS>;
clock-names = "pclk_lvds";
power-domains = <&power RK3588_PD_VOP>;
rockchip,grf = <&grf>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
lvds_in: port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
lvds_in_vop: endpoint@0 {
reg = <0>;
remote-endpoint = <&vop_out_lvds>;
};
};
lvds_out: port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
lvds_out_panel: endpoint@0 {
reg = <0>;
remote-endpoint = <&panel_in_lvds>;
};
};
};
};
remote-endpoint 的配对关系。必须确保VOP输出端口的 remote-endpoint 指向LVDS控制器的输入端口,同时LVDS控制器的输出端口指向panel的输入端口。任何一端缺失都会导致显示链路中断。
4.3 LVDS panel节点定义
LVDS panel节点是设备树中描述液晶屏参数的核心节点。它定义了屏的物理规格、时序参数、初始化序列等关键信息。正确配置panel节点是LVDS显示驱动移植成功的关键。
4.3.1 panel节点基本结构
lvds_panel: lvds-panel {
compatible = "boe,tv080wum-nl0";
status = "okay";
enable-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&lvds_panel_pins>;
// 电源供应
power-supply = <&vcc3v3_lcd>;
backlight = <&backlight>;
// 显示时序
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <70000000>; // 像素时钟 70MHz
hactive = <1024>; // 水平有效像素
vactive = <600>; // 垂直有效像素
hfront-porch = <160>; // 水平前肩
hback-porch = <140>; // 水平后肩
hsync-len = <20>; // 水平同步宽度
vfront-porch = <12>; // 垂直前肩
vback-porch = <10>; // 垂直后肩
vsync-len = <3>; // 垂直同步宽度
hsync-active = <0>; // 水平同步极性(0低有效)
vsync-active = <0>; // 垂直同步极性(0低有效)
de-active = <0>; // 数据使能极性
pixelclk-active = <0>; // 像素时钟极性
};
};
// LVDS数据映射
rockchip,data-mapping = "jeida"; // 数据映射格式:jeida 或 vesa
rockchip,data-width = <24>; // 数据位宽:18或24
rockchip,output-type = "lvds"; // 输出类型
// 端口连接
port {
panel_in_lvds: endpoint {
remote-endpoint = <&lvds_out_panel>;
};
};
};
4.3.2 关键属性详解
| 属性名 | 类型 | 说明 | 典型值 |
|---|---|---|---|
compatible |
字符串 | 驱动匹配标识,必须与驱动一致 | "boe,tv080wum-nl0" |
enable-gpios |
GPIO引用 | 屏使能引脚,用于控制屏电源 | <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH> |
reset-gpios |
GPIO引用 | 屏复位引脚,用于初始化屏 | <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH> |
power-supply |
phandle | 屏电源供应节点引用 | <&vcc3v3_lcd> |
backlight |
phandle | 背光控制器节点引用 | <&backlight> |
clock-frequency |
整数 | 像素时钟频率,单位Hz | <70000000> |
hactive / vactive |
整数 | 水平和垂直分辨率 | <1024> / <600> |
hsync-len / vsync-len |
整数 | 同步信号脉冲宽度 | <20> / <3> |
hfront-porch / hback-porch |
整数 | 水平消隐前肩/后肩 | <160> / <140> |
vfront-porch / vback-porch |
整数 | 垂直消隐前肩/后肩 | <12> / <10> |
hsync-active / vsync-active |
布尔 | 同步信号极性(0低有效,1高有效) | <0> / <0> |
rockchip,data-mapping |
字符串 | LVDS数据映射格式 | "jeida" 或 "vesa" |
rockchip,data-width |
整数 | LVDS数据位宽 | <18> 或 <24> |
4.3.3 时序参数计算
显示时序参数直接影响屏的刷新率和显示稳定性。总像素时钟频率可通过以下公式计算:
总水平像素 = hactive + hfront-porch + hback-porch + hsync-len
总垂直像素 = vactive + vfront-porch + vback-porch + vsync-len
刷新率 = clock-frequency / (总水平像素 × 总垂直像素)
示例(1024×600 @ 60Hz):
总水平像素 = 1024 + 160 + 140 + 20 = 1344
总垂直像素 = 600 + 12 + 10 + 3 = 625
刷新率 = 70,000,000 / (1344 × 625) ≈ 83.3 Hz
clock-frequency 或消隐参数。过高的刷新率可能导致屏显示异常或功耗增加。
4.3.4 LVDS数据映射格式
LVDS接口支持两种数据映射格式:JEIDA 和 VESA。两种格式在数据通道上的RGB位排列不同,必须根据屏规格书正确选择。
| 数据通道 | JEIDA格式(24位) | VESA格式(24位) |
|---|---|---|
| 通道0 | R0-R5, G0 | R0-R5, G0 |
| 通道1 | G1-G5, B0-B1 | G1-G5, B0-B1 |
| 通道2 | B2-B5, Hsync, Vsync, DE | B2-B5, Hsync, Vsync, DE |
| 通道3 | R6-R7, G6-G7, B6-B7 | R6-R7, G6-G7, B6-B7 |
对于18位LVDS,数据映射格式差异主要体现在低位数据的处理上。JEIDA格式将RGB低位数据分散到各通道,而VESA格式则集中放置。配置错误会导致颜色显示异常。
4.4 设备树编译与验证
完成设备树配置后,需要编译并验证其正确性。RK3588平台使用DTC(Device Tree Compiler)工具进行编译。
4.4.1 编译命令
# 编译设备树源文件为dtb
dtc -I dts -O dtb -o rk3588-evb1-lp4x.dtb rk3588-evb1-lp4x.dts
# 反编译dtb为dts,用于验证
dtc -I dtb -O dts -o rk3588-evb1-lp4x-decompiled.dts rk3588-evb1-lp4x.dtb
# 检查设备树语法错误
dtc -I dts -O dtb -o /dev/null rk3588-evb1-lp4x.dts 2>&1
4.4.2 常见错误排查
| 错误类型 | 错误信息示例 | 解决方法 |
|---|---|---|
| 语法错误 | ERROR: syntax error |
检查括号、分号、引号是否匹配 |
| 属性重复 | WARNING: duplicate property |
删除重复的属性定义 |
| 引用错误 | ERROR: Reference to non-existent node |
检查 &label 是否正确定义 |
| 类型不匹配 | ERROR: Expected integer |
检查属性值类型是否正确 |
| 地址格式错误 | ERROR: Bad cell format |
检查 reg 属性的地址单元数量 |
/proc/device-tree 目录查看实际生效的设备树内容。使用 ls -lR /proc/device-tree/ 可以遍历所有节点和属性,确认LVDS panel节点是否正确加载。