2. Linux DRM 框架简介:DRM/KMS 架构、CRTC/Encoder/Connector/Plane 概念、设备树与驱动绑定
DRM(Direct Rendering Manager)是 Linux 内核中负责图形显示与渲染的核心框架。自内核 2.6.9 引入以来,DRM 已从最初的 GPU 管理扩展为包含 KMS(Kernel Mode Setting)的完整显示栈。对于 MIPI DSI 嵌入式显示驱动开发,理解 DRM/KMS 架构是编写高质量驱动的基石。
2.1 DRM/KMS 整体架构
DRM 框架分为两层:DRM Core 提供用户空间接口(/dev/dri/card0)、GEM 内存管理、Fence 同步机制;KMS 负责显示模式设置、扫描输出、显示流水线控制。KMS 是驱动开发者最常打交道的部分,它抽象了显示硬件为四个核心对象:CRTC、Encoder、Connector、Plane。
架构要点: DRM 驱动通过注册
struct drm_driver 和 struct drm_mode_config_funcs 向核心层暴露硬件能力。KMS 对象通过 drm_mode_config 统一管理,用户空间通过 Atomic API 或 Legacy API 提交显示状态。
2.2 核心 KMS 对象:CRTC / Encoder / Connector / Plane
KMS 将显示流水线拆解为四个职责明确的对象。理解它们之间的关系是调试 MIPI DSI 显示的关键。
| KMS 对象 | 内核结构体 | 职责描述 | MIPI DSI 场景对应 |
|---|---|---|---|
| CRTC | struct drm_crtc |
扫描输出控制:时序生成、帧缓冲切换、VBLANK 中断 | DSI 主机控制器的时序引擎 |
| Encoder | struct drm_encoder |
像素数据编码转换:RGB → MIPI DSI / LVDS / HDMI | DSI D-PHY 发送器 + 协议打包 |
| Connector | struct drm_connector |
物理连接检测:EDID 读取、热插拔、显示参数 | DSI 面板设备(固定连接,无热插拔) |
| Plane | struct drm_plane |
图层叠加:缩放、旋转、色彩空间转换、Alpha 混合 | 硬件图层(主图层 / 光标图层 / 视频图层) |
调试提示: 在 MIPI DSI 驱动中,Connector 通常不实现热插拔检测(HPD),而是通过
drm_connector_init() 固定为 connector_type = DRM_MODE_CONNECTOR_DSI。CRTC 和 Encoder 之间通过 drm_crtc_init_with_planes() 绑定。
2.3 设备树与驱动绑定
在嵌入式 Linux 中,DRM 驱动通过设备树(Device Tree)描述硬件拓扑,驱动核心通过 of_match_table 匹配设备节点。MIPI DSI 的设备树绑定遵循 Documentation/devicetree/bindings/display/ 下的规范。
2.3.1 典型 MIPI DSI 设备树结构
/* 示例:i.MX8M Plus MIPI DSI 设备树节点 */
&mipi_dsi {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "boe,tv110c9m-ll08";
reg = <0>;
reset-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
backlight = <&backlight_lcd0>;
dsi-lanes = <4>;
rotation = <0>;
port {
panel_in: endpoint {
remote-endpoint = <&mipi_dsi_out>;
};
};
};
ports {
port@1 {
reg = <1>;
mipi_dsi_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};
常见绑定错误: 忘记设置
dsi-lanes 属性会导致 D-PHY 初始化失败;reset-gpios 极性错误(GPIO_ACTIVE_LOW vs GPIO_ACTIVE_HIGH)会导致面板无法退出复位状态。务必对照面板数据手册确认时序和 GPIO 极性。
2.3.2 驱动绑定流程
DRM 驱动通过 component 框架或 drm_bridge 框架实现模块化绑定。MIPI DSI 主机控制器驱动通常实现 struct mipi_dsi_host_ops,面板驱动实现 struct mipi_dsi_driver。
| 步骤 | 驱动侧 | 关键函数 / 回调 | 说明 |
|---|---|---|---|
| 1 | DSI 主机控制器 | probe() → mipi_dsi_host_register() |
注册 DSI 主机,初始化 D-PHY 和时钟 |
| 2 | DSI 面板 | probe() → mipi_dsi_device_register_full() |
解析设备树,分配 DSI 设备 ID |
| 3 | DSI 主机控制器 | host_ops.attach() |
建立 DSI 总线连接,配置传输模式 |
| 4 | DRM 桥接 / 组件 | drm_bridge_add() / component_add() |
将面板作为 DRM 桥接器加入显示链 |
| 5 | DRM CRTC | drm_crtc_init_with_planes() |
初始化 CRTC 并关联主 Plane |
| 6 | DRM Connector | drm_connector_init() + drm_connector_attach_encoder() |
注册 Connector 并绑定到 Encoder |
2.4 关键数据结构与 API 速查
驱动开发中频繁使用的 DRM 核心 API 和数据结构如下表所示。建议在编写驱动时参考内核源码 include/drm/drm_* 头文件。
| 类别 | 结构体 / 函数 | 用途 |
|---|---|---|
| CRTC | drm_crtc_init_with_planes() |
初始化 CRTC 并绑定主 Plane 和光标 Plane |
| CRTC | struct drm_crtc_funcs |
实现 .set_config、.page_flip、.atomic_begin 等回调 |
| Encoder | drm_encoder_init() |
注册 Encoder,指定可能的 CRTC 掩码 |
| Connector | drm_connector_init() |
注册 Connector,指定类型(DSI/eDP/HDMI) |
| Connector | drm_connector_attach_encoder() |
将 Connector 绑定到 Encoder |
| Plane | drm_universal_plane_init() |
初始化 Plane,支持格式列表和属性 |
| Bridge | drm_bridge_add() / drm_bridge_attach() |
桥接器模式,用于面板或转换芯片 |
| Atomic | drm_atomic_state_alloc() / drm_atomic_commit() |
原子模式设置,保证显示状态切换无撕裂 |
调试切入点: 当 MIPI DSI 面板无显示时,首先检查
/sys/kernel/debug/dri/0/ 下的 KMS 对象状态:cat state 查看 CRTC/Encoder/Connector 连接关系;cat clients 查看用户空间占用。使用 modetest 工具可以手动设置模式测试显示链是否完整。
2.5 本章小结
- DRM/KMS 是 Linux 显示驱动的标准框架,KMS 提供 CRTC、Encoder、Connector、Plane 四个核心抽象。
- MIPI DSI 驱动中,CRTC 对应时序引擎,Encoder 对应 D-PHY 编码,Connector 对应面板设备,Plane 对应硬件图层。
- 设备树通过
compatible属性匹配驱动,DSI 主机和面板通过mipi_dsi_host_ops和mipi_dsi_driver实现总线绑定。 - 驱动绑定流程遵循:设备树解析 → 主机注册 → 面板探测 → DRM 组件聚合 → 显示链就绪。
- 调试时善用
/sys/kernel/debug/dri/和modetest工具验证 KMS 对象状态。