3. KMS (Kernel Mode Setting) 核心:KMS的作用、与FBDEV的区别、Atomic Modeset与Legacy Modeset对比

3.1 KMS 的核心作用

KMS(Kernel Mode Setting)是 DRM 框架中负责显示模式配置与管理的核心子系统。它将显示控制权从用户空间(X Server、Wayland Compositor)转移到内核空间,确保模式切换(分辨率、刷新率、图层叠加)的原子性与安全性。

KMS 的主要职责包括:

  • 显示模式管理:枚举显示器支持的时序参数(EDID 解析),设置分辨率、刷新率、色彩深度。
  • 平面(Plane)管理:管理硬件图层(Primary、Overlay、Cursor),控制每个平面的缓冲区地址、裁剪区域、透明度。
  • CRTC 控制:管理显示控制器(CRTC)的扫描时序、时钟源、帧缓冲区关联。
  • 连接器(Connector)管理:检测显示器热插拔(Hotplug)、获取物理连接状态(HDMI/DP/MIPI DSI)。
  • 内存管理:分配与释放帧缓冲区(FB)、处理 DMA-BUF 导入导出。
关键概念:KMS 将显示硬件抽象为 drm_framebuffer → drm_plane → drm_crtc → drm_encoder → drm_connector 五级管道,所有配置操作均通过 drm_mode_config 结构体协调。
KMS 核心架构图 用户空间 (Wayland / X11 / Weston) DRM IOCTL 系统调用层 (drmModeAtomicCommit / drmModeSetCrtc) KMS 核心 (drm_mode_config) 模式校验 | 状态对象管理 | 原子提交 | 事件通知 硬件抽象层 (drm_plane / drm_crtc / drm_encoder / drm_connector) 显示硬件 (DPU / HDMI TX / DSI Controller)

3.2 KMS 与 FBDEV 的区别

FBDEV(Framebuffer Device)是 Linux 内核早期的显示框架,仅提供简单的帧缓冲区操作接口。KMS 在功能、性能、安全性上全面超越 FBDEV,是当前嵌入式与桌面显示的主流方案。

对比维度 FBDEV KMS (DRM)
模式切换 通过 FBIOPUT_VSCREENINFO 切换,无校验,易撕裂 通过 drmModeSetCrtc 或原子提交,带完整校验与 VBlank 同步
多图层支持 仅单层(主帧缓冲),无硬件叠加 支持 Primary + Overlay + Cursor 多平面,硬件合成
热插拔检测 无原生支持,需轮询或外部机制 通过 drm_connector 的 HPD 中断,实时通知
内存管理 固定线性内存,无 DMA-BUF 支持 支持 GEM、DMA-BUF、显存分配与共享
多显示器 仅单显示输出,扩展需额外驱动 原生支持多 CRTC + 多 Connector,克隆/扩展/独立输出
用户空间接口 /dev/fbX,mmap 直接操作 /dev/dri/cardX,通过 IOCTL 操作,更安全
性能 CPU 频繁拷贝,功耗高 支持 Page Flip、零拷贝、GPU 合成
迁移建议:SA8155 平台已完全弃用 FBDEV,所有显示链路均基于 DRM/KMS。若遗留代码使用 fbdev 接口,需通过 modeset 库或直接调用 DRM IOCTL 重写。
FBDEV vs KMS 架构对比 FBDEV 架构 用户空间 (Xorg fbdev driver) /dev/fb0 (单帧缓冲) 显示硬件 (单通道) 局限:单层、无热插拔、CPU 拷贝 KMS 架构 用户空间 (Wayland / Weston) /dev/dri/card0 (DRM 主设备) KMS 管道 (Plane+CRTC+Encoder+Connector) 优势:多平面、原子提交、零拷贝、HPD

3.3 Atomic Modeset 与 Legacy Modeset 对比

KMS 提供两种模式设置接口:Legacy Modeset(传统模式)和 Atomic Modeset(原子模式)。Atomic 是 DRM 框架的现代标准,SA8155 平台强制要求使用 Atomic API。

3.3.1 Legacy Modeset 接口

Legacy 接口通过独立的 IOCTL 调用分别设置 CRTC、Plane、Connector:

  • drmModeSetCrtc() — 设置 CRTC 与帧缓冲绑定
  • drmModeSetPlane() — 设置平面位置与缓冲区
  • drmModeConnectorSetProperty() — 设置连接器属性

