4、KMS驱动初始化流程:瑞芯微平台drm驱动probe流程,组件绑定与设备树解析
本章深入剖析瑞芯微平台 DRM/KMS 驱动的初始化流程,重点聚焦 probe 阶段、组件绑定机制以及设备树解析过程。理解这一流程是进行显示模式配置与调试的基础,也是掌握整个 KMS 框架的关键入口。
4.1 驱动初始化整体流程概览
瑞芯微平台 DRM 驱动的初始化遵循 Linux 内核标准驱动模型,但结合了 Rockchip 特有的组件化设计。整体流程可分为三个阶段:
- 平台驱动 Probe:匹配设备树节点,触发 DRM 设备注册。
- 组件绑定:通过 component 框架,将 VOP、HDMI、MIPI DSI 等子驱动绑定到主 DRM 设备。
- 设备树解析:从设备树中获取显示接口、时钟、中断、寄存器地址等关键资源。
关键概念: 瑞芯微的 DRM 驱动采用
component 框架,将主显示控制器(VOP)与各个显示接口(Encoder/Connector)解耦,实现模块化加载与绑定。
4.2 平台 Probe 流程详解
瑞芯微 DRM 主驱动通常注册为 rockchip_drm_platform_driver,其 probe 函数是初始化的起点。核心步骤如下:
| 步骤 | 函数/操作 | 说明 |
|---|---|---|
| 1 | drm_dev_alloc() |
分配 DRM 设备结构体,设置 driver_features |
| 2 | component_match_add() |
根据设备树端口信息,添加组件匹配规则 |
| 3 | component_bind_all() |
触发所有匹配组件的 bind 回调 |
| 4 | drm_dev_register() |
注册 DRM 设备到内核,对外暴露 /dev/dri/card0 |
调试提示: 在
rockchip_drm_probe 函数入口添加 dev_info 打印,可以确认驱动是否成功匹配设备树节点。若 probe 未调用,请检查 compatible 字符串是否匹配。
4.3 组件绑定机制
瑞芯微平台使用 component 框架实现主从驱动解耦。主驱动(DRM core)不直接管理子设备,而是通过组件匹配与绑定机制,将 VOP、HDMI、DSI 等子驱动聚合起来。
4.3.1 组件匹配规则
组件匹配通过设备树的 ports 节点实现。主驱动遍历 ports 下的 port 节点,根据 remote-endpoint 找到对应的子设备节点,并添加到组件匹配列表中。
// 伪代码:组件匹配添加逻辑
struct component_match *match = NULL;
for_each_endpoint_of_node(dev->of_node, endpoint) {
remote = of_graph_get_remote_port_parent(endpoint);
if (remote) {
component_match_add(dev, &match, component_compare_of, remote);
of_node_put(remote);
}
}
ret = component_bind_all(dev, match);
4.3.2 子驱动 Bind 回调
每个子驱动(如 rockchip_vop、dw_hdmi)需要实现 component_ops 结构体中的 bind 和 unbind 函数。在 bind 中,子驱动完成自身初始化,并注册到 DRM 框架中。
| 子驱动 | Bind 主要工作 | 注册的 DRM 对象 |
|---|---|---|
| rockchip_vop | 初始化 CRTC,配置寄存器、中断、时钟 | struct drm_crtc |
| dw_hdmi | 初始化 HDMI 控制器,注册 Encoder + Connector | struct drm_encoder, struct drm_connector |
| mipi_dsi | 初始化 DSI 控制器,注册 Encoder + Connector | struct drm_encoder, struct drm_connector |
4.4 设备树解析关键点
设备树是瑞芯微平台显示驱动的配置核心。驱动通过 of_* 系列 API 解析设备树节点,获取硬件资源与拓扑关系。
4.4.1 关键设备树节点结构
// 典型瑞芯微显示设备树结构
display_subsystem: display-subsystem {
compatible = "rockchip,display-subsystem";
ports = <&vop_out>;
};
vop: vop@ff900000 {
compatible = "rockchip,rk3399-vop-big";
reg = <0x0 0xff900000 0x0 0x3efc>;
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru ACLK_VOP0>, <&cru HCLK_VOP0>;
clock-names = "aclk_vop", "hclk_vop";
ports {
#address-cells = <1>;
#size-cells = <0>;
vop_out: port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
vop_out_hdmi: endpoint@0 {
reg = <0>;
remote-endpoint = <&hdmi_in_vop>;
};
};
};
};
hdmi: hdmi@ff940000 {
compatible = "rockchip,rk3399-dw-hdmi";
reg = <0x0 0xff940000 0x0 0x20000>;
ports {
hdmi_in: port {
#address-cells = <1>;
#size-cells = <0>;
hdmi_in_vop: endpoint@0 {
reg = <0>;
remote-endpoint = <&vop_out_hdmi>;
};
};
};
};
4.4.2 解析流程与 API
| 解析目标 | 使用的 API | 获取内容 |
|---|---|---|
| 寄存器地址 | of_iomap() / platform_get_resource() |
MMIO 基地址与范围 |
| 中断号 | platform_get_irq() |
IRQ 编号,用于注册中断处理 |
| 时钟 | of_clk_get() / devm_clk_get() |
ACLK、HCLK、DCLK 等时钟句柄 |
| 端口拓扑 | of_graph_get_remote_port_parent() |
获取连接的远程设备节点 |
| 显示时序 | of_get_display_timing() |
panel-timing 或 display-timings 子节点 |
常见问题: 设备树中
remote-endpoint 指向错误或缺失,会导致组件绑定失败,表现为 component_bind_all 返回 -EPROBE_DEFER 或 -EINVAL。务必检查 ports 节点的连接完整性。
4.5 初始化顺序与依赖关系
瑞芯微平台对组件初始化顺序有严格要求,错误的顺序可能导致系统挂起或显示异常。
- VOP 必须先于 Encoder 初始化:因为 Encoder 的
bind回调中需要获取 VOP 的 CRTC 对象。 - 时钟与电源域依赖:VOP 和 HDMI 可能共享同一个电源域,需确保电源域在组件 bind 前已使能。
- EPROBE_DEFER 处理:若某个子驱动依赖的资源(如 I2C、PHY)未就绪,应返回 -EPROBE_DEFER,等待内核重试。
4.6 调试方法与常见问题
4.6.1 调试手段
- 动态调试打印:在
rockchip_drm_probe、component_bind_all前后添加dev_dbg,观察初始化进度。 - 检查 /sys/kernel/debug/dri/0/:查看 CRTC、Encoder、Connector 是否已成功注册。
- 使用 drm_info:用户态工具,可查看 DRM 设备拓扑与状态。
4.6.2 常见问题与解决方案
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| probe 未调用 | compatible 不匹配 / 设备树未使能 | 检查设备树 status 是否为 "okay" |
| component_bind_all 返回 -EPROBE_DEFER | 子驱动依赖资源未就绪 | 检查 I2C、PHY、时钟等依赖是否已加载 |
| VOP 绑定成功但 HDMI 失败 | 端口连接错误或 HDMI 固件问题 | 验证 remote-endpoint 指向,检查 HDMI 电源 |
| drm_dev_register 失败 | minor 号耗尽或内存不足 | 检查 dmesg,确认是否有内存压力 |
核心要点回顾:
- 瑞芯微 KMS 驱动初始化分为 probe、组件绑定、设备树解析三个阶段。
- component 框架是实现模块化显示驱动的关键,通过设备树端口拓扑自动匹配子驱动。
- 设备树解析是获取硬件资源与连接关系的唯一入口,必须保证节点完整性与正确性。
- 初始化顺序依赖 VOP 先于 Encoder,否则会导致绑定失败。