3. DSI设备树绑定与解析

在瑞芯微平台MIPI DSI显示驱动开发中,设备树(Device Tree)是连接硬件描述与软件驱动的核心桥梁。本章将深入解析DSI控制器节点中关键属性的绑定规则与内核解析机制,帮助开发者准确配置设备树,确保驱动能够正确识别硬件资源并初始化显示链路。

3.1 DSI设备树节点结构概览

一个典型的瑞芯微MIPI DSI控制器设备树节点包含以下核心属性组,它们共同定义了控制器的硬件资源、时钟拓扑、复位逻辑、引脚复用、电源域以及数据传输速率。

关键提示:设备树配置错误是MIPI DSI驱动调试中最常见的问题来源。属性值缺失、地址冲突或时钟频率不匹配,往往导致驱动probe失败或显示异常。建议在修改设备树后,使用dtc -I dtb -O dts反编译确认最终生效的配置。
DSI设备树节点属性组结构 DSI控制器节点 compatible 驱动匹配标识 reg / interrupts 地址空间与中断 clocks 时钟源与速率 resets 复位控制 pinctrl 引脚复用配置 power-domains 电源域管理 rockchip,lane-rate 数据通道速率 panel子节点 显示面板参数 属性组协同工作流程 1. compatible 匹配驱动 → 驱动probe入口 2. reg 映射寄存器基址 → 硬件访问就绪 3. clocks/resets/pinctrl/power-domains 初始化硬件环境 4. rockchip,lane-rate 配置PHY速率 → 启动MIPI链路

3.2 compatible属性:驱动匹配的钥匙

compatible属性是设备树节点与Linux驱动进行绑定的关键标识。内核通过该属性的字符串值,在驱动注册的of_device_id匹配表中查找对应的驱动程序。

3.2.1 瑞芯微平台DSI compatible值规范

SoC平台 compatible字符串 对应驱动文件
RK3288 rockchip,rk3288-mipi-dsi dw-mipi-dsi.c
RK3399 rockchip,rk3399-mipi-dsi dw-mipi-dsi.c
RK3566/RK3568 rockchip,rk3568-mipi-dsi dw-mipi-dsi2.c
RK3588 rockchip,rk3588-mipi-dsi dw-mipi-dsi2.c

3.2.2 内核解析机制

驱动probe阶段,内核调用of_match_node()函数遍历驱动的of_device_id表,与设备节点的compatible值进行字符串精确匹配。匹配成功后,驱动获取对应的data字段,用于区分不同SoC的硬件差异。

// 驱动中的 of_device_id 匹配表示例
static const struct of_device_id dw_mipi_dsi_of_match[] = {
    { .compatible = "rockchip,rk3288-mipi-dsi", .data = &rk3288_dsi_data },
    { .compatible = "rockchip,rk3399-mipi-dsi", .data = &rk3399_dsi_data },
    { .compatible = "rockchip,rk3568-mipi-dsi", .data = &rk3568_dsi_data },
    { .compatible = "rockchip,rk3588-mipi-dsi", .data = &rk3588_dsi_data },
    { /* sentinel */ }
};
常见错误:compatible字符串拼写错误或大小写不匹配是导致驱动无法加载的首要原因。务必与内核源码中的of_device_id表严格一致。建议从内核源码arch/arm64/boot/dts/rockchip/目录下的参考设备树文件中复制。

3.3 reg属性:寄存器地址空间映射

reg属性定义了DSI控制器的寄存器基地址和地址范围,驱动通过platform_get_resource()获取该信息,并调用devm_ioremap_resource()完成物理地址到内核虚拟地址的映射。

3.3.1 典型配置格式

// 设备树中的reg属性
reg = <0x0 0xff960000 0x0 0x10000>;
// 格式: <地址高位 地址低位 大小高位 大小低位>
// 对于32位平台: reg = <0xff960000 0x10000>;

3.3.2 多地址空间场景

部分瑞芯微SoC的DSI控制器包含独立的PHY寄存器空间,此时reg属性包含多个地址段:

// RK3588 DSI控制器多reg示例
reg = <0x0 0xff960000 0x0 0x10000>,  // DSI主机控制器
      <0x0 0xff968000 0x0 0x10000>;  // DSI PHY寄存器
reg索引 用途 驱动获取方式
0 DSI主机控制器寄存器 platform_get_resource(pdev, IORESOURCE_MEM, 0)
1 DSI PHY寄存器(可选) platform_get_resource(pdev, IORESOURCE_MEM, 1)

