3. KMS对象模型:CRTC、Encoder、Connector、Plane、Bridge的对象层次结构与生命周期管理
KMS(Kernel Mode Setting)是Linux内核显示子系统的核心框架,它通过一组标准化的对象模型抽象了显示硬件管线。理解CRTC、Encoder、Connector、Plane、Bridge这五大对象的层次结构与生命周期,是开发GPU驱动的基础。
3.1 五大核心对象概述
KMS对象模型将显示管线拆解为五个逻辑组件,每个组件对应一个内核数据结构,并通过DRM框架统一管理。下表列出了各对象的职责与核心数据结构:
| 对象 | 内核结构体 | 职责描述 | 硬件对应 |
|---|---|---|---|
| CRTC | drm_crtc |
控制显示时序、扫描输出、帧缓冲区切换 | 显示控制器(Display Controller) |
| Encoder | drm_encoder |
将像素数据编码为特定接口信号(如LVDS、HDMI、DP) | 编码器芯片(如eDP Transmitter) |
| Connector | drm_connector |
代表物理连接器,检测热插拔、读取EDID | HDMI/DP/VGA物理接口 |
| Plane | drm_plane |
管理硬件图层(Overlay/Primary/Cursor),支持合成 | 硬件图层引擎(如Sprite/Overlay) |
| Bridge | drm_bridge |
连接Encoder与Connector之间的信号转换/调理芯片 | 电平转换器、MIPI桥片、HDMI转DP芯片 |
drm_crtc 是显示管线的“调度中心”,它必须绑定至少一个 drm_plane(Primary Plane)才能输出画面。Encoder和Connector之间可以插入多个Bridge,形成链式拓扑。
3.2 对象层次结构:显示管线拓扑
KMS对象之间的连接关系构成了一条完整的显示管线。从帧缓冲区到物理显示器,数据流经Plane → CRTC → Encoder → Bridge(s) → Connector。下图展示了典型的层次结构:
- 一个CRTC可以绑定多个Plane(至少1个Primary Plane),但一个Plane只能属于一个CRTC。
- 一个Encoder只能连接一个CRTC,但可以连接多个Connector(通过Bridge复用)。
- Bridge可以形成链式拓扑,典型场景:MIPI DSI → 电平转换Bridge → eDP Bridge → eDP Connector。
- Connector是管线的终点,直接对应物理接口。
3.3 生命周期管理:创建、绑定与销毁
KMS对象的生命周期由DRM核心框架驱动,GPU驱动只需在初始化/卸载时注册和注销对象。生命周期分为三个阶段:
3.3.1 创建阶段(Probe/Init)
在驱动的 bind() 或 probe() 回调中,驱动按以下顺序创建KMS对象:
- 分配CRTC:调用
drm_crtc_init(),传入drm_crtc_funcs回调表。 - 分配Plane:调用
drm_universal_plane_init(),指定支持的像素格式和图层类型。 - 分配Encoder:调用
drm_encoder_init(),指定可能的编码类型(如DRM_MODE_ENCODER_TMDS)。 - 分配Bridge:调用
drm_bridge_add(),或通过devm_drm_bridge_add()自动管理。 - 分配Connector:调用
drm_connector_init(),注册热插拔检测回调。
// 典型创建流程示例(伪代码)
struct drm_crtc *crtc = drm_crtc_alloc(dev);
drm_crtc_init(dev, crtc, &crtc_funcs);
struct drm_plane *primary = drm_plane_alloc(dev);
drm_universal_plane_init(dev, primary, 0, &plane_funcs,
formats, num_formats,
DRM_PLANE_TYPE_PRIMARY, NULL);
struct drm_encoder *encoder = drm_encoder_alloc(dev);
drm_encoder_init(dev, encoder, &encoder_funcs,
DRM_MODE_ENCODER_DP, NULL);
struct drm_bridge *bridge = devm_drm_bridge_alloc(dev, sizeof(*bridge));
drm_bridge_add(bridge);
struct drm_connector *connector = drm_connector_alloc(dev);
drm_connector_init(dev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort);
3.3.2 绑定阶段(Mode Set)
当用户空间通过 drmModeSetCrtc() 或 atomic_check() 提交配置时,KMS框架执行对象绑定:
| 绑定操作 | API/回调 | 说明 |
|---|---|---|
| Plane → CRTC | drm_atomic_set_crtc_for_plane() |
将Plane关联到目标CRTC,设置显示位置和裁剪区域 |
| CRTC → Encoder | drm_atomic_set_encoder_for_crtc() |
CRTC输出连接到指定Encoder |
| Encoder → Bridge | drm_bridge_attach() |
将Bridge挂接到Encoder的输出链上 |
| Bridge → Connector | drm_bridge_connector_init() |
Bridge链的末端连接到Connector |
| Connector → Encoder | drm_connector_attach_encoder() |
建立Connector与Encoder的静态关联 |
drm_bridge_attach(),且每个Bridge的 next 指针必须正确设置。错误的绑定顺序会导致显示管线中断。
3.3.3 销毁阶段(Unbind/Remove)
当驱动卸载或设备移除时,KMS框架自动执行销毁流程。驱动通常只需调用 drm_dev_unregister() 和 drm_atomic_helper_shutdown(),框架会按创建顺序的逆序销毁对象:
- 先销毁Connector:调用
drm_connector_cleanup(),释放EDID缓存和热插拔资源。 - 再销毁Bridge链:调用
drm_bridge_remove(),断开所有Bridge连接。 - 然后销毁Encoder:调用
drm_encoder_cleanup()。 - 接着销毁CRTC:调用
drm_crtc_cleanup(),释放Vblank相关资源。 - 最后销毁Plane:调用
drm_plane_cleanup()。
// 销毁阶段示例(驱动 unbind 回调)
static void my_driver_unbind(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
// 1. 停止所有显示输出
drm_atomic_helper_shutdown(drm_dev);
// 2. 注销DRM设备(框架自动清理KMS对象)
drm_dev_unregister(drm_dev);
drm_dev_put(drm_dev);
}
3.4 对象生命周期状态机
每个KMS对象内部维护一个状态机,用于跟踪其生命周期阶段。下图展示了通用状态转换:
- INIT → REGISTERED:对象分配后必须注册到DRM框架,否则无法被用户空间发现。
- REGISTERED → BOUND:通过Atomic Commit或Legacy Mode Set建立对象间的连接关系。
- BOUND → ACTIVE:CRTC开始输出时序,Plane开始扫描帧缓冲区,Encoder和Bridge开始传输数据。
- ACTIVE → BOUND:禁用显示输出(如DPMS Off),但保留绑定关系。
- DESTROYED:对象内存被释放,不可再访问。
3.5 Bridge对象的特殊生命周期
Bridge对象在KMS模型中具有特殊的生命周期管理需求,因为它可以独立于Encoder和Connector存在,并且支持热插拔。Bridge的生命周期包含以下关键点:
- 独立注册:Bridge通过
drm_bridge_add()注册到全局Bridge列表,不依赖其他KMS对象。 - 延迟绑定:Bridge可以在Encoder初始化之后、Connector初始化之前的任意时刻通过
drm_bridge_attach()绑定到Encoder。 - 链式管理:多个Bridge形成链表,每个Bridge的
next指针指向下一个Bridge。框架通过drm_bridge_chain_mode_set()遍历整个链。 - 热插拔支持:Bridge可以实现
detect回调,用于检测下游设备(如显示器)的连接状态。
// Bridge链式绑定示例
struct drm_bridge *bridge_a, *bridge_b, *bridge_c;
// 注册所有Bridge
drm_bridge_add(bridge_a);
drm_bridge_add(bridge_b);
drm_bridge_add(bridge_c);
// 按顺序绑定到Encoder
drm_bridge_attach(encoder, bridge_a, NULL); // bridge_a 是链头
drm_bridge_attach(encoder, bridge_b, bridge_a); // bridge_b 跟在 bridge_a 后面
drm_bridge_attach(encoder, bridge_c, bridge_b); // bridge_c 是链尾
// 框架遍历链时自动调用每个Bridge的 mode_set
drm_bridge_chain_mode_set(bridge_a, &mode, &adjusted_mode);
drm_bridge_attach() 第二个参数 previous 必须正确传递。如果传递 NULL,则Bridge成为链头;如果传递前一个Bridge的指针,则插入到链中。错误的 previous 会导致链断裂,显示管线无法正常工作。
3.6 对象模型与硬件适配的映射关系
KMS对象模型的设计目标之一是屏蔽硬件差异,提供统一的用户空间接口。下表总结了不同硬件架构下对象模型的适配方式:
| 硬件架构 | CRTC实现 | Encoder实现 | Bridge实现 | 典型场景 |
|---|---|---|---|---|
| 集成GPU(如Intel i915) | 显示管道(Pipe A/B/C) | 集成Transcoder | 通常不需要Bridge | 笔记本内置显示屏 |
| 独立GPU(如AMD Radeon) | DCE/DCN控制器 | 外部TMDS/DP编码器 | 电平转换Bridge | 外接显示器 |
| 嵌入式SoC(如Rockchip) | VOP(Video Output Processor) | MIPI DSI/HDMI TX | MIPI D-PHY Bridge、eDP Bridge | 平板电脑、车载显示 |
| 虚拟化/模拟器(如virtio-gpu) | 虚拟CRTC | 虚拟Encoder | 无Bridge | QEMU虚拟机显示 |
3.7 本章小结
KMS对象模型通过CRTC、Encoder、Connector、Plane、Bridge五个核心对象,将复杂的显示硬件管线抽象为层次化的软件结构。生命周期管理遵循“创建→注册→绑定→活跃→销毁”的严格流程,其中Bridge对象的链式管理是驱动开发中的难点。理解这些对象的层次结构与生命周期,是编写稳定、可维护的GPU显示驱动的基石。