4. 显示控制器节点解析:必备属性与驱动匹配逻辑
显示控制器(Display Controller)节点是设备树中描述显示硬件核心的节点,通常对应 SoC 内部的 CRTC(Cathode Ray Tube Controller)或 Display Engine。内核 DRM 驱动通过解析该节点的 clocks、clock-names、resets、power-domains 等必备属性,完成硬件时钟使能、复位释放和电源域上电等初始化操作。本节将逐一解析这些属性的语义、格式及其在驱动中的匹配逻辑。
"vendor,display-controller" 或 "vendor,display-engine",驱动通过 of_match_table 进行匹配。必备属性若缺失,驱动 probe 将直接返回 -ENODEV。
4.1 必备属性总览
下表列出了显示控制器节点中必须包含的四个属性及其在内核驱动中的典型用途:
| 属性名 | 类型 | 驱动匹配逻辑 | 缺失后果 |
|---|---|---|---|
clocks |
phandle 列表 | 通过 devm_clk_get() 或 of_clk_get() 获取时钟句柄 |
时钟无法使能,显示无输出 |
clock-names |
字符串列表 | 驱动按名称索引特定时钟(如 "pclk"、"axi_clk") | 驱动无法区分多时钟场景 |
resets |
phandle 列表 | 通过 devm_reset_control_get() 获取复位控制器 |
硬件可能处于复位状态 |
power-domains |
phandle 列表 | 通过 dev_pm_domain_attach() 关联电源域 |
电源域未上电,寄存器访问失败 |
4.2 clocks 与 clock-names 属性解析
clocks 属性是一个 phandle 数组,每个 phandle 指向一个时钟提供者节点(如 clk 或 cgu)。clock-names 为每个时钟指定一个逻辑名称,驱动通过名称而非索引来获取时钟,提高代码可读性和可维护性。
典型设备树片段:
display_controller: display-controller@1a00000 {
compatible = "vendor,display-controller";
reg = <0x1a00000 0x1000>;
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_DISPLAY_PCLK>,
<&ccu CLK_DISPLAY_AXI>,
<&ccu CLK_DISPLAY_MCLK>;
clock-names = "pclk", "axi_clk", "mclk";
resets = <&rst RESET_DISPLAY>;
power-domains = <&pd_display>;
status = "okay";
};
驱动中获取时钟的典型代码:
struct clk *pclk, *axi_clk, *mclk;
pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(pclk))
return PTR_ERR(pclk);
axi_clk = devm_clk_get(dev, "axi_clk");
if (IS_ERR(axi_clk))
return PTR_ERR(axi_clk);
mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(mclk))
return PTR_ERR(mclk);
devm_clk_get() 而非 clk_get(),前者在驱动卸载时自动释放时钟句柄,避免资源泄漏。对于可选时钟,使用 devm_clk_get_optional() 允许时钟缺失时继续 probe。
4.3 resets 属性解析
resets 属性指向复位控制器节点,驱动在 probe 阶段需要将显示控制器从复位状态释放。复位操作通常在时钟使能之前完成,确保时钟信号稳定传递到逻辑电路。
驱动中复位操作的典型流程:
struct reset_control *rst;
rst = devm_reset_control_get(dev, NULL);
if (IS_ERR(rst))
return PTR_ERR(rst);
/* 先解除复位 */
reset_control_deassert(rst);
/* 再使能时钟 */
clk_prepare_enable(pclk);
clk_prepare_enable(axi_clk);
clk_prepare_enable(mclk);
reset_control_deassert() 后添加适当的延迟。
4.4 power-domains 属性解析
power-domains 属性将显示控制器节点关联到 SoC 的电源管理域。当系统从低功耗状态唤醒时,电源域控制器负责恢复供电。驱动通过 dev_pm_domain_attach() 建立关联,运行时 PM 框架自动管理电源域的上电和下电。
驱动中电源域关联的典型代码:
int ret;
ret = dev_pm_domain_attach(dev, true);
if (ret < 0 && ret != -EPROBE_DEFER)
dev_warn(dev, "failed to attach power domain: %d\n", ret);
power-domains 属性。但为了可移植性,建议始终显式指定,即使只有一个电源域。
4.5 驱动匹配逻辑流程图
下图展示了内核 DRM 驱动在 probe 阶段解析显示控制器节点必备属性的完整流程:
4.6 属性缺失时的驱动行为
内核 DRM 框架对必备属性缺失的处理策略如下:
| 缺失属性 | 驱动行为 | 内核日志 |
|---|---|---|
clocks |
probe 返回 -ENODEV | display-controller xxx: failed to get clocks |
clock-names |
若多时钟则 probe 失败;单时钟可降级 | display-controller xxx: missing clock-names |
resets |
probe 返回 -ENODEV | display-controller xxx: failed to get reset |
power-domains |
probe 继续,但运行时 PM 可能异常 | display-controller xxx: power domain not found |
/sys/kernel/debug/devices_deferred 文件,查看是否有设备因依赖资源(如时钟、电源域)而处于延迟 probe 状态。使用 clk_summary 和 regulator_summary 调试接口确认时钟和电源状态。
4.7 多实例与属性复用
在支持多显示控制器的 SoC 中(如双通道显示),每个控制器节点独立声明自己的 clocks、resets 和 power-domains。驱动通过 of_device_is_compatible() 或 of_match_node() 区分不同实例。
多实例设备树示例:
display_controller0: display-controller@1a00000 {
compatible = "vendor,display-controller-v2";
clocks = <&ccu CLK_DISPLAY0_PCLK>,
<&ccu CLK_DISPLAY0_AXI>;
clock-names = "pclk", "axi_clk";
resets = <&rst RESET_DISPLAY0>;
power-domains = <&pd_display0>;
};
display_controller1: display-controller@1a01000 {
compatible = "vendor,display-controller-v2";
clocks = <&ccu CLK_DISPLAY1_PCLK>,
<&ccu CLK_DISPLAY1_AXI>;
clock-names = "pclk", "axi_clk";
resets = <&rst RESET_DISPLAY1>;
power-domains = <&pd_display1>;
};
驱动中通过 struct device *dev 的 of_node 指针区分实例,每个实例独立管理自己的时钟和复位资源。
4.8 常见错误与排查方法
- 时钟名称不匹配:驱动中
devm_clk_get(dev, "pclk")与设备树clock-names = "pixel_clk"不一致,导致返回 -ENOENT。应严格对齐名称。 - 复位顺序错误:在时钟使能之后才 deassert 复位,可能导致时钟域未稳定时复位信号变化,引发总线锁死。应遵循先复位后时钟的顺序。
- 电源域依赖缺失:未在设备树中声明
power-domains,但硬件实际需要电源域控制,导致寄存器访问时发生 SError 或 hang。使用dev_pm_domain_attach()的返回值判断是否成功。 - 属性拼写错误:设备树中误写为
clock-names为clock-name(缺少 s),内核解析时忽略该属性,驱动获取时钟失败。使用dtc -I dtb -O dts反编译检查。
通过本节的学习,你应该能够独立解析显示控制器节点的四个必备属性,理解驱动中对应的获取和初始化逻辑,并能在设备树调试中快速定位属性相关的 probe 失败问题。