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芯片
关键概念: 在KMS对象模型中,drm_crtc 是显示管线的“调度中心”,它必须绑定至少一个 drm_plane(Primary Plane)才能输出画面。Encoder和Connector之间可以插入多个Bridge,形成链式拓扑。

3.2 对象层次结构:显示管线拓扑

KMS对象之间的连接关系构成了一条完整的显示管线。从帧缓冲区到物理显示器,数据流经Plane → CRTC → Encoder → Bridge(s) → Connector。下图展示了典型的层次结构:

KMS对象层次结构图 KMS对象层次结构:显示管线拓扑 Framebuffer Plane 组(硬件图层) Primary Overlay Cursor CRTC(显示控制器) Encoder(编码器) Bridge 链(可选) Bridge A Bridge B Bridge C 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对象:

  1. 分配CRTC:调用 drm_crtc_init(),传入 drm_crtc_funcs 回调表。
  2. 分配Plane:调用 drm_universal_plane_init(),指定支持的像素格式和图层类型。
  3. 分配Encoder:调用 drm_encoder_init(),指定可能的编码类型(如 DRM_MODE_ENCODER_TMDS)。
  4. 分配Bridge:调用 drm_bridge_add(),或通过 devm_drm_bridge_add() 自动管理。
  5. 分配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的静态关联
注意: Bridge的绑定顺序至关重要。如果Bridge链中存在多个Bridge,必须按从Encoder到Connector的方向依次调用 drm_bridge_attach(),且每个Bridge的 next 指针必须正确设置。错误的绑定顺序会导致显示管线中断。

3.3.3 销毁阶段(Unbind/Remove)

当驱动卸载或设备移除时,KMS框架自动执行销毁流程。驱动通常只需调用 drm_dev_unregister() 和 drm_atomic_helper_shutdown(),框架会按创建顺序的逆序销毁对象:

  1. 先销毁Connector:调用 drm_connector_cleanup(),释放EDID缓存和热插拔资源。
  2. 再销毁Bridge链:调用 drm_bridge_remove(),断开所有Bridge连接。
  3. 然后销毁Encoder:调用 drm_encoder_cleanup()。
  4. 接着销毁CRTC:调用 drm_crtc_cleanup(),释放Vblank相关资源。
  5. 最后销毁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对象内部维护一个状态机,用于跟踪其生命周期阶段。下图展示了通用状态转换:

KMS对象生命周期状态机 KMS对象生命周期状态机 INIT(已分配) drm_*_init() REGISTERED(已注册) atomic_check() BOUND(已绑定) mode_set() ACTIVE(活跃) disable() drm_*_cleanup() drm_dev_unregister() DESTROYED(已销毁)
生命周期要点:
  • 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);
常见陷阱: Bridge的 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虚拟机显示
适配原则: 驱动开发者在实现KMS对象时,应遵循“一个硬件功能对应一个KMS对象”的原则。如果硬件将Encoder和Bridge集成在同一芯片中,仍然建议拆分为两个KMS对象,以保持框架的通用性和可扩展性。

3.7 本章小结

KMS对象模型通过CRTC、Encoder、Connector、Plane、Bridge五个核心对象,将复杂的显示硬件管线抽象为层次化的软件结构。生命周期管理遵循“创建→注册→绑定→活跃→销毁”的严格流程,其中Bridge对象的链式管理是驱动开发中的难点。理解这些对象的层次结构与生命周期,是编写稳定、可维护的GPU显示驱动的基石。