2. 显示系统基础
在开始移植 DRM 驱动之前,必须先理解 Linux 显示子系统为什么从 FBDEV 演进到 DRM。很多移植失败并不是驱动代码写错,而是把“帧缓冲”和“显示控制器管理”混为一谈。FBDEV 只提供一块线性显存和若干 ioctl,而 DRM 把显示管线拆成可管理的对象,并用 KMS 管理显示输出、用 GEM 管理显存缓冲。理解这条演进线,才能在设备树里正确描述管线,在调试时知道问题出在哪个层次。
一、从 FBDEV 到 DRM:显示子系统的演进
早期 Linux 显示驱动以 FBDEV(Framebuffer Device)为核心。它把显示设备抽象成 /dev/fb0,应用通过 mmap 映射显存,直接写入像素数据,再通过 FBIOPUT_VSCREENINFO 设置分辨率、像素格式等参数。FBDEV 的优点是简单,适合固定分辨率、单图层、无硬件加速的嵌入式场景。
但现代 SoC 的显示控制器越来越复杂:多图层叠加、硬件光标、色彩空间转换、缩放、多屏输出、页面翻转、垂直同步等。FBDEV 的单一帧缓冲模型无法表达这些能力,于是 DRM(Direct Rendering Manager)成为主流。DRM 最初用于 GPU 显存管理,后来通过 KMS 接管显示输出,形成“DRM + KMS + GEM”的完整框架。今天,主流 SoC 的显示驱动几乎都走 DRM 路径,FBDEV 更多作为兼容层存在。
核心区别:FBDEV 面向“一块显存”,DRM 面向“一条显示管线”。前者是结果,后者是过程。
二、FBDEV 与 DRM 的关系
两者不是简单的替代关系。Linux 内核提供 fbdev emulation,让 DRM 驱动同时注册一个 /dev/fb0,供只支持 FBDEV 的旧应用使用。也就是说,DRM 是底层真实驱动,FBDEV 是上层兼容接口。移植时如果只实现 FBDEV,会丢失 KMS 的原子提交、多图层和页面翻转能力;如果只实现 DRM 而不开 fbdev 模拟,某些旧 Qt 或控制台程序可能无法显示。
在设备树中,显示控制器节点通常由 DRM 驱动匹配,而 FBDEV 不再单独描述。调试时若看到 /dev/fb0 存在,并不代表驱动是 FBDEV,它可能来自 DRM 的模拟层。判断方法可以查看 /sys/class/drm/ 下是否有 card0 及其 connector 节点。
# 查看 DRM 设备与连接器
ls /sys/class/drm/
# card0 card0-DSI-1 card0-HDMI-A-1 renderD128
# 查看当前显示模式
cat /sys/class/drm/card0-DSI-1/modes
# 查看 fbdev 模拟是否启用
ls /dev/fb*
三、KMS 与 GEM 基本概念
KMS(Kernel Mode Setting)负责“显示什么、怎么显示”。它把显示管线抽象为几类对象:
- CRTC:显示控制器,负责扫描输出,决定时序和刷新。
- Encoder:编码器,把 CRTC 的像素流转换为 HDMI、DSI、LVDS 等信号。
- Connector:物理接口,如 HDMI 口、MIPI DSI 屏,负责读取 EDID 和热插拔检测。
- Plane:图层,负责从显存取像素并叠加,支持主图层和叠加图层。
- Framebuffer:当前扫描输出的缓冲对象,关联到 GEM 对象。
GEM(Graphics Execution Manager)负责“显存怎么分配、怎么共享”。它管理 DRM 的 buffer object(BO),提供创建、映射、同步和跨进程共享能力。应用通过 DRM_IOCTL_MODE_CREATE_DUMB 创建 dumb buffer,或通过 PRIME 在 GPU 与显示控制器之间共享缓冲区。KMS 决定管线连接,GEM 决定数据存放,两者配合完成一次显示。
四、典型应用场景与调试切入点
不同场景对显示子系统的要求不同,理解场景有助于判断该用 FBDEV 还是 DRM。
| 场景 | 典型接口 | 推荐框架 | 关键关注点 |
|---|---|---|---|
| 嵌入式 HMI 固定屏 | MIPI DSI / RGB | DRM + fbdev 模拟 | 时序参数、背光、单图层 |
| 多屏异显 | HDMI + DSI | DRM/KMS | CRTC 分配、Connector 热插拔 |
| 视频播放与叠加 | HDMI / eDP | DRM + GEM + Plane | 页面翻转、PRIME、零拷贝 |
| 旧 Qt 应用兼容 | 任意 | FBDEV 或 fbdev 模拟 | /dev/fb0 是否存在、像素格式 |
| GPU 渲染上屏 | eDP / HDMI | DRM + GEM + PRIME | DMA-BUF 共享、同步栅栏 |
调试提示:先确认 /sys/class/drm/ 下 connector 状态,再检查 modetest 是否能枚举 CRTC 和 Plane。若 connector 为 disconnected,优先排查设备树中的接口节点、时钟和电源域,而不是改驱动代码。
五、常见误区与复盘
- 误区一:把 FBDEV 当成 DRM 的替代品。实际上 DRM 是底层,FBDEV 是兼容接口。移植时应以 DRM 为主,按需开启 fbdev 模拟。
- 误区二:只配置设备树,不验证 KMS 对象。设备树只描述硬件连接,KMS 对象是否完整由驱动 probe 决定。用
modetest验证比只看 dmesg 更可靠。 - 误区三:忽略 GEM 的显存类型。Dumb buffer 适合简单测试,但视频和 GPU 场景需要 DMA-BUF 和 PRIME,否则会出现拷贝开销和撕裂。
- 误区四:看到
/dev/fb0就认为驱动是 FBDEV。它可能来自 DRM 的 fbdev 模拟,需结合/sys/class/drm/判断。
掌握 FBDEV 与 DRM 的分层关系、KMS 的对象模型和 GEM 的显存管理,是后续设备树配置和显示链路调试的基础。只有先分清“管线”和“显存”两条线,才能在移植中快速定位问题属于哪个层次。