3. KMS (Kernel Mode Setting) 详解
KMS(Kernel Mode Setting)是 DRM 框架的核心子系统,负责在内核空间管理显示模式、分辨率、刷新率以及显示管线的连接状态。与传统的用户态模式设置(UMS)不同,KMS 将模式设置与显示缓冲区管理(GEM)分离,确保多应用环境下显示状态的一致性,并消除模式切换时的闪烁问题。
3.1 KMS 初始化流程
KMS 初始化发生在 DRM 设备驱动的 bind() 或 probe() 阶段,主要完成以下步骤:
- CRTC 初始化:创建 CRTC 对象,注册
mode_set、enable、disable等回调函数。 - Encoder 初始化:创建 Encoder 对象,指定可能的 CRTC 掩码(
possible_crtcs)。 - Connector 初始化:创建 Connector 对象,注册
get_modes、detect等回调。 - Plane 初始化:创建主平面(Primary Plane)和可能的叠加平面(Overlay/Cursor Plane)。
- 模式读取:通过 Connector 的
get_modes回调从 EDID 或固定时序表中读取显示模式。 - 默认模式设置:选择一个初始模式并调用 CRTC 的
mode_set进行首次配置。
drm_dev_register() 之前完成,否则用户态无法通过 drmModeGetResources() 获取到有效的显示资源。
get_modes 回调中手动添加 drm_mode_create() 创建的显示模式,并设置 type 为 DRM_MODE_TYPE_PREFERRED。
3.2 模式设置(Mode Setting)
模式设置是 KMS 的核心功能,指将一组显示参数(分辨率、刷新率、时钟、时序)应用到 CRTC 和 Encoder/Connector 链路的过程。用户态通过 drmModeSetCrtc() 或原子提交(Atomic Commit)触发模式设置。
3.2.1 显示模式结构
每个显示模式由 drm_display_mode 结构体描述,关键字段如下:
| 字段 | 含义 | 典型值(1080p60) |
|---|---|---|
hdisplay |
水平有效像素 | 1920 |
vdisplay |
垂直有效像素 | 1080 |
htotal |
水平总像素(含消隐) | 2200 |
vtotal |
垂直总像素(含消隐) | 1125 |
clock |
像素时钟(kHz) | 148500 |
vrefresh |
垂直刷新率(Hz) | 60 |
flags |
同步极性标志 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
3.2.2 模式设置流程
- 模式选择:从 Connector 的模式列表中选择一个匹配的
drm_display_mode。 - CRTC 配置:调用 CRTC 的
mode_set回调,配置时序发生器(TG)和像素时钟。 - Encoder 配置:调用 Encoder 的
mode_set回调,配置数据映射和编码格式。 - Connector 配置:调用 Connector 的
mode_set回调,配置物理接口参数(如 LVDS 电压、MIPI DSI 时序)。 - CRTC 使能:调用 CRTC 的
enable回调,启动时序输出。
- 像素时钟超出 LCD 控制器或面板的 PLL 范围。
- 水平/垂直消隐参数不符合面板规格。
- Encoder 的
possible_crtcs 掩码未正确设置,导致 CRTC 与 Encoder 不匹配。
3.3 显示参数配置
显示参数配置涉及 LCD 控制器硬件寄存器的设置,主要包括以下方面:
3.3.1 时序参数配置
LCD 控制器需要根据 drm_display_mode 计算并配置以下时序寄存器:
| 参数 | 寄存器字段 | 计算方式 |
|---|---|---|
| 水平同步宽度(HSPW) | HSYNC 脉冲宽度 | mode->hsync_end - mode->hsync_start |
| 水平后肩(HBP) | HSYNC 结束到有效数据 | mode->htotal - mode->hsync_end |
| 水平前肩(HFP) | 有效数据到 HSYNC 开始 | mode->hsync_start - mode->hdisplay |
| 垂直同步宽度(VSPW) | VSYNC 脉冲宽度 | mode->vsync_end - mode->vsync_start |
| 垂直后肩(VBP) | VSYNC 结束到有效数据 | mode->vtotal - mode->vsync_end |
| 垂直前肩(VFP) | 有效数据到 VSYNC 开始 | mode->vsync_start - mode->vdisplay |
3.3.2 像素时钟配置
像素时钟由 LCD 控制器的 PLL 产生,配置步骤通常为:
- 根据
mode->clock(单位 kHz)计算目标频率。 - 选择 PLL 的参考时钟源(如 24MHz 晶振)。
- 计算分频系数(M、N、K、OD)使输出频率接近目标值。
- 配置 PLL 寄存器并等待锁定。
- 将 PLL 输出连接到 LCD 控制器的像素时钟域。
3.3.3 接口时序配置
对于不同的 LCD 接口,需要额外配置:
- RGB 并行接口:数据使能(DE)极性、HSYNC/VSYNC 极性、数据位宽(16/18/24bit)。
- LVDS 接口:通道数(4/8 lane)、数据映射格式(JEIDA/VESA)、时钟相位。
- MIPI DSI 接口:虚拟通道、数据包格式、LP/HS 模式切换、时钟频率。
- eDP 接口:链路速率(1.62/2.7/5.4Gbps)、通道数、训练模式。
3.4 Vblank 同步机制
Vblank(垂直消隐期)是帧与帧之间的时间间隔,在此期间不会向 LCD 面板传输像素数据。KMS 利用 Vblank 实现以下关键功能:
- 页面翻转(Page Flip):在 Vblank 期间切换显示缓冲区,避免撕裂(Tearing)。
- 垂直同步(VSync):同步应用渲染帧率与显示刷新率。
- 帧统计:提供帧序号和时间戳,用于性能分析和自适应同步。
3.4.1 Vblank 中断处理
LCD 控制器在每帧的 Vblank 起始时刻产生硬件中断,KMS 的中断处理流程如下:
- 硬件触发 Vblank 中断。
- 中断服务程序(ISR)调用
drm_crtc_handle_vblank()。 - DRM 核心更新 CRTC 的 Vblank 计数和时间戳。
- 唤醒等待 Vblank 事件的用户态进程(通过
DRM_IOCTL_WAIT_VBLANK)。 - 触发已注册的 Vblank 回调(如页面翻转完成回调)。
3.4.2 Vblank 相关 API
| 函数/IOCTL | 用途 | 调用时机 |
|---|---|---|
drm_crtc_vblank_get() |
获取 Vblank 引用计数,使能 Vblank 中断 | 驱动初始化或页面翻转前 |
drm_crtc_vblank_put() |
释放 Vblank 引用计数,可关闭中断 | 页面翻转完成或 CRTC 关闭 |
drm_crtc_handle_vblank() |
通知 DRM 核心 Vblank 事件发生 | ISR 中调用 |
DRM_IOCTL_WAIT_VBLANK |
用户态等待下一个 Vblank | 应用渲染循环 |
DRM_IOCTL_PAGE_FLIP |
请求在下一个 Vblank 切换缓冲区 | 应用提交新帧 |
drm_crtc_vblank_off() 禁用 Vblank 中断,避免不必要的唤醒。在 CRTC 重新使能时调用 drm_crtc_vblank_on() 恢复。
3.5 原子模式设置(Atomic Mode Setting)
原子模式设置是 KMS 的进阶特性,允许在一次事务中同时提交多个 CRTC、Plane、Connector 的状态变更,确保所有变更同时生效或全部回滚。原子操作的核心数据结构为 drm_atomic_state,包含:
- CRTC 状态:模式、使能状态、Gamma 表。
- Plane 状态:Framebuffer、裁剪区域、位置、透明度。
- Connector 状态:连接状态、EDID 变更。
1. 用户态分配
drm_atomic_state 并添加对象。2. 调用
drm_atomic_check_only() 验证状态合法性。3. 调用
drm_atomic_commit() 提交变更。4. 驱动在 Vblank 中应用所有硬件寄存器更新。
5. 提交完成后通知用户态。
原子模式设置是现代 DRM 驱动(如 i915、msm、vc4)的标准实现方式,嵌入式 LCD 控制器驱动也逐步从传统 mode_set 回调迁移到