显示 DRM 驱动
本文档介绍 RK3588 VOP2 显示控制器在 Linux 6.1 内核中的 DRM/KMS 子系统、设备树配置和用户态调试。
适用范围: RK3588 Linux 6.1 Debian 12 / Ubuntu 22.04 系统,C-3588LQ V1.0 + SHIMETAPI-M5-R2A V1.0 底板。
1. 概念基础
1.1 DRM/KMS 是什么
DRM(Direct Rendering Manager)+ KMS(Kernel Mode Setting)是 Linux 内核的现代显示子系统,负责管画面怎么渲染、怎么输出到屏幕。它有四个核心概念,记住了后面看命令输出就不晕:
- CRTC:显示控制器(对应硬件 VOP)
- Plane:图层(视频 / 光标 / 主图层)
- Connector:物理输出(HDMI / DSI / eDP)
- Encoder:CRTC → Connector 中间编码
串起来理解:各个 Plane 上的图层叠好,交给 CRTC 扫描,经 Encoder 转换成接口信号,最后从 Connector 送到屏幕。
RK3588 包含两个 VOP(Video Output Processor,Rockchip 的显示控制器硬件),理论上可支持双屏独立显示。
1.2 主要显示输出接口
| 接口 | 最高规格 | 备注 |
|---|---|---|
| HDMI | 2.1 8K @ 60fps | 含音频 |
| eDP | 1.4 8K | 内置屏常用 |
| DSI | 4K | MIPI 屏 |
| DP | 1.4 | 标准 DisplayPort |
1.3 本机状态
先看一眼本机的 DRM 节点布局,后面的命令都会用到这些名字:
| 路径 | 说明 |
|---|---|
/sys/class/drm/card0 | 主 VOP 控制器 |
card0-HDMI-A-1 | HDMI 输出(connected) |
card0-Writeback-1 | Mem-to-Mem 写回节点(视频管线) |
card1 | 第二 VOP |
renderD128 / renderD129 | GPU 渲染节点 |
2. 准备工作
2.1 硬件清单
| 组件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| 主控板 | C-3588LQ 核心板 + SHIMETAPI-M5-R2A 底板 | 1 | HDMI 内置 |
| 调试串口线 | USB 转 TTL(3.3V) | 1 | 波特率 1500000 |
| HDMI 显示屏 | HDMI 2.0 | 1 | 已连接 |
| LCD / DSI | MIPI DSI 屏 | 可选 | 加 DSI 转接板 |
2.2 引脚
底板的 HDMI 接口已直接引出,插上显示器即可;DSI / eDP 屏则需要 FPC 排线连接:
| 主控板引脚 | 屏引脚 | 用途 |
|---|---|---|
| DSI0_CLK_P / DSI0_CLK_N | CLK_P / CLK_N | MIPI 时钟 |
| DSI0_D0_P / DSI0_D0_N | D0_P / D0_N | Lane 0 |
| DSI0_D1_P / DSI0_D1_N | D1_P / D1_N | Lane 1 |
| 3.3V / 1.8V | VCC | 屏电源 |
| GPIO | RST / BL_ON | 复位 / 背光使能 |
3. 软件准备
3.1 内核配置
显示通路要整体打开:DRM 框架、Rockchip VOP2、以及各个输出接口的驱动:
CONFIG_DRM=y
CONFIG_DRM_KMS_HELPER=y
CONFIG_DRM_ROCKCHIP=y
CONFIG_ROCKCHIP_VOP2=y
CONFIG_ROCKCHIP_ANALOGIX_DP=y
CONFIG_ROCKCHIP_CDN_DP=y
CONFIG_ROCKCHIP_DW_MIPI_DSI=y
CONFIG_ROCKCHIP_DW_HDMI=y
CONFIG_DRM_RCAR_USE_LVDS_CH34XX=y /* 视底板而定 */
CONFIG_DRM_I2C_ADV7511=y /* HDMI 编码器示例 */
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_LOGO=y /* 启动 logo */3.2 设备树
显示通路在设备树里是一串节点:VOP 生成画面,HDMI 控制器负责编码输出,末端的 connector 节点代表物理接口,节点之间用 endpoint 互相引用串起来:
/* VOP2 */
vop: vop@fe040000 {
compatible = "rockchip,rk3588-vop2";
reg = <0x0 0xfe040000 0x0 0x1000>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
clock-names = "aclk", "hclk";
resets = <&cru SRST_VOP>;
reset-names = "vop";
iommu-groups = <...>;
/* 各 window / layer */
status = "okay";
};
/* HDMI */
hdmi: hdmi@fde80000 {
compatible = "rockchip,rk3588-dw-hdmi";
reg = <0x0 0xfde80000 0x0 0x20000>;
interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru CLK_HDMIP>, <&cru PCLK_HDMI>;
clock-names = "pixclk", "pclk";
phys = <&hdmi_phy>;
phy-names = "phy";
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
hdmi_in_vop: endpoint {
remote-endpoint = <&vop_out_hdmi>;
};
};
port@1 {
reg = <1>;
hdmi_out_con: endpoint {
remote-endpoint = <&hdmi_con_in>;
};
};
};
};
/* HDMI Connector */
hdmi_con: connector@1 {
compatible = "hdmi-connector";
label = "hdmi";
port {
hdmi_con_in: endpoint {
remote-endpoint = <&hdmi_out_con>;
};
};
};4. 设备端 DRM
以下命令都在板子上执行,逐项确认显示子系统的状态。
4.1 查看 DRM 卡
ls /sys/class/drm/实机输出:
card0
card0-HDMI-A-1
card0-Writeback-1
card1
renderD128
renderD129
version能看到 card0 和 card0-HDMI-A-1,说明 DRM 驱动已经就位。
4.2 查看连接器状态
cat /sys/class/drm/card0-HDMI-A-1/status实机输出:
connected这台板子的 HDMI 口已连上显示器。
4.3 查看连接器详情
EDID 是显示器自报身份的信息块(厂商、型号、支持的分辨率都写在里面),modes 则直接列出可用分辨率:
cat /sys/class/drm/card0-HDMI-A-1/edid | hexdump -C | head
cat /sys/class/drm/card0-HDMI-A-1/modes输出示例:
1920x1080
1280x720
720x576
...4.4 查看 framebuffer
ls /dev/fb*DRM 模式下画面由
/dev/dri/renderD128(GPU 渲染节点)加实际的 CRTC scanout 完成,传统的/dev/fbX在纯 DRM 系统下可能为空。
4.5 查看当前分辨率
cat /sys/class/drm/card0-HDMI-A-1/mode
# 或
modetest -c4.6 关闭 / 打开显示器
做功耗测试时经常要临时关屏、再恢复:
# 关闭(黑屏)
echo 0 > /sys/class/drm/card0-HDMI-A-1/status
# 恢复
echo auto > /sys/class/drm/card0-HDMI-A-1/status5. 用户态测试(modetest)
modetest 是 libdrm 自带的测试程序,可以绕过桌面环境直接点亮屏幕,最适合验证显示通路通不通:
apt install -y libdrm-tests
modetest -M rockchip -s <connector_id>@<crtc_id>:1920x1080
modetest -M rockchip -c输出示例(节选):
Connectors:
id encoder status name
38 7 connected HDMI-A-1
CRTCs:
id fb pos size
46 47 (0,0) 1920x1080可通过 modetest -s 38@46 在指定连接器 / CRTC 上画测试花纹,屏幕出现彩条即通路正常。
6. 设备树添加显示通路(PC 硯)
如需 DSI / eDP 显示屏,在设备树里补上屏节点和背光:
/* DSI 屏 */
&dsi0 {
status = "okay";
rockchip,dsi-pixel-format = <RK_DSI_FMT_RGB888>;
dsi0_panel: panel@0 {
compatible = "simple-panel";
...
port {
panel_in_dsi: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
};
};
/* 背光(如果由 PWM 控制) */
&pwm12 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pwm12m0_pins>;
};
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm12 0 5000000 0>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
status = "okay";
};电脑端 重新编译烧录后,设备端应在 card*-DSI-1 看到 DSI 屏。
7. 代码解读
7.1 驱动注册
Rockchip DRM 的总入口:bind 时遍历设备树,把各个显示子模块逐个挂进 KMS:
// drivers/gpu/drm/rockchip/rockchip_drm_drv.c(简化)
static int rockchip_drm_bind(struct device *dev)
{
/* 遍历 DTS,匹配 vop / hdmi / dsi 节点并注册 KMS 子模块 */
rockchip_drm_register_vop(...);
rockchip_drm_register_analogix_dp(...);
rockchip_drm_register_dw_hdmi(...);
rockchip_drm_register_dw_mipi_dsi(...);
...
}7.2 用户态调用链
用户态设置一次画面,内核里经过的完整路径:
用户空间: modetest / X server / Weston
→ open(/dev/dri/card0)
→ DRM_IOCTL_MODE_GETCONNECTOR /* 查询输出 */
→ DRM_IOCTL_MODE_GETCRTC /* 获取 CRTC */
→ DRM_IOCTL_MODE_SETCRTC /* 设置分辨率 */
→ DRM_IOCTL_MODE_ATOMIC_COMMIT /* 原子提交(含 plane / gamma / mode 等) */
→ vop2_atomic_commit_tail() /* Rockchip VOP2 */
→ 设置 VOP2 寄存器
→ GPU / SoC 渲染输出 → HDMI PHY → 物理接口8. 故障排除
8.1 HDMI 未识别
dmesg | grep -i hdmi
cat /sys/class/drm/card0-HDMI-A-1/status先看 status 是不是 connected,再从 dmesg 里找初始化失败的线索。
8.2 不显示 Logo
- 设备树未 enable
&vop CONFIG_LOGO=y未设simple-framebuffer配置异常
8.3 DSI 屏黑屏
- 检查 lane 数(
data-lanes = <1 2 3 4>) - 检查 RESET / BL_ON GPIO 时序(先 RESET → 延时 → 释放)
- 检查连续时钟
dsi,continuous-clock属性
