2. DRM/KMS核心对象建模
在 i.MX 平台上,DRM/KMS 并不是一组彼此独立的驱动文件,而是一棵由 drm_device 统领、通过对象指针相互引用的显示管线模型。理解这六个核心对象在 i.MX 驱动中的实例化顺序、绑定关系与生命周期,是后续排查“屏幕不亮”“分辨率不对”“图层错位”等问题的前提。本节以 i.MX8M 系列(如 i.MX8MM/i.MX8MP)的 imx-drm 与 dw-mipi-dsi、nwl-dsi、imx-lcdif 等驱动为背景,说明这些对象“是什么、谁创建、谁连接、何时销毁”。
一、六个对象的职责边界
drm_device 是整棵显示树的根容器,它持有 mode_config、对象 IDR、文件句柄与中断管理。在 i.MX 上,它通常由 imx_drm_bind() 通过 drm_dev_alloc() 创建,并在所有子设备(CRTC、encoder、connector、plane、bridge)注册完成后调用 drm_dev_register() 暴露给用户空间。
drm_crtc 代表“扫描输出控制器”,负责从 framebuffer 取像素、按 mode 时序产生扫描信号。i.MX8MP 的 LCDIF、i.MX8MM 的 DPR/显示控制器都会注册为 CRTC。它持有 primary plane,并通过 possible_crtcs 与 encoder 建立候选关系。
drm_encoder 是“时序编码器”,把 CRTC 输出的并行像素流转换为某种物理接口时序(如 MIPI DSI、LVDS、HDMI TMDS)。在 i.MX 中,encoder 常由 dw_mipi_dsi_bind() 或 imx_ldb_bind() 创建,并通过 drm_encoder_init() 注册。
drm_connector 是“物理连接点”,描述显示器如何接入、支持哪些 mode、当前连接状态(connected/disconnected)。它通过 drm_connector_attach_encoder() 与 encoder 绑定,是用户空间查询 EDID、设置 mode 的入口。
drm_plane 是“图层”,承载 framebuffer 并参与合成。i.MX 的 IPU/DPU/LCDIF 通常提供 primary、overlay、cursor 三类 plane,通过 drm_universal_plane_init() 注册,并用 possible_crtcs 限定可挂载的 CRTC。
drm_bridge 是“可级联的转换器”,用于把 encoder 输出再经过一级转换(如 DSI-to-HDMI、LVDS serializer、MIPI DPHY 时序调整)。i.MX 的 dw-mipi-dsi 常以 bridge 形式挂在 encoder 与 connector 之间,形成 encoder → bridge → connector 的链式结构。
二、i.MX 中的实例化关系
在设备树中,显示管线通常写成 lcdif → mipi_dsi → panel 或 lcdif → ldb → panel 的 of_graph 端点连接。驱动 probe 时,各子驱动先创建自己的对象,再由 imx-drm 的 bind 回调统一装配。典型顺序是:
- 各 CRTC 驱动(如
imx-lcdif)probe,创建drm_crtc与drm_plane,并保存到私有结构; - encoder/bridge 驱动(如
dw-mipi-dsi)probe,创建drm_encoder与drm_bridge; - panel 驱动 probe,创建
drm_panel,并在 connector 驱动中注册drm_connector; imx_drm_bind()调用drm_dev_alloc()创建drm_device,随后依次调用各子模块的bind回调,把 CRTC、plane、encoder、bridge、connector 挂入 device;- 最后
drm_dev_register()与drm_connector_register()完成注册,用户空间即可通过/dev/dri/card0访问。
对象之间的引用关系可以概括为:drm_device 持有全部对象;drm_crtc 通过 possible_crtcs 被 encoder 选择;drm_encoder 通过 drm_bridge_attach() 连接 bridge;drm_connector 通过 drm_connector_attach_encoder() 绑定 encoder;drm_plane 通过 possible_crtcs 与 CRTC 关联。这种“多对多候选、运行时确定”的模型,正是 KMS 能支持多屏、多图层灵活组合的基础。
三、生命周期与销毁顺序
对象的生命周期与创建顺序相反:当设备解绑或模块卸载时,imx_drm_unbind() 先调用 drm_dev_unregister() 停止用户空间访问,再依次调用各子模块的 unbind 回调,最后 drm_dev_put() 释放 drm_device。此时 CRTC、plane、encoder、bridge、connector 的引用计数归零,各自释放内存。需要特别注意的是,drm_connector 与 drm_bridge 常被 panel 驱动或 PHY 驱动持有额外引用,若销毁顺序不当,容易出现 use-after-free 或“屏幕已关但时钟未停”的问题。
在 i.MX8MP 上,一个典型的 MIPI-DSI 显示管线在 /sys/kernel/debug/dri/0/ 下可以看到 crtc-0、encoder-0、connector-0、plane-0/1/2 等节点,它们正是上述对象在 debugfs 中的映射。通过 cat /sys/kernel/debug/dri/0/state 可以观察当前 CRTC 的 mode、connector 的连接状态以及 plane 的 framebuffer 绑定情况,这是验证对象关系是否正确建立的最直接手段。
drm_device 是唯一的根,其余对象都通过 possible_crtcs、attach_encoder、bridge_attach 等接口挂接到这棵树上。调试显示问题时,先确认对象是否成功注册,再确认引用关系是否与设备树 of_graph 一致,往往能快速定位问题所在。