3. DRM框架基础
在全志(Allwinner)平台上移植DRM显示驱动,第一步不是写寄存器,而是理解DRM子系统如何把一块屏幕抽象成一组可编程对象。DRM(Direct Rendering Manager)负责显存与命令提交,KMS(Kernel Mode Setting)负责显示模式设置与画面合成。二者共同构成Linux显示驱动的骨架,而全志的Display Engine(DE)驱动本质上就是把这套骨架“翻译”成DE的图层、时序与DMA通道配置。
一、KMS核心对象:从抽象到硬件
KMS把显示通路拆成五类对象,它们之间是“流水线式”的引用关系:
- Framebuffer(FB):描述一块可扫描输出的像素缓冲,记录宽高、像素格式、pitch与GEM对象句柄。它不关心显存实际在哪,只描述“怎么读”。
- Plane:图层,是FB的承载者。一个CRTC可叠加多个Plane(全志DE通常支持多个UI/Video层),Plane负责位置、缩放、混合与alpha。
- CRTC:显示控制器,对应一路扫描输出引擎,负责时序生成(h/v sync、porch)与像素时钟。它把若干Plane合成后送往Encoder。
- Encoder:把CRTC的并行像素流转换为具体接口信号,如RGB、LVDS、MIPI DSI、HDMI TMDS。
- Connector:物理连接器,管理热插拔检测(HPD)、EDID读取与显示模式列表,是用户空间看到的“显示器”。
这五者的关系可以用下面的结构图直观理解:
二、GEM与TTM:显存从哪里来
Framebuffer只是“视图”,真正分配显存的是GEM(Graphics Execution Manager)。GEM提供drm_gem_object抽象,负责对象创建、句柄管理、mmap与PRIME导出。它本身不规定显存位置,只定义“一块可被GPU/显示控制器访问的缓冲”。
TTM(Translation Table Manager)则进一步管理显存域(VRAM、GTT、SYSTEM),负责缓冲在不同域之间的迁移与同步。全志平台通常没有独立VRAM,显示缓冲多分配在CMA(Contiguous Memory Allocator)区域,以保证DE能拿到物理连续的地址。因此实际路径是:GEM对象 → CMA分配 → DMA-BUF导出 → 显示控制器扫描。
三、方法流程:一次模式设置的完整链路
用户空间通过libdrm发起一次显示配置,内核侧大致经历以下步骤:
- 打开
/dev/dri/card0,调用drmModeGetResources()枚举CRTC、Encoder、Connector。 - 用
drmModeGetConnector()读取连接状态与EDID,得到可用模式列表。 - 创建Dumb Buffer或GEM Buffer,并
drmModeAddFB()生成Framebuffer。 - 调用
drmModeSetCrtc(),把FB绑定到CRTC,并指定输出到哪个Connector。 - 若需叠加图层,使用
drmModeSetPlane()配置Plane的位置、缩放与混合。 - 提交后触发原子(Atomic)或传统(Legacy)路径,驱动写DE寄存器并启动扫描。
# 典型调试命令:查看当前KMS对象
modetest -M sun4i-drm -c # 列出CRTC
modetest -M sun4i-drm -e # 列出Encoder
modetest -M sun4i-drm -p # 列出Connector与模式
modetest -M sun4i-drm -s 40:1920x1080 -P 30@40:1920x1080+0+0
四、案例场景:全志H616 HDMI点屏
以H616 + HDMI为例,设备树中tcon-tv、hdmi、dw-hdmi节点分别对应CRTC、Encoder与Connector。启动后内核日志会打印:
[drm] Initialized sun4i-drm 1.0.0 for display-engine on minor 0
sun4i-drm display-engine: bound 1c0c000.tcon-tv (ops 0xffff...)
sun4i-drm display-engine: bound 1c30000.hdmi (ops 0xffff...)
[drm] Connector HDMI-A-1: connected, EDID 1920x1080@60
此时若modetest -p能看到模式列表,说明Connector与EDID通路正常;若drmModeSetCrtc返回-EINVAL,多半是Framebuffer的pitch或格式与DE不匹配,而不是HDMI本身的问题。
五、常见误区与复盘
| 误区 | 现象 | 正确理解 |
|---|---|---|
| 把Framebuffer当成显存 | 改FB参数后画面仍异常 | FB只是视图,真正数据在GEM/CMA缓冲 |
| 认为Plane越多越好 | 图层叠加后花屏或撕裂 | DE图层数有限,且带宽与格式有约束 |
| 忽略Connector状态 | SetCrtc成功但无输出 | 需先确认HPD与EDID,再配置模式 |
| GEM与DMA-BUF混用不当 | 跨设备共享时地址错误 | 用PRIME导出/导入,确保dma-buf附件正确 |
理解这五类对象与GEM/TTM的分工,是后续分析显示缓存、DMA-BUF共享与全志DE寄存器配置的基础。只有把“谁描述数据、谁搬运数据、谁扫描输出”这三件事分清,移植过程中的花屏、无输出、撕裂等问题才能被快速定位。