3.4 clocks属性:时钟拓扑配置

MIPI DSI控制器需要多个时钟源协同工作,clocks属性通过phandle引用时钟控制器中的时钟输出,驱动使用clk_get()或devm_clk_get()获取时钟句柄。

3.4.1 时钟属性结构

// 设备树时钟配置示例
clocks = <&cru CLK_MIPIDSI_24M>,
         <&cru CLK_MIPIDSI_CFG>;
clock-names = "pclk", "cfg";

3.4.2 瑞芯微平台DSI时钟列表

clock-names 时钟作用 典型频率
pclk APB总线接口时钟,用于寄存器访问 100 MHz
cfg DSI配置时钟,用于内部逻辑 200 MHz
ref 参考时钟,用于PHY频率锁定 24 MHz
txbytehs 高速字节时钟,用于数据发送 由lane-rate计算

3.4.3 内核时钟解析流程

// 驱动中获取时钟的典型代码
struct clk *pclk, *cfg_clk;

pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(pclk))
    return dev_err_probe(dev, PTR_ERR(pclk), "failed to get pclk\n");

cfg_clk = devm_clk_get(dev, "cfg");
if (IS_ERR(cfg_clk))
    return dev_err_probe(dev, PTR_ERR(cfg_clk), "failed to get cfg clk\n");

3.5 resets属性:复位控制

resets属性用于控制DSI控制器的硬件复位信号,确保控制器在上电或模式切换时处于确定的初始状态。驱动通过reset_control_get()获取复位句柄,并在初始化序列中执行复位操作。

// 设备树复位配置
resets = <&cru SRST_MIPIDSI_CFG>;
reset-names = "cfg";

// 驱动中复位操作
struct reset_control *rst;

rst = devm_reset_control_get(dev, "cfg");
if (IS_ERR(rst))
    return dev_err_probe(dev, PTR_ERR(rst), "failed to get reset\n");

// 执行复位:先拉低再释放
reset_control_assert(rst);
udelay(10);
reset_control_deassert(rst);
调试建议:如果DSI驱动在probe阶段卡死或返回-EPROBE_DEFER,检查resets属性是否引用了正确的复位控制器。复位资源未就绪是导致驱动延迟加载的常见原因。

3.6 pinctrl属性:引脚复用配置

pinctrl属性定义了DSI接口的引脚复用状态,包括数据通道(Data Lane)、时钟通道(Clock Lane)以及可能的GPIO控制引脚。瑞芯微平台使用pinctrl-names定义不同操作状态下的引脚配置。

// 设备树pinctrl配置
pinctrl-names = "default", "sleep";
pinctrl-0 = <&dsi_pins_default>;
pinctrl-1 = <&dsi_pins_sleep>;

// 引脚组定义(在pinctrl节点中)
dsi_pins_default: dsi-pins-default {
    rockchip,pins =
        /* 时钟通道 */
        <4 RK_PA0 2 &pcfg_pull_none>,
        /* 数据通道0 */
        <4 RK_PA1 2 &pcfg_pull_none>,
        /* 数据通道1 */
        <4 RK_PA2 2 &pcfg_pull_none>;
};
pinctrl状态 触发时机 典型配置
default 驱动probe时 MIPI功能模式,内部上拉/下拉关闭
sleep 系统进入低功耗时 引脚置为GPIO输入,降低漏电流

3.7 power-domains属性:电源域管理

瑞芯微SoC采用电源域(Power Domain)架构管理不同模块的供电。power-domains属性将DSI控制器关联到对应的电源域,驱动通过dev_pm_domain_attach()确保在访问硬件前电源已稳定开启。

// 设备树电源域配置
power-domains = <&power RK3588_PD_VI>;

// 驱动中无需额外代码,内核PM框架自动处理
// 电源域会在probe前由driver core使能
关键说明:电源域配置错误通常表现为寄存器访问时返回全0或全1,或者驱动probe时发生同步错误。使用cat /sys/kernel/debug/pm_genpd/pm_genpd_summary可以查看各电源域的当前状态,辅助排查电源问题。

3.8 rockchip,lane-rate属性:数据通道速率配置

rockchip,lane-rate是瑞芯微平台自定义属性,用于指定MIPI DSI每个数据通道的传输速率,单位为MHz。该值直接影响PHY的PLL配置和高速数据传输的建立时间。

3.8.1 属性配置与计算

// 设备树配置
rockchip,lane-rate = <1000>;  // 每个通道1 Gbps

