3、显示驱动框架:Linux DRM框架介绍、RK3588 DRM驱动架构、VOP与CRTC关系
3.1 Linux DRM框架概述
DRM(Direct Rendering Manager)是Linux内核中负责图形显示和GPU管理的标准框架。它取代了传统的FBDEV(Framebuffer Device)架构,提供了更现代的显示管线抽象、内存管理、同步机制和用户空间API。
核心设计理念: DRM将显示硬件抽象为若干个CRTC(Cathode Ray Tube Controller,显示控制器)、Encoder(编码器)、Connector(连接器)和Plane(图层)的原子化组合,用户空间通过
drmModeAtomicCommit实现无撕裂的帧切换。
DRM框架的核心组件及其职责如下表所示:
| 组件 | 内核对象 | 职责描述 |
|---|---|---|
| CRTC | drm_crtc |
控制显示时序(行场同步、像素时钟),驱动VOP(Video Output Processor)硬件 |
| Plane | drm_plane |
管理图层叠加、缩放、色彩空间转换,每个CRTC可绑定多个Plane |
| Encoder | drm_encoder |
将CRTC输出的像素数据编码为特定接口格式(LVDS、MIPI DSI、HDMI等) |
| Connector | drm_connector |
代表物理显示接口,检测热插拔、读取EDID、管理显示模式 |
| Bridge | drm_bridge |
可选的外部桥接芯片抽象层,用于LVDS转eDP、DSI转LVDS等场景 |
DRM框架的软件分层结构如下图所示:
3.2 RK3588 DRM驱动架构
RK3588的DRM驱动位于内核源码 drivers/gpu/drm/rockchip/ 目录下,核心文件包括:
- rockchip_drm_drv.c — 驱动入口,注册platform_driver,初始化drm_device
- rockchip_vop2_reg.c — VOP2寄存器定义和操作函数
- rockchip_vop2.c — VOP2 CRTC实现,包含atomic_flush、enable/disable、mode_set
- rockchip_lvds.c — LVDS Encoder + Connector驱动,负责时序配置和PHY初始化
- rockchip_drm_dsi.c — MIPI DSI驱动,用于DSI转LVDS桥接场景
- rockchip_drm_vv.c — 虚拟显示驱动,用于无物理屏调试
关键路径: RK3588的显示数据流为:
其中VOP2负责从DDR抓取帧缓冲数据,叠加图层,生成RGB像素流;LVDS Encoder将并行RGB转换为串行LVDS差分信号。
GPU/VPU → DDR → VOP2 (CRTC) → LVDS Encoder → LVDS PHY → LVDS Connector → LCD Panel其中VOP2负责从DDR抓取帧缓冲数据,叠加图层,生成RGB像素流;LVDS Encoder将并行RGB转换为串行LVDS差分信号。
RK3588 DRM驱动的组件拓扑关系如下图所示:
3.3 VOP与CRTC关系
VOP(Video Output Processor)是Rockchip SoC中的显示输出处理器硬件模块,在DRM框架中对应CRTC角色。RK3588集成了VOP2,相比前代VOP有显著增强:
| 特性 | VOP (RK3399) | VOP2 (RK3588) |
|---|---|---|
| 最大输出分辨率 | 4K@60fps | 8K@60fps |
| 图层数 | 3个Win | 4个Win + 1个HDR |
| AFBC支持 | 仅Win2 | 所有Win支持 |
| HDR处理 | 不支持 | HDR10/HLG |
| 输出接口 | 1路显示 | 3路独立显示 |
| 缩放引擎 | 仅主层 | 每个Win独立缩放 |
VOP2与CRTC的映射关系在驱动初始化时建立,核心代码流程如下:
// rockchip_vop2.c 中的关键初始化流程
static int vop2_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm_dev = data;
struct vop2 *vop2;
struct vop2_video_port *vp;
int i;
// 1. 解析设备树,获取VOP2寄存器基址、时钟、中断
vop2 = devm_kzalloc(dev, sizeof(*vop2), GFP_KERNEL);
// ...
// 2. 遍历每个video_port,注册为DRM CRTC
for (i = 0; i < vop2->data->nr_vps; i++) {
vp = &vop2->vps[i];
vp->vop2 = vop2;
vp->id = i;
// 3. 初始化CRTC,绑定vop2_crtc_funcs和vop2_crtc_helper_funcs
ret = drm_crtc_init_with_planes(drm_dev, &vp->crtc,
&vp->win->plane, NULL,
&vop2_crtc_funcs, NULL);
// 4. 设置CRTC辅助函数(mode_set, enable, disable, atomic_flush)
drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
}
// 5. 注册VOP2为drm_simple_display_pipe(简化路径)或完整CRTC
return 0;
}
常见移植陷阱: VOP2的CRTC注册必须与设备树中的
video_port节点一一对应。如果设备树中定义了3个port,但驱动只注册了2个CRTC,会导致第3路显示无法枚举。检查/sys/kernel/debug/dri/0/crtc-*确认CRTC数量。
VOP2内部架构与CRTC的对应关系如下图所示:
3.4 CRTC与Encoder/Connector的绑定
在RK3588的DRM驱动中,CRTC与Encoder/Connector的绑定通过设备树端口(port)和DRM组件框架完成。核心绑定逻辑如下:
// rockchip_drm_drv.c 中的组件绑定
static int rockchip_drm_bind(struct device *dev)
{
struct drm_device *drm_dev;
struct rockchip_drm_private *private;
// 1. 创建drm_device
drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
// 2. 初始化组件匹配列表
component_match_add(dev, &match, compare_of, NULL);
// 3. 等待所有组件(VOP2、LVDS、HDMI等)就绪
return component_bind_all(dev, drm_dev);
}
// rockchip_lvds.c 中的Encoder/Connector注册
static int rockchip_lvds_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm_dev = data;
struct rockchip_lvds *lvds;
// 1. 获取绑定的CRTC(通过设备树port远程端点匹配)
lvds->crtc = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
// 2. 初始化Encoder
drm_encoder_init(drm_dev, &lvds->encoder, &rockchip_lvds_encoder_funcs,
DRM_MODE_ENCODER_LVDS, NULL);
lvds->encoder.possible_crtcs = lvds->crtc; // 绑定到特定CRTC
// 3. 初始化Connector
drm_connector_init(drm_dev, &lvds->connector, &rockchip_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
// 4. 连接Encoder和Connector
drm_connector_attach_encoder(&lvds->connector, &lvds->encoder);
}
设备树绑定示例: LVDS节点通过
其中
ports指定连接到哪个VOP2的Video Port。lvds@fda90000 { ... ports { port@0 { remote-endpoint = <&vp0_out_lvds>; }; }; };其中
vp0_out_lvds是VOP2节点中Video Port 0的输出端点,驱动通过drm_of_find_possible_crtcs解析这个连接关系。
CRTC、Encoder、Connector三者的生命周期管理关系如下表:
| 操作 | CRTC (VOP2) | Encoder (LVDS) | Connector (Panel) |
|---|---|---|---|
| 初始化 | 分配Video Port、配置时钟、注册中断 | 初始化PHY、配置输出格式 | 读取EDID/panel参数、注册显示模式 |
| Enable | 启动VOP时序、使能DMA | 使能LVDS时钟、输出差分信号 | 发送panel上电序列、背光控制 |
| Mode Set | 配置H/V总参数、像素时钟 | 配置数据映射格式(JEIDA/VESA) | 验证模式是否在panel支持范围内 |
| Disable | 停止VOP、关闭时钟 | 关闭LVDS PHY | 发送panel下电序列、关闭背光 |