1. DRM 驱动概述
1.1 DRM 框架发展历史
DRM(Direct Rendering Manager)最初诞生于 XFree86 时代,目的是解决多个 X Server 进程同时访问显卡时的资源竞争问题。2003 年,DRM 被合入 Linux 主线内核 2.5 系列,成为内核图形子系统的基础组件。早期的 DRM 仅提供基本的 GPU 命令提交和内存管理,显示输出仍由用户态的 X Server 控制。
2012 年,Linux 内核 3.8 引入了 KMS(Kernel Mode Setting),将显示模式设置、帧缓冲管理和输出链路控制从用户态移入内核。这一变革彻底改变了嵌入式显示驱动的开发方式:开发者不再需要为每个 SoC 编写复杂的用户态显示库,而是通过统一的 DRM/KMS 接口完成显示链路配置。
2014 年之后,DRM 框架逐步引入 GEM(Graphics Execution Manager)作为标准内存管理方案,替代了早期的 TTM(Translation Table Manager)。GEM 提供了 Buffer Object、Dumb Buffer、Prime(DMA-BUF 共享)等机制,成为嵌入式平台显示内存管理的事实标准。
- 2003 — DRM 合入主线,提供 GPU 命令提交基础
- 2012 — KMS 引入,显示模式设置内核化
- 2014 — GEM 成为主流内存管理方案
- 2016 — Atomic KMS 合入,支持无撕裂提交
- 2018+ — Bridge/Encoder 抽象完善,适配 MIPI DSI/HDMI/DP
1.2 核心组件:DRM / KMS / GEM
DRM 框架由三个核心子系统构成,各自承担不同的职责。理解这三者的分工是进行驱动移植和显示链路调试的前提。
| 组件 | 全称 | 核心职责 | 关键数据结构 |
|---|---|---|---|
| DRM | Direct Rendering Manager | GPU 命令提交、上下文管理、文件操作接口 | drm_device, drm_file, drm_driver |
| KMS | Kernel Mode Setting | 显示模式设置、输出链路管理、帧缓冲控制 | drm_crtc, drm_encoder, drm_connector, drm_plane |
| GEM | Graphics Execution Manager | 显存分配、Buffer Object 管理、DMA-BUF 共享 | drm_gem_object, drm_gem_cma_object |
drm_gem_cma_helper 是移植时最常用的内存管理方案,无需复杂的 GPU MMU 支持。
1.3 DRM 在嵌入式 Linux 中的地位
在嵌入式 Linux 领域,DRM/KMS 已经取代了传统的 FBDEV(Frame Buffer Device)和 V4L2 输出接口,成为显示子系统的事实标准。几乎所有主流嵌入式 SoC 平台(i.MX、Rockchip、Allwinner、Qualcomm、Mediatek、STM32MP)都使用 DRM 驱动作为显示输出方案。
DRM 在嵌入式系统中的核心优势体现在以下几个方面:
- 统一接口 — 应用层通过标准 DRM ioctl 操作显示,无需关心底层 SoC 差异
- 零拷贝显示 — GEM/Prime 支持 DMA-BUF 共享,视频解码器输出可直接送显
- 多图层合成 — KMS Plane 支持硬件图层叠加,无需 GPU 参与即可实现 UI 合成
- 无撕裂更新 — Atomic KMS 保证帧切换在 VBlank 期间完成,消除撕裂
- 设备树驱动 — 显示链路拓扑通过设备树描述,驱动移植只需修改 dts
1.4 DRM 驱动移植的核心挑战
在嵌入式平台上移植 DRM 驱动,开发者通常面临以下关键问题:
| 挑战 | 典型场景 | 解决方案 |
|---|---|---|
| 设备树显示链路描述 | MIPI DSI 桥接芯片 + 触摸屏组合 | 正确配置 ports、remote-endpoint、panel 节点 |
| Encoder/Bridge 适配 | HDMI 转换芯片(如 LT8619、SIL9022) | 实现 drm_bridge_funcs 回调,配置 I2C 初始化序列 |
| 时序与分辨率配置 | 非标 LCD 屏(800×480、1024×600) | 在 panel 节点中填写 display-timings 子节点 |
| 时钟与复位依赖 | DSI 控制器需要 PLL 时钟和 GPIO 复位 | 设备树中声明 clocks、resets、pinctrl 属性 |
| DMA-BUF 共享 | 视频解码器直接输出到显示缓冲区 | 使用 GEM Prime 导出 dma-buf fd,通过 drm_mode_set_plane 送显 |