4. CRTC核心数据结构:struct drm_crtc、struct drm_crtc_funcs、struct drm_crtc_state
在KMS(Kernel Mode Setting)框架中,CRTC(Cathode Ray Tube Controller)是显示管线的核心调度与时序控制单元。它负责从Framebuffer读取像素数据,按照设定的时序参数生成行/场同步信号,并将数据流送往Encoder。理解CRTC的三个核心数据结构——struct drm_crtc、struct drm_crtc_funcs和struct drm_crtc_state——是掌握CRTC初始配置与状态管理的前提。
核心要点:CRTC在KMS中扮演“显示控制器”角色,其数据结构设计遵循DRM的“对象-函数-状态”三元组模式,即一个对象(
drm_crtc)绑定一组操作函数(drm_crtc_funcs)和一个可变状态(drm_crtc_state)。
4.1 struct drm_crtc:CRTC对象结构体
struct drm_crtc是CRTC在内核中的核心对象,继承自drm_mode_object。它描述了CRTC的硬件属性、当前配置、绑定关系以及状态指针。在SA8155平台上,每个显示接口(如DP、DSI、HDMI)通常对应一个独立的CRTC实例。
| 成员变量 | 类型 | 说明 |
|---|---|---|
dev |
struct drm_device * |
指向所属DRM设备的指针 |
port |
struct device_node * |
设备树中对应的端口节点,用于解析硬件连接 |
funcs |
const struct drm_crtc_funcs * |
CRTC操作函数表,驱动必须实现 |
state |
struct drm_crtc_state * |
指向当前CRTC状态的指针(原子模式设置核心) |
primary |
struct drm_plane * |
主图层(Primary Plane),通常用于显示主帧缓冲 |
cursor |
struct drm_plane * |
光标图层(Cursor Plane),可选 |
enabled |
bool |
CRTC是否已启用(非原子模式使用,原子模式通过state判断) |
mode |
struct drm_display_mode |
当前设置的显示模式(非原子模式使用) |
base |
struct drm_mode_object |
DRM模式对象基类,提供ID和属性管理 |
SA8155实践提示:在SA8155的MDSS(Mobile Display Subsystem)中,每个CRTC对应一个硬件显示控制器(如DPU的Mixer)。初始化时,需要通过
drm_crtc_init_with_planes()将CRTC与Primary Plane和Cursor Plane绑定。
// CRTC初始化示例(SA8155 DPU驱动简化版)
struct drm_crtc *crtc;
int ret;
crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
if (!crtc)
return -ENOMEM;
// 绑定主图层和光标图层,并注册CRTC
ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, cursor_plane,
&msm_crtc_funcs, "primary_crtc");
if (ret) {
kfree(crtc);
return ret;
}
// 设置CRTC端口(用于设备树解析)
crtc->port = of_graph_get_port_by_id(dev->dev->of_node, 0);
4.2 struct drm_crtc_funcs:CRTC操作函数表
struct drm_crtc_funcs定义了驱动需要实现的CRTC操作回调。这些回调是KMS框架与硬件交互的接口,涵盖了CRTC的使能、模式设置、原子状态管理、属性控制等核心功能。
关键设计:在原子模式设置(Atomic Mode Setting)中,
atomic_check和atomic_flush(或atomic_begin/atomic_end)是驱动必须实现的两个核心回调,它们分别负责状态验证和硬件提交。
| 回调函数 | 作用 | 原子模式要求 |
|---|---|---|
set_config |
设置CRTC的显示模式(非原子模式入口) | 可选(原子模式通过atomic_check替代) |
destroy |
销毁CRTC对象,释放资源 | 必须实现 |
page_flip |
页面翻转,用于实现VBlank同步的缓冲区切换 | 必须实现(或通过atomic_flush实现) |
set_property |
设置CRTC属性(非原子模式) | 可选(原子模式通过atomic_set_property替代) |
atomic_duplicate_state |
复制CRTC状态,用于原子事务的状态快照 | 必须实现 |
atomic_destroy_state |
销毁CRTC状态 | 必须实现 |
atomic_set_property |
原子模式下设置CRTC属性 | 推荐实现(用于自定义属性) |
atomic_get_property |
原子模式下获取CRTC属性 | 推荐实现 |
enable_vblank |
使能VBlank中断 | 必须实现(用于页面翻转和性能监测) |
disable_vblank |
禁用VBlank中断 | 必须实现 |
// SA8155 CRTC函数表定义示例
static const struct drm_crtc_funcs msm_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.destroy = msm_crtc_destroy,
.page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = msm_crtc_duplicate_state,
.atomic_destroy_state = msm_crtc_destroy_state,
.atomic_set_property = msm_crtc_atomic_set_property,
.atomic_get_property = msm_crtc_atomic_get_property,
.enable_vblank = msm_crtc_enable_vblank,
.disable_vblank = msm_crtc_disable_vblank,
};
常见错误:在实现
atomic_duplicate_state时,必须调用__drm_atomic_helper_crtc_duplicate_state()来复制公共状态字段,否则会导致状态丢失或内存泄漏。同样,atomic_destroy_state中应调用__drm_atomic_helper_crtc_destroy_state()。
4.3 struct drm_crtc_state:CRTC原子状态
struct drm_crtc_state是原子模式设置的核心数据结构,它保存了CRTC在某一时刻的完整配置快照。KMS框架通过状态比较(drm_atomic_crtc_needs_modeset())来判断是否需要重新配置硬件。
| 成员变量 | 类型 | 说明 |
|---|---|---|
crtc |
struct drm_crtc * |
指向所属CRTC的指针 |
enable |
bool |
CRTC是否启用(原子模式替代drm_crtc.enabled) |
active |
bool |
CRTC是否处于激活状态(与power管理相关) |
mode |
struct drm_display_mode |
当前请求的显示模式 |
adjusted_mode |
struct drm_display_mode |
硬件调整后的模式(考虑时钟限制、边界调整等) |
mode_changed |
bool |
模式是否发生变化(由框架自动计算) |
active_changed |
bool |
激活状态是否发生变化 |
connectors_changed |
bool |
连接的Connector是否发生变化 |
plane_mask |
u32 |
位掩码,标识哪些Plane绑定到此CRTC |
event |
struct drm_pending_vblank_event * |
页面翻转事件,用于用户空间同步 |
state |
struct drm_atomic_state * |
指向所属原子事务状态的指针 |
// CRTC状态复制函数示例(SA8155扩展状态)
struct msm_crtc_state {
struct drm_crtc_state base; // 必须作为第一个成员
// SA8155私有扩展字段
u32 interface_type; // 接口类型:DP/DSI/HDMI
u32 mixer_id; // DPU Mixer硬件ID
bool dual_pipe; // 是否启用双管道模式
};
struct drm_crtc_state *msm_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct msm_crtc_state *state;
state = kmalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
// 复制公共状态字段
__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
// 复制私有字段
state->interface_type = to_msm_crtc_state(crtc->state)->interface_type;
state->mixer_id = to_msm_crtc_state(crtc->state)->mixer_id;
state->dual_pipe = to_msm_crtc_state(crtc->state)->dual_pipe;
return &state->base;
}
4.4 数据结构关系图
下图展示了CRTC三个核心数据结构之间的关联,以及它们与KMS框架中其他组件(Plane、Connector、Encoder)的关系。
4.5 原子状态管理流程
在原子模式设置中,CRTC的状态管理遵循“复制-修改-验证-提交”的流程。驱动通过drm_atomic_state事务来协调CRTC、Plane和Connector的状态变更。
- 状态复制:调用
atomic_duplicate_state创建当前状态的快照。 - 属性修改:通过
atomic_set_property修改状态中的特定字段(如mode、enable)。 - 原子检查:框架调用
drm_atomic_check_only,触发各个对象的atomic_check回调,验证状态组合的合法性。 - 硬件提交:通过
drm_atomic_commit提交状态,框架调用atomic_flush(或atomic_begin/atomic_end)将配置写入硬件寄存器。 - 状态替换:提交成功后,框架将
crtc->state指针指向新状态,旧状态被销毁。
// 原子模式设置中CRTC状态检查示例
static int msm_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
struct msm_crtc_state *msm_state = to_msm_crtc_state(state);
struct drm_display_mode *mode = &state->adjusted_mode;
int ret;
// 1. 检查模式时序是否在硬件支持范围内
ret = msm_dpu_mode_valid(crtc, mode);
if (ret)
return ret;
// 2. 检查接口类型与Mixer的兼容性
if (msm_state->interface_type == INTERFACE_DP &&
msm_state->mixer_id > MAX_DP_MIXER_ID)
return -EINVAL;
// 3. 检查Plane掩码是否有效
if (hweight32(state->plane_mask) > MAX_PLANES_PER_CRTC)
return -EINVAL;
return 0;
}
调试技巧:在SA8155开发中,可以通过
drm_atomic_crtc_needs_modeset(state)判断当前状态变更是否需要重新配置硬件时序。如果返回true,驱动必须在atomic_flush中执行完整的CRTC关闭-配置-重新使能序列。
4.6 关键差异对比
| 对比维度 | drm_crtc |
drm_crtc_funcs |
drm_crtc_state |
|---|---|---|---|
| 角色 | CRTC对象实例 | 操作接口定义 | 配置状态容器 |
| 生命周期 | 驱动加载时创建,卸载时销毁 | 静态常量,全局共享 | 每次原子提交创建,提交后销毁 |
| 可变性 | 部分字段可变(如state指针) | 不可变(const) | 可变(通过原子事务修改) |
| 存储位置 | 堆分配(kzalloc) | 代码段(.rodata) | 堆分配(kmalloc) |
| 核心作用 | 表示硬件CRTC | 提供硬件操作方法 | 保存原子配置快照 |
总结:在SA8155显示驱动开发中,
struct drm_crtc是CRTC的“身份证”,struct drm_crtc_funcs是CRTC的“操作手册”,struct drm_crtc_state是CRTC的“状态快照”。三者协同工作,构成了KMS框架中CRTC管理的基础。驱动开发者的核心任务就是正确实现这三个结构体,并确保它们之间的数据流和状态转换符合原子模式设置的规范。