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框架的软件分层结构如下图所示:

Linux DRM 框架软件分层结构 用户空间:libdrm / Mesa / Weston / SurfaceFlinger 系统调用:ioctl (DRM_IOCTL_MODE_*) DRM Core:drm_framebuffer / drm_atomic / drm_gem / drm_syncobj DRM Driver:rockchip_drm_vop2 / rockchip_drm_dsi / rockchip_lvds 硬件层:VOP2 / LVDS PHY / DSI DPHY / HDMI TX 说明:RK3588 驱动层位于 DRM Core 之下,直接操作 VOP2 和 LVDS PHY 寄存器

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的显示数据流为:
GPU/VPU → DDR → VOP2 (CRTC) → LVDS Encoder → LVDS PHY → LVDS Connector → LCD Panel
其中VOP2负责从DDR抓取帧缓冲数据,叠加图层,生成RGB像素流;LVDS Encoder将并行RGB转换为串行LVDS差分信号。

RK3588 DRM驱动的组件拓扑关系如下图所示:

RK3588 DRM 驱动组件拓扑 VOP2 CRTC rockchip_vop2.c Plane 0 (Win0) 视频层/UI层 Plane 1 (Win1) 光标/OSD层 Plane 2 (Win2) AFBC解码层 Plane 3 (Win3) 缩放/旋转层 LVDS Encoder rockchip_lvds.c LVDS Connector panel-simple / panel-lvds LCD Panel 设备树描述 说明:每个VOP2 CRTC最多支持4个Plane,LVDS Encoder和Connector在设备树中通过端口(port)连接

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的对应关系如下图所示:

VOP2 内部架构与 CRTC 对应关系 AXI 系统总线(DDR 帧缓冲读取) Win0 (Smart) Win1 (Smart) Win2 (ESmart) Win3 (ESmart) AFBC 解码器 / 缩放引擎 / CSC 色彩空间转换 Alpha 混合器 / 背景色生成 Video Port 0 CRTC 0 (VP0) Video Port 1 CRTC 1 (VP1) Video Port 2 CRTC 2 (VP2) 输出接口:LVDS / MIPI DSI / HDMI / eDP / DP 说明:VOP2 内部有 3 个 Video Port,每个对应一个 DRM CRTC。Win0~Win3 是图层输入, 经过混合后分配到不同 Video Port,最终由输出接口发送到显示面板。

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下电序列、关闭背光