缺点:非原子性,多次调用间可能出现中间状态(撕裂、闪烁);无回滚机制;需用户空间自行保证调用顺序。

3.3.2 Atomic Modeset 接口

Atomic 接口通过一次 drmModeAtomicCommit() 调用提交完整的状态变更:

  • 构建 drmModeAtomicReq 对象,添加所有需要变更的属性
  • 内核校验整个状态的一致性(带宽、时钟、图层约束)
  • 支持 TEST_ONLY 标志进行预校验,不实际生效
  • 支持 NONBLOCK 异步提交,通过 event 通知完成
  • 失败时自动回滚,不改变当前显示状态
SA8155 平台强制要求:所有显示配置必须使用 Atomic Modeset。Legacy 接口在 DPU 驱动中已被标记为 deprecated,调用会返回 -ENOTSUPP。
对比维度 Legacy Modeset Atomic Modeset
调用方式 多次独立 IOCTL 单次 drmModeAtomicCommit
原子性 无,中间状态可见 全有或全无,无中间状态
回滚 需用户手动恢复 内核自动回滚
预校验 不支持 支持 DRM_MODE_ATOMIC_TEST_ONLY
异步提交 不支持 支持 DRM_MODE_PAGE_FLIP_EVENT
属性支持 有限(位置、大小、FB ID) 所有 KMS 属性(alpha、zpos、color_encoding、scaling)
性能 多次上下文切换,延迟高 单次调用,延迟低,适合高帧率

3.3.3 Atomic 提交流程示例

// 1. 创建 atomic request
drmModeAtomicReq *req = drmModeAtomicAlloc();

// 2. 添加属性变更
drmModeAtomicAddProperty(req, crtc_id, crtc_active_prop, 1);
drmModeAtomicAddProperty(req, crtc_id, mode_id_prop, mode_blob_id);
drmModeAtomicAddProperty(req, plane_id, src_x_prop, 0);
drmModeAtomicAddProperty(req, plane_id, src_y_prop, 0);
drmModeAtomicAddProperty(req, plane_id, crtc_id_prop, crtc_id);
drmModeAtomicAddProperty(req, conn_id, crtc_id_prop, crtc_id);

// 3. 提交(带预校验)
int ret = drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
if (ret) {
    // 校验失败,处理错误
    drmModeAtomicFree(req);
    return ret;
}

// 4. 实际提交(异步)
ret = drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_NONBLOCK |
                          DRM_MODE_PAGE_FLIP_EVENT, &user_data);
drmModeAtomicFree(req);
调试陷阱:Atomic 提交失败时,通过 drmModeAtomicCommit 返回的 errno 判断原因。常见错误:-EINVAL(属性值非法)、-ENOSPC(带宽超限)、-EACCES(权限不足)。在 SA8155 上,dmesg 中 DPU 驱动会打印详细的校验失败日志。
Atomic Modeset vs Legacy Modeset 流程对比 Legacy Modeset 流程 1. drmModeSetCrtc() 2. drmModeSetPlane() 3. drmModeConnectorSetProperty() 中间状态:可能撕裂/闪烁 4. 最终生效(无回滚) Atomic Modeset 流程 1. drmModeAtomicAlloc() 2. 添加所有属性变更 3. TEST_ONLY 预校验 4. drmModeAtomicCommit() 5. 原子生效 / 自动回滚

3.4 SA8155 平台 KMS 调试要点

在 SA8155 平台上调试 KMS 时,重点关注以下工具与接口:

  • modetest:libdrm 提供的测试工具,可枚举 Connector、CRTC、Plane,执行 Legacy 或 Atomic 模式设置。
  • dmesg:DPU 驱动(msm_dpu)的调试日志,通过 drm.debug=0x1e 内核参数开启。
  • sysfs 接口:/sys/kernel/debug/dri/0/ 下查看 KMS 状态、VBlank 计数、带宽使用。
  • Atomic 校验日志:当 Atomic 提交失败时,驱动会在 dmesg 中打印 [dpu] 前缀的详细原因。
快速验证命令:modetest -M msm_dpu -a 以 Atomic 模式枚举所有 KMS 对象;modetest -M msm_dpu -s 42:1920x1080@60 -a 设置指定 Connector 的分辨率。