2. 显示驱动框架:Linux DRM框架介绍、MSM DRM驱动架构、SA8155显示驱动代码结构
2.1 Linux DRM框架概述
DRM(Direct Rendering Manager)是Linux内核中负责图形显示与渲染管理的标准框架。它向上提供统一的用户空间接口(通过/dev/dri/card0设备节点),向下抽象GPU、Display Controller、Encoder、Connector等硬件单元。
核心设计理念: DRM将显示管线拆解为若干个可组合的抽象对象,驱动开发者只需实现对应的回调函数,框架自动完成状态管理、原子提交、事件通知等复杂逻辑。
2.1.1 DRM核心对象模型
| 对象 | 角色 | 对应硬件 | 关键操作 |
|---|---|---|---|
| CRTC | 显示控制器,负责扫描输出与时序生成 | DPU硬件管线(Mixer + PingPong + P010) | mode_set、atomic_flush、enable/disable |
| Plane | 图层叠加单元,支持多个图层混合 | DPU SSPP(Source Surface Processor Pipe) | update_plane、disable_plane、atomic_check |
| Encoder | 编码器,将CRTC输出的像素流转换为物理接口信号 | DPU INTF(Interface)模块 | mode_fixup、atomic_mode_set |
| Connector | 物理连接器,检测显示器热插拔与EDID信息 | HDMI、DP、DSI物理接口 | detect、get_modes、atomic_get_property |
| Bridge | 桥接芯片,用于信号转换(如DP转HDMI) | 外部显示桥片 | pre_enable、enable、disable |
开发提示: 在SA8155平台上,CRTC与DPU硬件管线是1:1映射关系。一个CRTC对应一个DPU硬件实例,包含完整的Mixer → PingPong → INTF数据通路。
2.1.2 DRM原子提交(Atomic Commit)
DRM原子提交是SA8155显示驱动开发中必须掌握的核心机制。它保证多个显示对象的状态更新在同一个VBlank周期内同步生效,避免撕裂(Tearing)和闪烁。
- 非原子模式(Legacy): 每个对象单独提交,无法保证时序同步,已逐步淘汰。
- 原子模式(Atomic): 驱动实现
atomic_check和atomic_flush回调,用户空间通过DRM_IOCTL_MODE_ATOMIC一次性提交完整状态。 - 状态对象:
drm_crtc_state、drm_plane_state、drm_connector_state,驱动可在其中携带私有硬件状态。
// 原子提交流程(用户空间侧)
struct drm_mode_atomic atomic = {0};
atomic.flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
atomic.count_objs = 3; // CRTC + Plane + Connector
atomic.objs_ptr = (uint64_t)objs;
atomic.count_props_ptr = (uint64_t)count_props;
atomic.props_ptr = (uint64_t)props;
atomic.values_ptr = (uint64_t)values;
int ret = drmIoctl(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
if (ret) {
// 原子提交失败,整个状态回滚
handle_atomic_fail();
}
2.2 MSM DRM驱动架构
MSM DRM是Qualcomm平台在Linux内核中的显示驱动实现,位于drivers/gpu/drm/msm/目录。它同时管理Adreno GPU和DPU显示控制器,SA8155使用的正是MSM DRM框架。
2.2.1 MSM DRM关键数据结构
| 数据结构 | 作用 | 所属模块 |
|---|---|---|
msm_drm_private |
MSM DRM全局私有数据,管理KMS实例、GEM对象、Fence上下文 | msm_drv |
msm_kms |
KMS(Kernel Mode Setting)抽象接口,提供enable_vblank、prepare_commit等回调 |
msm_kms |
dpu_kms |
DPU子驱动的主结构体,包含硬件目录、时钟、中断、IRQ域 | dpu_kms |
dpu_crtc |
DPU CRTC实现,管理Mixer、PingPong、CTL硬件块 | dpu_crtc |
dpu_hw_ctl |
硬件控制块抽象,负责启动/停止显示管线、触发刷新 | dpu_hw_ctl |
2.3 SA8155显示驱动代码结构
SA8155的显示驱动代码位于drivers/gpu/drm/msm/disp/dpu1/目录,这是整个课程最常打交道的代码区域。下面列出核心文件及其职责:
2.3.1 核心文件功能速查表
| 文件名 | 功能描述 | 课程关注度 |
|---|---|---|
dpu_kms.c |
DPU KMS初始化、模式设置入口、全局资源管理 | ⭐⭐⭐ |
dpu_crtc.c |
CRTC实现,包含dpu_crtc_atomic_flush、dpu_crtc_vblank_cb等核心回调 |
⭐⭐⭐⭐⭐ |
dpu_plane.c |
图层管理,SSPP硬件配置、源裁剪、缩放、格式转换 | ⭐⭐⭐⭐ |
dpu_encoder.c |
编码器实现,管理INTF接口、帧完成中断、传输模式 | ⭐⭐⭐ |
dpu_hw_ctl.c |
硬件控制块,负责显示管线启动/停止、刷新触发、安全模式 | ⭐⭐⭐⭐ |
dpu_hw_intf.c |
接口硬件抽象,配置时序参数、分辨率、像素时钟 | ⭐⭐⭐⭐ |
dpu_power.c |
电源与时钟管理,时钟频率配置、使能/禁能、带宽投票 | ⭐⭐⭐⭐⭐ |
dpu_hw_catalog.c |
硬件目录,定义SA8155支持的DPU硬件块列表与能力 | ⭐⭐ |
2.3.2 代码调用链路示例:CRTC使能流程
当用户空间通过DRM原子提交使能CRTC时,驱动内部会经历以下调用链:
- dpu_crtc_atomic_enable() → 设置CRTC状态为启用,启动VBlank定时器
- dpu_crtc_setup_mixer() → 配置Mixer与PingPong硬件块
- dpu_encoder_prepare() → 准备编码器,配置INTF接口参数
- dpu_power_clk_enable() → 使能DPU时钟域,设置时钟频率
- dpu_hw_ctl_start() → 启动硬件控制块,开始扫描输出
// dpu_crtc_atomic_enable 简化代码片段
static void dpu_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(dpu_crtc);
// 1. 使能时钟
dpu_power_clk_enable(&dpu_kms->power, DPU_CLK_AHB);
dpu_power_clk_set_rate(&dpu_kms->power, DPU_CLK_CORE, dpu_crtc->cur_mode->clock * 1000);
// 2. 配置Mixer
dpu_crtc_setup_mixer(dpu_crtc, crtc->state);
// 3. 启动硬件控制块
dpu_hw_ctl_start(dpu_crtc->hw_ctl, DPU_CTL_MODE_VIDEO);
// 4. 使能VBlank
drm_crtc_vblank_on(crtc);
}
⚠️ 时钟配置陷阱: SA8155的DPU时钟域包含多个时钟源(core_clk、ahb_clk、axi_clk、vsync_clk等),
dpu_power_clk_set_rate()必须在时钟使能之后调用,且频率值必须与硬件目录中定义的频率表匹配,否则会导致显示黑屏或时序异常。
2.4 本章小结
- DRM框架 提供了CRTC、Plane、Encoder、Connector四大抽象对象,原子提交机制是SA8155显示驱动的核心交互方式。
- MSM DRM架构 分为用户空间 → DRM核心 → MSM驱动 → DPU/Adreno子驱动 → 硬件抽象层五层,每层职责清晰。
- SA8155代码结构 集中在
dpu1/目录,dpu_crtc.c和dpu_power.c是时钟配置实践中最常修改的文件。 - 下一章将深入DPU硬件管线,详细拆解Mixer、PingPong、INTF、SSPP等硬件模块的工作原理与寄存器配置。