3. 瑞芯微VOP驱动架构:VOP硬件管线、VOP驱动初始化流程、VOP与DRM核心的绑定
瑞芯微平台的显示输出核心是 VOP(Video Output Processor,视频输出处理器)。VOP 驱动作为 DRM/KMS 框架下的 CRTC 实现,负责将 Framebuffer 中的图像数据经过一系列硬件管线处理后,最终通过 HDMI、MIPI DSI、eDP 等接口输出到显示设备。本章深入剖析 VOP 的硬件管线构成、驱动初始化流程以及如何与 DRM 核心层完成绑定。
3.1 VOP 硬件管线架构
VOP 内部是一个高度可编程的显示处理流水线。以 RK3588 的 VOP2 为例,其硬件管线主要包含以下关键模块:
| 模块 | 功能描述 | 关键特性 |
|---|---|---|
| Win(窗口) | 支持多个独立图层(Win0~Win3),每个 Win 可绑定不同的 Framebuffer。 | 支持缩放、YUV/RGB 转换、Alpha 混合、Z-order 排序。 |
| Mixer(混合器) | 将多个 Win 输出的图层按照 Z-order 进行 Alpha 混合,生成最终的合成图像。 | 支持全局背景色、逐像素 Alpha、预乘 Alpha。 |
| Dither(抖动) | 将高色深图像(如 10bit)抖动处理为低色深输出(如 8bit),减少色带。 | 支持 Temporal Dithering(时域抖动)。 |
| Gamma/LUT | 提供可编程的 Gamma 校正查找表,用于色彩校准。 | 支持分段线性 Gamma 或全表 LUT。 |
| Timing Controller(T-CON) | 根据显示模式(如 1920x1080@60Hz)生成行/场同步信号、DE 信号。 | 支持 VESA/CEA 标准时序,可编程 HBP/HFP/VBP/VFP。 |
| Connector(接口) | 将并行 RGB 数据转换为特定接口协议(如 LVDS、MIPI DSI、eDP、HDMI)。 | 每个接口有独立的 PHY 和时钟域。 |
架构要点: VOP 的 Win 模块是驱动与 DRM Plane 对应的硬件实体。每个 Win 可以独立配置源地址、裁剪区域、显示位置和缩放系数,这是实现多图层合成和硬件光标的基础。
下图展示了 VOP 内部从内存读取到接口输出的完整数据流:
3.2 VOP 驱动初始化流程
VOP 驱动的初始化遵循 Linux 平台驱动模型,在 rockchip_vop2_probe() 函数中完成。核心步骤包括资源获取、硬件复位、中断注册和 DRM 组件注册。
- 设备树解析与资源获取:读取 VOP 寄存器基地址、时钟、中断号、复位控制等资源。
- 时钟与复位初始化:使能 AXI/AHB 时钟、VOP 核心时钟(如 dclk、aclk、hclk),释放复位信号。
- 硬件版本检测:读取 VOP 版本寄存器,区分 VOP1/VOP2 等不同 IP 版本。
- Win 与 Mixer 配置:根据设备树中定义的 Win 数量,初始化每个 Win 的寄存器偏移和功能掩码。
- 中断注册:注册 VOP 帧完成中断(FS)、行中断(LINE)等,用于 Vblank 信号和 CRC 校验。
- DRM CRTC 与 Plane 初始化:调用
drm_crtc_init_with_planes()将 VOP 注册为 DRM CRTC,将 Win 注册为 DRM Plane。 - 组件绑定:通过
component_add()将 VOP 加入 DRM 驱动组件框架,等待所有组件(如 HDMI、DSI 编码器)就绪后完成绑定。
初始化关键点: VOP 驱动必须确保所有时钟和电源域在注册 DRM 设备之前已经稳定。如果时钟未使能就操作寄存器,会导致系统挂死。建议在 probe 函数中增加时钟状态检查。
以下为 VOP2 驱动 probe 函数的核心代码片段:
static int vop2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct vop2 *vop2;
struct resource *res;
int ret, i;
vop2 = devm_kzalloc(dev, sizeof(*vop2), GFP_KERNEL);
if (!vop2)
return -ENOMEM;
// 1. 获取寄存器基地址
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
vop2->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(vop2->regs))
return PTR_ERR(vop2->regs);
// 2. 获取时钟
vop2->aclk = devm_clk_get(dev, "aclk_vop");
vop2->hclk = devm_clk_get(dev, "hclk_vop");
vop2->dclk = devm_clk_get(dev, "dclk_vop");
if (IS_ERR(vop2->aclk) || IS_ERR(vop2->hclk) || IS_ERR(vop2->dclk))
return -EPROBE_DEFER;
// 3. 使能时钟
clk_prepare_enable(vop2->aclk);
clk_prepare_enable(vop2->hclk);
clk_prepare_enable(vop2->dclk);
// 4. 硬件复位
reset_control_assert(vop2->rst);
udelay(10);
reset_control_deassert(vop2->rst);
// 5. 初始化 Win 硬件信息
for (i = 0; i < VOP2_MAX_WIN; i++) {
vop2->win[i]->phy = &vop2_win_phys[i];
vop2->win[i]->regs = vop2->regs + vop2_win_phys[i].offset;
}
// 6. 注册中断
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
vop2_isr, 0, dev_name(dev), vop2);
if (ret)
return ret;
// 7. 初始化 DRM 子组件
vop2->drm_dev = drm_dev_alloc(&vop2_driver, dev);
if (IS_ERR(vop2->drm_dev))
return PTR_ERR(vop2->drm_dev);
// 8. 注册组件,等待绑定
return component_add(dev, &vop2_component_ops);
}
3.3 VOP 与 DRM 核心的绑定
VOP 驱动通过 DRM 的 组件化框架(Component Framework) 实现与 Encoder、Connector 的绑定。绑定过程分为两个阶段:
| 阶段 | 函数 | 动作 |
|---|---|---|
| 组件添加 | component_add() |
VOP 驱动将自己注册为组件,等待 master 驱动(rockchip-drm)调用 bind 回调。 |
| 组件绑定 | vop2_bind() |
创建 CRTC 和 Plane,注册到 DRM 设备,并与对应的 Encoder 建立连接。 |
| 组件解绑 | vop2_unbind() |
清理 CRTC、Plane,释放中断和内存。 |
在 vop2_bind() 函数中,VOP 驱动完成以下关键绑定操作:
- CRTC 初始化:调用
drm_crtc_init_with_planes(),将 VOP 主控制器注册为 CRTC,并关联主 Plane 和光标 Plane。 - Plane 注册:遍历所有 Win 硬件,为每个 Win 调用
drm_universal_plane_init(),设置支持的像素格式(如 ARGB8888、NV12、NV16)。 - Vblank 处理:通过
drm_crtc_vblank_init()启用 Vblank 支持,在中断处理函数中调用drm_crtc_handle_vblank()。 - Encoder 连接:在 master 驱动的 bind 函数中,通过
drm_encoder_init()和drm_bridge_attach()将 VOP 的输出连接到对应的 Encoder/Bridge。
绑定注意事项: 如果 VOP 驱动在 bind 阶段未能成功注册 Plane,DRM 核心将无法创建 Framebuffer,导致整个显示链路不可用。务必检查 Plane 的格式列表是否与硬件 Win 的能力匹配。
下图展示了 VOP 与 DRM 核心组件之间的绑定关系:
3.4 关键数据结构与函数接口
VOP 驱动中几个核心的数据结构直接映射到 DRM 框架:
struct vop2:VOP 控制器私有数据结构,包含寄存器基地址、时钟、中断、Win 数组、DRM CRTC 指针等。struct vop2_win:单个 Win 的私有数据结构,包含硬件寄存器偏移、支持的格式列表、当前绑定的 DRM Plane 指针。struct vop2_video_port:视频端口结构,对应一个完整的显示输出链路(CRTC + Encoder + Connector),RK3588 最多支持 4 个视频端口。
VOP 驱动对外暴露的关键操作函数集:
| 函数 | 所属结构 | 作用 |
|---|---|---|
vop2_crtc_enable() |
drm_crtc_helper_funcs |
使能 CRTC,配置时序、使能时钟、启动 T-CON。 |
vop2_crtc_disable() |
drm_crtc_helper_funcs |
关闭 CRTC,停止时钟,进入低功耗模式。 |
vop2_plane_atomic_update() |
drm_plane_helper_funcs |
更新 Plane 的 Framebuffer 地址、裁剪区域、缩放系数。 |
vop2_plane_atomic_disable() |
drm_plane_helper_funcs |
禁用指定 Plane,关闭对应 Win 的显示。 |
vop2_atomic_commit_tail() |
drm_mode_config_helper_funcs |
执行原子提交的硬件更新,包括 Flush 寄存器。 |
性能优化提示: 在
vop2_plane_atomic_update() 中,如果 Framebuffer 使用 AFBC(帧缓冲压缩),需要额外配置 AFBC 解码寄存器。AFBC 可以减少内存带宽占用,但会增加约 1~2 行的延迟。
通过以上分析可以看出,瑞芯微 VOP 驱动通过精细的硬件管线设计、规范的组件化初始化流程以及紧密的 DRM 核心绑定,为上层应用提供了高效、灵活的显示输出能力。理解 VOP 的架构是后续进行显示优化(如多图层合成、低延迟渲染、HDR 输出)的基础。