// 驱动中解析
of_property_read_u32(np, "rockchip,lane-rate", &lane_rate);

3.8.2 速率与显示参数的关系

lane-rate的计算基于显示分辨率、刷新率和色彩深度:

// lane-rate 计算公式(近似)
lane_rate = (h_active + h_blank) * (v_active + v_blank) * fps * bpp / lanes

// 示例:1080p60, 24bpp, 4-lane
// lane_rate = (2200 * 1125 * 60 * 24) / 4 ≈ 891 MHz
// 实际配置取整为 900 MHz
分辨率 刷新率 色彩深度 通道数 推荐lane-rate (MHz)
1920x1080 60 Hz 24 bpp 4 900
2560x1440 60 Hz 24 bpp 4 1400
3840x2160 30 Hz 24 bpp 4 1500
3840x2160 60 Hz 24 bpp 8 1500

3.8.3 内核解析与PHY配置

// 驱动中lane-rate到PHY配置的转换
static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
{
    u32 lane_rate;
    u32 phy_config;
    
    of_property_read_u32(dsi->dev->of_node, "rockchip,lane-rate", &lane_rate);
    
    // 根据lane-rate计算PHY分频系数
    phy_config = (lane_rate * 1000000) / 2;  // 转换为Hz并二分频
    
    // 写入PHY寄存器
    dsi_write(dsi, DSI_PHY_TMR_CFG, phy_config);
    
    return 0;
}
速率配置警告:lane-rate设置过高会导致MIPI信号质量下降,出现屏幕闪烁、花屏或链路不稳定;设置过低则无法满足显示带宽需求。建议使用示波器测量PHY输出端的信号眼图,确保上升/下降时间符合MIPI D-PHY规范(150 ps ~ 250 ps)。

3.9 完整设备树节点示例

以下是一个基于RK3588平台的完整DSI控制器设备树节点,整合了上述所有属性:

dsi0: dsi@ff960000 {
    compatible = "rockchip,rk3588-mipi-dsi";
    reg = <0x0 0xff960000 0x0 0x10000>,
          <0x0 0xff968000 0x0 0x10000>;
    interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
    
    clocks = <&cru CLK_MIPIDSI_24M>,
             <&cru CLK_MIPIDSI_CFG>;
    clock-names = "pclk", "cfg";
    
    resets = <&cru SRST_MIPIDSI_CFG>;
    reset-names = "cfg";
    
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&dsi0_pins_default>;
    pinctrl-1 = <&dsi0_pins_sleep>;
    
    power-domains = <&power RK3588_PD_VI>;
    
    rockchip,lane-rate = <1000>;
    rockchip,grf = <&grf>;
    
    status = "disabled";
    
    panel@0 {
        compatible = "boe,tv110wum-nl0";
        reg = <0>;
        backlight = <&backlight>;
        enable-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
        reset-gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;
        
        ports {
            panel_in: endpoint {
                remote-endpoint = <&dsi0_out>;
            };
        };
    };
    
    ports {
        #address-cells = <1>;
        #size-cells = <0>;
        
        dsi0_out: endpoint@0 {
            reg = <0>;
            remote-endpoint = <&panel_in>;
        };
    };
};

3.10 属性解析调试方法

当DSI驱动无法正常加载时,可以通过以下方法验证设备树属性是否正确解析:

  1. 查看驱动probe日志:使用dmesg | grep dw-mipi-dsi过滤驱动输出,确认probe成功与否及错误原因。
  2. 检查设备树节点:在/sys/firmware/devicetree/base/路径下查看实际生效的设备树属性值。
  3. 验证时钟频率:使用cat /sys/kernel/debug/clk/clk_summary | grep mipi查看时钟是否已使能及实际频率。
  4. 确认电源域状态:通过cat /sys/kernel/debug/pm_genpd/pm_genpd_summary确认DSI所在电源域为"on"状态。
  5. 测量lane-rate:使用示波器在PHY输出端测量时钟通道频率,验证是否与配置值一致。
DSI设备树属性解析调试流程 驱动probe入口 解析compatible匹配 获取reg/irq资源 获取clocks/resets 配置pinctrl/power 解析lane-rate配置PHY 初始化完成
调试利器:在驱动代码中添加dev_info()打印每个属性的解析结果,配合dynamic_debug动态控制日志级别,可以快速定位属性解析失败的环节。例如:dev_info(dev, "lane-rate: %u MHz\n", lane_rate);