3. DSI设备树绑定与解析
在瑞芯微平台MIPI DSI显示驱动开发中,设备树(Device Tree)是连接硬件描述与软件驱动的核心桥梁。本章将深入解析DSI控制器节点中关键属性的绑定规则与内核解析机制,帮助开发者准确配置设备树,确保驱动能够正确识别硬件资源并初始化显示链路。
3.1 DSI设备树节点结构概览
一个典型的瑞芯微MIPI DSI控制器设备树节点包含以下核心属性组,它们共同定义了控制器的硬件资源、时钟拓扑、复位逻辑、引脚复用、电源域以及数据传输速率。
dtc -I dtb -O dts反编译确认最终生效的配置。
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 */ }
};
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);
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使能
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;
}
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驱动无法正常加载时,可以通过以下方法验证设备树属性是否正确解析:
- 查看驱动probe日志:使用
dmesg | grep dw-mipi-dsi过滤驱动输出,确认probe成功与否及错误原因。 - 检查设备树节点:在
/sys/firmware/devicetree/base/路径下查看实际生效的设备树属性值。 - 验证时钟频率:使用
cat /sys/kernel/debug/clk/clk_summary | grep mipi查看时钟是否已使能及实际频率。 - 确认电源域状态:通过
cat /sys/kernel/debug/pm_genpd/pm_genpd_summary确认DSI所在电源域为"on"状态。 - 测量lane-rate:使用示波器在PHY输出端测量时钟通道频率,验证是否与配置值一致。
dev_info()打印每个属性的解析结果,配合dynamic_debug动态控制日志级别,可以快速定位属性解析失败的环节。例如:dev_info(dev, "lane-rate: %u MHz\n", lane_rate);