4. SA8155 DRM驱动初始化:msm_drm_init流程、设备树(DTS)解析、MDSS驱动加载顺序
本章深入分析SA8155平台DRM子系统的启动流程,重点围绕msm_drm_init函数执行路径、设备树(DTS)解析机制以及MDSS(Mobile Display Subsystem)驱动的加载顺序展开。理解这一初始化链路是后续进行HDR显示配置与调试的基础。
4.1 msm_drm_init 主流程
msm_drm_init 是SA8155 DRM驱动的入口函数,位于 drivers/gpu/drm/msm/msm_drv.c。该函数负责完成DRM设备的注册、组件绑定以及核心对象的初始化。
以下为 msm_drm_init 的主要执行步骤:
- 平台驱动探测:当DTS中匹配到
qcom,mdss节点时,触发mdss_probe,进而调用msm_drm_init。 - DRM设备分配:调用
drm_dev_alloc分配drm_device结构体,并设置驱动私有数据。 - 组件绑定:通过
component_bind_all绑定MDSS下的所有子组件(如DPU、DSI、HDMI等)。 - 模式配置初始化:调用
msm_drm_modeset_init,创建CRTC、Encoder、Connector和Plane。 - GPU初始化:如果平台包含GPU节点,则初始化GPU子系统。
- DRM设备注册:调用
drm_dev_register将设备注册到内核,并创建对应的字符设备。
msm_drm_init() → component_bind_all() → msm_drm_modeset_init() → drm_dev_register()
4.2 设备树(DTS)解析
SA8155平台使用设备树来描述硬件拓扑。DRM驱动通过解析DTS获取显示控制器的寄存器地址、中断号、时钟频率、接口类型等关键参数。核心节点位于 qcom,mdss 下。
以下为SA8155显示相关DTS节点的典型结构:
// SA8155 MDSS DTS 节点示例
mdss: mdss@ae00000 {
compatible = "qcom,mdss";
reg = <0x0ae00000 0x1000>;
reg-names = "mdss_phys";
clocks = <&gcc GCC_DISP_AHB_CLK>,
<&gcc GCC_DISP_AXI_CLK>;
clock-names = "iface", "bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
dpu: dpu@ae01000 {
compatible = "qcom,sdm845-dpu";
reg = <0x0ae01000 0x8f000>,
<0x0aeb0000 0x2008>;
reg-names = "mdp_phys", "vbif_phys";
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_DISP_MDP_CLK>;
clock-names = "bus";
};
dsi0: dsi@ae94000 {
compatible = "qcom,mdss-dsi-ctrl";
reg = <0x0ae94000 0x400>;
reg-names = "dsi_ctrl";
clocks = <&gcc GCC_DISP_BYTE0_CLK>;
clock-names = "byte";
phys = <&dsi0_phy>;
phy-names = "dsi";
};
hdmi: hdmi@ae90000 {
compatible = "qcom,mdss-hdmi-tx";
reg = <0x0ae90000 0x10000>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
hpd-gpios = <&tlmm 34 GPIO_ACTIVE_HIGH>;
};
};
DTS解析的关键函数与对应关系如下表:
| DTS节点 | 解析函数 | 获取的资源 |
|---|---|---|
| mdss | mdss_probe() | 顶层寄存器、时钟、中断 |
| dpu | dpu_bind() | MDP寄存器、VBIF、中断 |
| dsi0 / dsi1 | msm_dsi_host_init() | DSI控制器寄存器、PHY、时钟 |
| hdmi | msm_hdmi_bind() | HDMI TX寄存器、HPD GPIO |
status = "disabled" 的节点不会被驱动探测。若DSI或HDMI接口未使能,需检查对应节点的status属性是否设置为 "okay"。
4.3 MDSS驱动加载顺序
MDSS(Mobile Display Subsystem)是SA8155显示子系统的顶层硬件模块,包含DPU、DSI、HDMI、DP等多个IP核。驱动的加载顺序遵循先父后子、先依赖后被依赖的原则。
加载顺序由 component 框架保证,具体流程如下:
- 步骤1:平台总线匹配到
qcom,mdss节点,执行mdss_probe(),注册MDSS顶层设备。 - 步骤2:MDSS驱动调用
of_platform_populate(),扫描DTS中子节点,触发子设备的平台驱动探测。 - 步骤3:各子设备驱动(DPU、DSI、HDMI等)在
probe中调用component_add(),将自己注册为组件。 - 步骤4:当所有必需的组件都添加完成后,
component_master_ops.bind回调被触发,执行msm_drm_init中的组件绑定。
下表总结了各子模块的加载顺序与依赖关系:
| 加载顺序 | 模块名称 | 依赖关系 | 初始化函数 |
|---|---|---|---|
| 1 | MDSS (顶层) | 无 | mdss_probe() |
| 2 | DPU (显示处理单元) | MDSS时钟、寄存器 | dpu_bind() |
| 3 | DSI PHY | DPU接口 | msm_dsi_phy_probe() |
| 4 | DSI 控制器 | DSI PHY | msm_dsi_host_init() |
| 5 | HDMI TX | DPU接口 | msm_hdmi_bind() |
| 6 | DisplayPort | DPU接口 | msm_dp_bind() |
/sys/kernel/debug/component 下可以查看当前系统中所有组件的注册状态。如果某个组件未注册,DRM初始化将卡在 component_bind_all 处。
4.4 组件化绑定与回调机制
SA8155 DRM驱动使用Linux内核的 component 框架来管理多个子设备之间的依赖关系。该框架通过 component_master 和 component 两个角色实现解耦。
关键数据结构与回调函数如下:
// 组件主设备结构体
static const struct component_master_ops msm_drm_ops = {
.bind = msm_drm_bind,
.unbind = msm_drm_unbind,
};
// 子组件添加示例 (DPU)
static const struct component_ops dpu_component_ops = {
.bind = dpu_bind,
.unbind = dpu_unbind,
};
// 在 dpu_probe 中注册组件
static int dpu_probe(struct platform_device *pdev)
{
// ... 初始化硬件资源 ...
return component_add(&pdev->dev, &dpu_component_ops);
}
组件绑定流程的时序图如下:
4.5 初始化过程中的常见问题与调试方法
在SA8155平台DRM驱动初始化过程中,开发者常遇到以下问题:
| 问题现象 | 可能原因 | 调试方法 |
|---|---|---|
| drm_dev_register 失败 | DTS中缺少必要的时钟或中断资源 | 检查 dmesg 中的 EPROBE_DEFER 信息 |
| component_bind_all 超时 | 某个子设备未注册组件 | 查看 /sys/kernel/debug/component 确认组件状态 |
| CRTC/Encoder 创建失败 | DPU 初始化异常或接口类型不匹配 | 添加 drm.debug=0x1e 内核参数,查看DRM日志 |
| 显示无输出 | DSI/HDMI 节点 status 为 disabled | 检查DTS中对应节点的 status 属性 |
# cat /sys/kernel/debug/component/devices — 查看所有注册的组件# cat /sys/kernel/debug/dri/0/state — 查看DRM状态# dmesg | grep msm — 过滤MSM驱动日志
通过以上分析,开发者应能清晰理解SA8155平台DRM驱动的初始化流程、DTS解析机制以及MDSS驱动的加载顺序。这些知识是后续进行HDR显示配置与调试的基础。