RK3568 多路显示移植实战:OpenHarmony 下从设备树到 DRM 的完整配置指南
2026/9/12 5:04:04 网站建设 项目流程

RK3568 的多路显示移植—【万物智能之开源鸿蒙 OpenHarmony 系统实战开发系列教程】

先说明白一件事:多路显示移植这个事,听起来像是“接上两块屏就能用”,但真正落到 RK3568 这套硬件和 OpenHarmony 这套系统上,中间隔着设备树、DRM 显示框架、VOP 视频输出处理器、图层合成、触控联动等一系列环节。任何一个节点没配对,结果就是第二路屏要么黑着,要么分辨率错乱,要么画面撕裂。我前后在两个项目里做过 RK3568 的多屏适配,一块是 7 寸 MIPI DSI 加 HDMI 1080P,另一块是双 MIPI DSI 加 eDP 三屏输出,踩过的坑加起来比写代码的时间还多。这篇就把完整的移植思路、配置细节和排错方法整理出来,给正在 OpenHarmony 上做 RK3568 显示适配的工程师一条可以少走弯路的参考路径。

先确认一下适用范围:本文以 RK3568 平台、OpenHarmony 标准系统(3.2 及以上版本)为基准,所有设备树配置和内核选项以 Linux 5.10 内核分支为参考。如果你用的是其他内核版本,节点名和属性名可能会有细微差异,但排查思路完全通用。

1. 多路显示不是炫技:RK3568 在 OpenHarmony 上做多屏的真实价值

很多刚从 Android 转过来的工程师会问:OpenHarmony 的多路显示到底能解决什么业务问题?单纯把一个桌面图标从左屏拖到右屏,这不叫刚需。我理解的多屏,在嵌入式场景里对应的是三类硬需求:

第一类是信息密度不够用。典型如带屏中控、工业 HMI,一块屏上要同时显示参数曲线、告警列表、实时视频流,界面排布非常拥挤。拆成主屏加副屏之后,主屏管交互,副屏管监控数据,UI 复杂度直接降一个量级。

第二类是异构显示媒介并存。RK3568 的显示接口特别丰富,HDMI、eDP、MIPI DSI、RGB/LVDS、BT1120 都可以接。实际产品里经常是“一手工业屏一手 HDMI 大屏”的组合,两种屏的分辨率、色深、刷新率完全不同,多路显示移植要解决的就是让它们在一个系统里各显其道。

第三类是多任务并行可见。比如带屏门禁设备,门口机显示视频通话画面,管理中心通过 HDMI 输出投放通知公告;再比如智能健身镜,主屏 1080P 出训练视频,副屏用 MIPI 显示体感数据。两块屏显示的内容互相独立,但都在同一个 OpenHarmony 系统里运行。

OpenHarmony 的多屏能力往下走依赖的是 DRM(Direct Rendering Manager)框架。RK3568 的显示控制器 VOP2 在 DRM 框架下可以注册多个 CRTC,每个 CRTC 对应一个显示管道,也就是一路可独立刷新的显示输出。这是多屏能成立的硬件基础。而 OpenHarmony 的图形子系统通过 HDI(Hardware Device Interface)层对接 DRM,把多屏能力暴露给上层窗口管理,最终让应用可以决定把某个窗口放到第几块屏上。

明白了这个链路,你就能建立一条完整的多屏移植主线:硬件确认显示通道 → 内核配置使能对应驱动 → 设备树声明编码器和屏幕参数 → 系统起来后通过 DRM 验证多 CRTC 状态 → 上层窗口分发与触控校准。接下来逐步拆解。

2. RK3568 显示子系统底牌:先搞清 VOP 和各个显示接口再动手

2.1 VOP2:多路显示的总闸门

RK3568 的显示核心叫 VOP2,全称 Video Output Processor。它负责从内存读图像数据、做图层叠加、格式转换,最后把像素时钟和同步信号送给下游的显示接口。你可以把它理解成一个功能强大的“画面调度中心”,每一路出口 CRTC 都对应 VOP2 内部的一个 Video Port。

RK3568 的 VOP2 支持 4 个 Video Port,实际可用的 CRTC 数量取决于芯片封装和 SDK 配置。常见配置下能同时工作的显示通道是 3 路左右,再加上 HDMI、eDP、MIPI DSI 这些编码器(Encoder)的交叉互连,排列组合非常灵活。内核里对应的驱动节点是vop2,它会在 DRM 设备中注册多个 CRTC。

移植多屏之前,必须先搞清楚你的板子上 VOP2 各端口的优先级和时钟约束。VOP2 的端口不是完全平等的,某些高分辨率输出对像素时钟要求很高,如果多个显示通道同时抢同一个 PLL 的时钟源,就可能出现“接上第二块屏,第一块屏变花”这种诡异问题。后续调试章节会专门讲。

2.2 各路显示接口的本质区别

RK3568 支持的外部显示接口大概可以分成两类:一类是“直连屏”,一类是“协议转换”。理解这个区别,对设备树配置有很大帮助。

  • MIPI DSI:直接驱动 MIPI 接口的 LCD 屏,点屏过程要配时序、配 DSI 命令。RK3568 有两个 DSI 控制器,可以做到双 DSI 拼接驱动一块高分辨率大屏,也可以各自独立带一块屏。
  • eDP:接 eDP 接口的笔记本屏或平板屏,需要配置 Lane 数、链路速率。RK3568 的 eDP 控制器在设备树里通常是靠link-ratelane-count两个参数调整带宽。
  • HDMI:最典型的协议转换型接口,VOP 输出的并行 RGB 信号经过 HDMI 发送器变成 TMDS 差分信号。RK3568 内置 HDMI 2.0 控制器,最大支持 4K@60Hz 输出。
  • RGB/LVDS/BT1120:并行接口,一般接工控屏或转接板。BT1120 在 RK3568 上常用于输出 1080P 的视频信号给采集端或后级处理芯片。

做多屏移植时,很多人只盯着“屏幕型号”去配置,忽略了显示控制器到接口之间的通路配置。其实 RK3568 设备树的显示部分约等于一道分诊台:接口负责和屏幕握手,VOP 负责把画面送进来,两者之间还有一条路由关系需要点对点指定。这个路由关系就是 dts 里各节点之间 endpoint 的连接关系,后面会详细展开。

2.3 动手前的硬件摸底清单

在敲任何一行 dts 之前,先做一轮硬件盘点:

  1. 确认板子上实际引出哪些显示接口,每一路接口连接到哪个连接器。这一步要对着原理图查,别只看核心板规格书。
  2. 确认每块屏幕的详细规格:分辨率、刷新率、像素时钟(PCLK)、数据通道数(比如 MIPI 是 4 lane 还是 2 lane)、是否需要初始化序列(DCS Command)。
  3. 确认 HDMI 的 EDID 是否能正常读取,不能读 EDID 的情况下要准备一个固定的默认显示模式。
  4. 确认显示电源和背光电源的 GPIO/PMIC 控制方式,多屏移植最容易遗漏的点就是第二路屏的背光没拉起来,导致系统日志里显示接口已就绪但屏幕是黑的。

这样一轮摸底下来,你会发现多屏移植的工作量其实分成了三块:dts 配置占三成,驱动裁剪占两成,剩下五成都在调时序和排错。

3. 移植前的地基:内核配置、DRM 驱动裁剪和编译链路准备

这里的顺序有讲究。很多人上来就改 dts,编译完发现 hdmi 节点都没被解析进去,才回头补内核配置。正确顺序是:先确认内核有对应驱动,再确认 dts 被编译,最后确认驱动加载顺序

3.1 内核 defconfig 必开项

RK3568 在 OpenHarmony 标准系统下通常使用rockchip_linux_defconfig这类基础配置,多屏显示需要确保以下几个配置项是打开的:

CONFIG_DRM_ROCKCHIP=y CONFIG_DRM_ROCKCHIP_DW_HDMI=y CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI=y CONFIG_DRM_ROCKCHIP_CDN_DP=y CONFIG_DRM_ROCKCHIP_ANALOGIX_DP=y CONFIG_DRM_ROCKCHIP_LVDS=y CONFIG_DRM_ROCKCHIP_RGB=y CONFIG_DRM_ROCKCHIP_BT1120=y CONFIG_DRM_ROCKCHIP_VOP2=y CONFIG_DRM_ROCKCHIP_VVOP=y

注意VVOP是虚拟显示输出,部分方案里用来做截屏或者虚拟屏,如果你不需要就关掉,省得它在多屏枚举阶段多出一个 /dev/dri/card0 之外的分节点,干扰判断。

还有一种情况是板子用到了 Mali GPU 显示加速,CONFIG_MALI_CSF或者CONFIG_MALI_BIFROST相关配置会影响 framebuffer 的分配方式,先在 defconfig 里保持 SDK 默认值,不要为了精简去删 GPU 驱动,否则 OpenHarmony 图形栈起不来。

3.2 DRM 驱动加载成功的判断标准

刷完内核启动系统之后,第一件事是查/sys/class/drm/下有哪些节点。正常多屏状态下应该能看到:

card0-DP-1 card0-DSI-1 card0-DSI-2 card0-HDMI-A-1 card0-eDP-1

每个节点对应一个 DRM connector。如果接了两块屏,预期看到两个 connector,但实际只出现一个,说明要么 dts 里对应的 encoder 节点没有被 probe,要么对应的 phy/时钟依赖没满足。

再配合dmesg | grep -i drm看驱动打印:

rockchip-drm display-subsystem: bound fde00000.vop2 (ops vop2_component_ops) rockchip-drm display-subsystem: bound hdmi@fe0a0000 (ops dw_hdmi_rockchip_ops)

第一行的fde00000.vop2是 VOP2 的寄存器基址,第二行的hdmi@fe0a0000是 HDMI 控制器。这两个绑定消息都必须出现。如果 bound 只出现一个,优先去查另一个节点的status、时钟和电源域配置。

3.3 依赖关系:时钟、电源域和 PHY 一次备齐

RK3568 的显示相关时钟在 dts 的cru(Clock and Reset Unit)节点里统一管理。多屏场景下要特别关注的时钟族有:

  • dclk_vop0dclk_vop1dclk_vop2:VOP 的像素时钟。
  • clk_mipi_dsi0clk_mipi_dsi1:MIPI DSI 的字节时钟。
  • clk_hdmi:HDMI 的音频/视频时钟。
  • clk_edp:eDP 的链路时钟。

电源域方面,power-domain@RK3568_PD_VO是显示输出的总开关,必须在 VOP 和各个 encoder 节点里显式引用:

power-domains = <&power RK3568_PD_VO>;

这个写漏的典型现象是:系统起来后cat /sys/class/drm/card0-HDMI-A-1/status显示 connected,但modetest列不出 mode,dmesg 里全是timeout waiting for vblank这类报错。原因就是 VO 电源域没起来,硬件寄存器读不回来正常状态。

PHY 这块主要针对 MIPI DSI 和 eDP。MIPI DSI 需要配置mipi_dphy节点,eDP 通常走cdn_dp或者analogix_dp,每个 PHY 在 dts 里都要有对应的physphy-names属性。多路 MIPI 时还要确认两路 DSI 的 PHY 是否共用了同一个refclk,共用的情况下要检查时钟频率是否满足两路相加的带宽,否则第二路 DSI 的点屏时序会不稳定。

4. 设备树配置是全剧核心:多路显示的 dts 节点怎么搭

这一节放核心配置代码。RK3568 多路显示的 dts 配置,本质上是在做四件事:声明显示控制器、声明输出接口、声明物理屏幕、声明连接关系。

4.1 从原厂 dtsi 中裁剪拓扑

RK3568 的 SDK 通常会提供一批带全部显示节点但默认关闭的 dtsi 文件,比如rk3568.dtsirk3568-evb.dtsi。我第一次做双屏项目时犯过一个错:直接在 EVB 板 dts 上改,结果被一大堆自己用不到的节点(比如 VGA、DP)干扰,排查问题时分不清哪段配置在起作用。

更合理的做法是:基于最小系统 dts 开始,只保留一路显示,验证通过后再逐步打开第二路、第三路。每开一路,就重新验证一遍前面几路的显示是否正常。这种递进式修改能让你把问题隔离在“刚动的这个节点”内。

基础框架上,RK3568 的显示拓扑在 dtsi 里大概长这样:

&vop2 { compatible = "rockchip,rk3568-vop2"; status = "okay"; }; &hdmi { status = "okay"; }; &mipi_dsi0 { status = "okay"; }; &mipi_dsi1 { status = "disabled"; };

每一路 encoder 节点对应的status字段,决定了它在 DRM 设备里是否注册为可用 connector。多屏移植里最常见的问题不是配置写错,而是某路节点被 dtsi 全局 disabled,你在板级 dts 里没显式打开,导致系统里始终只有一路显示。

4.2 HDMI + MIPI DSI 双屏的完整配置参考

下面给出一份经过验证的、HDMI 主屏加 MIPI DSI 副屏的双屏配置骨架。我用注释标注关键点:

&hdmi { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx1_hpd &hdmim0_tx0_scl &hdmim0_tx0_sda>; power-domains = <&power RK3568_PD_VO>; #address-cells = <1>; #size-cells = <0>; hdmi_audio: hdmi-audio { compatible = "rockchip,dw-hdmi-audio"; #sound-dai-cells = <0>; }; }; &dsi0 { status = "okay"; power-domains = <&power RK3568_PD_VO>; #address-cells = <1>; #size-cells = <0>; panel@0 { compatible = "boe,tv070wsm"; // 换成实际屏幕的 compatible reg = <0>; backlight = <&backlight0>; reset-gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_LOW>; enable-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&dsi0_lcd_rst &dsi0_lcd_en>; power-supply = <&vcc3v3_lcd0>; dsi-lanes = <4>; // 屏幕初始化序列和时序由于厂商而异,放到 panel 节点时 // 可以走 panel-simple,或走自带 init 的驱动 }; };

这里有两个值得注意的细节。第一,power-domains必须写,否则 VO 电源域在运行时可能会被关闭,表现为屏点亮后休眠唤醒失败。第二,dsi-lanes要和屏幕的实际数据通道数保持一致,4 lane 屏写成 2 lane,点屏大概率无图或有花屏。

连接关系在display-subsystemports中体现。RK3568 的vop2和各个 encoder 之间通过endpoint建立连接:

&vop2 { vop2_out: ports { #address-cells = <1>; #size-cells = <0>; vp0: port@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; vp0_out_hdmi: endpoint@0 { reg = <0>; remote-endpoint = <&hdmi_in_vp0>; }; }; vp1: port@1 { reg = <1>; vp1_out_dsi0: endpoint@0 { remote-endpoint = <&dsi0_in_vp1>; }; }; }; }; &hdmi { ports { #address-cells = <1>; #size-cells = <0>; port@0 { reg = <0>; hdmi_in_vp0: endpoint { remote-endpoint = <&vp0_out_hdmi>; }; }; }; }; &dsi0 { ports { #address-cells = <1>; #size-cells = <0>; port@0 { reg = <0>; dsi0_in_vp1: endpoint { remote-endpoint = <&vp1_out_dsi0>; }; }; }; };

这段配置的核心是remote-endpoint的配对关系。vp0是 VOP2 的 0 号视频端口,接 HDMI 控制器;vp1是 1 号视频端口,接 DSI0。如果把两个 endpoint 配反了,比如把 HDMI 接到了 vp1,而 vp1 的带宽或时钟约束不满足 1080P HDMI 输出的需求,会出现接口协商正常但实际输出闪烁的问题。

4.3 双路 MIPI / eDP 的额外注意事项

双 MIPI 或者 MIPI + eDP 的组合,配置结构类似,但有两个特有场景:

双路 MIPI 各自带屏时,dsi0dsi1要分别挂在不同的 VP 上。一般来说 DSI0 走 vp1、DSI1 走 vp2,避免两个 DSI 控制器共享同一个 VP 的像素时钟,否则一旦两块屏分辨率不同,时钟分配会出现“厚此薄彼”的现象。

如果做双 DSI 拼接驱动一块高分屏,就不能把 DSI1 当成独立 encoder,而要放在同一个 panel 节点内部,通过dual-dsi属性声明:

&dsi1 { status = "okay"; rockchip,dual-dsi = <&dsi0>; }; &dsi0 { status = "okay"; panel@0 { compatible = "xx,yyyy"; dual-dsi = <1>; ... }; };

这种情况下,VOP 里 VP 要保持单通道输出,由 DSI0 做主控制器,DSI1 以从模式跟随,两块屏在硬件层面被看作一块整体屏幕。

eDP 的配置里,link-ratelane-count是核心。常见 1080P eDP 屏用 4 lane、HBR1(2.7Gbps)即可;2K 屏建议配到 HBR2(5.4Gbps)。如果配置偏低导致带宽不足,现象很典型:开机第一帧正常,随后出现周期性闪烁,因为后续帧数据超过链路带宽被丢弃。

&edp { status = "okay"; rockchip,link-rate = <0x1e>; // HBR2 rockchip,lane-count = <4>; };

别小看这几行,实际项目里因为 eDP 链路速率不足导致闪屏的问题,排查周期常常在两到三天以上。

4.4 背光和电源:多屏时最容易漏的玩命细节

设备树里的背光配置看着简单,多屏时却屡屡埋雷。第一块屏的背光通常没问题,因为从 Android 或单屏 demo 迁移过来时,它已经调通了。第二块屏的背光才见真章。

背光节点要注意两点:一是 PWM 通道不能和已经有复用的引脚冲突,二是背光使能引脚不要在设备树里写死高电平,而是接到enable-gpios上由驱动控制。我遇到过背光 GPIO 被gpio-export占用、开机时两个驱动抢同一个引脚输出导致背光闪断的问题,最后是把其中一个占用删掉才解决。

5. 应用层多屏协同:合成、触控和显示模式切换的适配细节

内核和 dts 只是打通了底层通道,OpenHarmony 多屏要真正可用,还差最后一公里:图形栈把画面合成到多块屏上,输入栈把触控事件送到对应的屏幕窗口。这一层的问题,很多是“内核明明正常,应用层却只有主屏有画面”的元凶。

5.1 OpenHarmony 的 DisplayManager 与多屏枚举

OpenHarmony 标准系统的图形渲染管线由 RenderService 统一管理,HDI 显示接口层负责对接 DRM。系统启动后,DisplayManager 会枚举/dev/dri/card0下的所有 connector,为每个 connector 创建对应的 Display 对象。

应用层判断多屏是否生效,最简单的方法是查hidumper display的输出。能看到两个或三个 display 设备,说明 HDI 层已经识别到了多屏。如果只看到一个 display,就算modetest在系统里能看到两个 connector,也说明 OpenHarmony 图形栈没有完成多屏使能。

这一步的常见原因是:OpenHarmony 图形栈的HdiDisplay初始化阶段,要求 connector 能够读到有效的modes列表。如果第二块屏因为 EDID 问题、时序问题导致 mode 列表为空,HdiDisplay就会跳过该 connnector。排查时回到 DRM 层,先用modetest -M rockchip -p确认两块屏都能列出 mode。

提示:OpenHarmony 标准系统里,modetest是直接可用的内核工具,它在调试阶段的价值远大于任何图形栈日志。多屏不通时先看modetest,再决定是内核问题还是应用层问题。

5.2 触控和显示的多屏映射

多屏中如果副屏是触摸屏,触控上报的坐标是相对副屏的物理坐标,而 OpenHarmony 的窗口管理需要把触控点映射到对应 display 的逻辑坐标。匹配关系在 HDI 输入层里通过screenId来区分。

实际开发中常见的坑是在input_config或设备节点配置里把触摸设备默认关联到了主屏。现象是:触摸副屏时,主屏的鼠标光标在动。我在第一个双屏项目里就踩过这个坑。

解决办法是把副屏触摸设备的screenId固定为副屏对应的 ID。OpenHarmony 的InputManager会读取 HDI 输入实现里返回的screenId,你可以通过修改input_device_config里的设备属性和screenId映射,或者在内核 input 驱动的 evdev 上报中把INPUT_PROP_DIRECT和屏幕关联关系梳理清楚。

如果副屏不带触摸,只做展示,那这一步可以跳过,但要注意副屏窗口的焦点策略:默认情况下新窗口只会出现在主屏,需要在窗口配置里显式指定 displayId,否则应用跑起来你会觉得“多屏没生效”。

5.3 显示模式切换与分辨率适配

RK3568 的 VOP2 支持每个 VP 独立设置分辨率,但 OpenHarmony 上层对整机一般会定义一个主屏分辨率作为系统 UI 的基准。副屏分辨率在 DisplayManager 初始化时通过读取 DRM 的 mode 自动适配。

一个经常被忽略的点是:HDMI 屏的 mode 是动态可变的,插拔时会触发 hotplug 事件。OpenHarmony 对 hotplug 的默认策略是“插入新屏自动扩展,拔掉后自动回收”。如果你的产品要求 HDMI 副屏固定输出某种分辨率,比如必须 1024x768 而不是 EDID 里的 1920x1080,那就需要改 mode 策略,或者在内核里屏蔽掉特定 mode。

&hdmi { rockchip,default-mode = <1920 1080 60>; };

这个属性不是所有内核版本都支持,查你当前内核的dw_hdmi_rockchip.c里有没有处理rockchip,default-mode的逻辑。没有的话,可以通过修改 EDID 或者用video=内核参数来固定分辨率。

5.4 合成性能和 UI 卡顿的初步调优

两路屏同时刷新时,GPU 合成压力会明显增加。Mali-G52 要同时处理两路图层合成,以及可能存在的视频解码显示,带宽吃紧会导致 UI 丢帧。建议一开始就把合成方式调成 GPU 合成(OpenHarmony 3.2+ 已支持硬件合成和 GPU 合成切换),并且把不需要合成的透明窗口尽量去掉。

排查看是否有电容性丢帧,可以开 RenderService 的帧率统计,或者在内核里打开vblank事件的trace_printk,看两个 CRTC 的 vblank 中断是否都在预期频率触发。如果发现某个 CRTC 的 vblank 频率异常低,大概率是它的像素时钟配置不正确,回到时钟和 PLL 配置去查。

6. 调试排错全过程:多路显示移植里最容易阴沟翻船的几个点

我把实际项目中遇到的高频问题整理成一张排查表,每个问题都附上根因和处置方式:

现象优先排查方向常见根因
第二路屏完全黑屏modetest看 connector 是否存在dts 里 encoder 节点 status 未打开
connector 存在但无 mode看 EDID 是否读到HDMI 的 DDC/SCL/SDA 引脚配置错
屏亮了但花屏检查时序和 PCLK屏幕的 porch/blanking 参数不对
两路屏互相干扰检查 VOP VP 时钟是否独立两个 VP 共用 PLL 导致频率跳动
休眠唤醒后副屏不亮检查 power-domain 和 backlight副屏背光使能时序晚于显示
上层只有主屏有画面hidumper display看 display countHDI 层未识别副屏 connector
副屏触摸映射到主屏检查 input screenId 映射触控设备未关联副屏 display

6.1 一个典型的“第二路屏不亮”完整排查链路

在双屏项目里,我把 MIPI DSI 副屏接上后,副屏一直不亮。完整排查过程按时间顺序整理如下,你可以参照这个链路快速定位自己的问题。

第一步,cat /sys/class/drm/card0-DSI-1/status,返回connected,说明链路检测到了屏幕。这说明 I2C 读取屏幕 ID 成功,但显示通路可能没建立。

第二步,cat /sys/class/drm/card0-DSI-1/modes,空的。一个 mode 都没有,说明 connector 和 encoder 的管道还在,但 VOP 没有给它分配有效的显示参数。

第三步,dmesg | grep -i mipi,看到一行mipi_dsi0: failed to get pixel clock: -517。-517 在 Linux 里是-EPROBE_DEFER,表示驱动因为依赖的时钟还没准备好而被推迟。再查clk_get对应的是dclk_vop1,而dclk_vop1在另一个驱动里被独占使用。

到这里根因就清晰了:我把副屏挂到了 vp1,但 vp1 的像素时钟源被某个驱动预先占用了。解决办法是把副屏改挂到 vp2,或者调整时钟树让 vp1 的 dclk 资源不被争抢。改完 dts 重编,屏幕正常点亮。

6.2 双屏分辨率组合引发的 VOP VP 选择问题

第二类高频坑:主屏 1080P 走 vp0,副屏 4K 走 vp1,结果副屏只能输出 1080P 甚至完全无信号。原因是 vp1 的时钟范围或带宽不够 4K 输出。

RK3568 的每个 VP 都有固定的最大像素时钟限制。查内核里的rockchip_vop2.c,不同 VP 的max_output定义不一样。用 4K 输出时,尽量选用带宽更高的 VP。这个信息几乎不会写在 SDK 的单独文档里,只能从源码或原厂 support 那里确认。

一个通用建议:把分辨率最高的屏放在 vp0,其余按分辨率降序排在 vp1、vp2。这样可以最大限度规避时钟和带宽瓶颈。

6.3 屏幕时序参数不是“照抄屏厂参数”就行

很多屏幕规格书给的是Hactive/Vactive/HFP/HBP/HSync/VSync,你照着参数填进去,点不亮或者显示偏移。原因之一是 RK3568 的 dts 在panel-timing节点里有些字段的单位是像素时钟周期数,不是微秒,换算不对就会偏。

另一个容易被忽略的点是clock-frequency(像素时钟频率)。这个值必须和屏幕要求的 PCLK 匹配,并且要让内核能在这个频率下找到合适的 PLL 分频组合。比如 1080P60 标准 PCLK 是 148.5MHz,如果乱填一个 150MHz,虽然驱动会去尝试找 PLL 分频,但出来的实际频率可能会有偏差,导致画面滚动或闪烁。

调试期间建议用临时的fail-sysrq或连续 dumpclk_summary,确认dclk实际输出频率和期望值偏差在 ±1% 以内。

6.4 第二路屏“开机正常,过一会儿黑了”的排查思路

这个问题的典型路径是:屏幕正常工作一段时间后,DRM 触发 hotplug 事件断开,然后重新协商失败。

排查顺序:先看日志里是否有hotplug相关 log,再测量屏幕的 HPD 电平。如果 HPD 引脚上有电平抖动,检查硬件设计上是否有去耦电容不足的问题。软件上也别闲着,把内核里drm_kms_helperpoll间隔调长一点:

CONFIG_DRM_DP_AUX_CHARDEV=y drm_kms_helper.poll=0

把 poll 关掉之后,系统不再周期性地去探测 connector 状态,hotplug 事件的误触发会大幅减少。前提是你的屏幕支持 HPD 中断,否则拔插检测依赖 poll,全都关了可能导致拔插无响应。这个要看具体产品取舍。

7. 移植完成后的验证清单与后续扩展建议

7.1 一套可以照抄的多屏验收流程

代码改完不要直接交给测试,先把下面这套流程在本地过一遍:

  1. 多屏枚举验证:系统冷启动后,modetest -M rockchip输出的 connector 数量等于实际硬件屏数量。
  2. 每屏独立输出验证:用modetest分别对每个 connector 刷纯色测试画面,确认每个接口都出图。
  3. 双屏同显验证:主屏播放视频同时副屏显示 UI,观察是否有帧率下降或撕裂。
  4. 插拔稳定性验证:HDMI 副屏反复热插拔 50 次,系统不应崩溃,拔掉后主屏恢复正常,插回后副屏重新出图。
  5. 休眠唤醒验证:系统深度休眠后唤醒,所有屏幕都要恢复到休眠前状态,包括分辨率、亮度、触控。
  6. 压力测试:跑 72 小时老化,观察是否有屏幕闪断、花屏、内存泄漏导致的显示异常。

以上任何一条不通过,都优先排查内核 DRM 层的日志,不要急着改应用层。

7.2 后续功能扩展的三个方向

多路显示一旦跑通,往后的想象空间很大。常见扩展方向包括:

  • 副屏低功耗显示:RK3568 支持在副屏只做静态画面输出时降低 VOP 频率,配合 OpenHarmony 的省电策略,可以做出显示增强型门锁、低功耗信息牌。
  • 多屏开机动画定制:OpenHarmony 的开机动画可以在多屏上分别显示不同内容,需要修改RenderService的启动画面逻辑。
  • 显示链路诊断:在/sys/kernel/debug/dri/0/下用statedump 每个 CRTC 的完整状态,做成诊断工具集成到产测流程中,比人工看日志高效得多。

我在实际项目中最后保留了一个小习惯:在任何一次多屏改动之后,先把所有屏的drm状态 dump 一遍存档。等哪天用户反馈“某块屏不显示了”,对比存档能快速定位是驱动变更还是硬件老化,省去大量重复排查时间。这个习惯从 RK3568 延续到我后来做的其他平台,屡试不爽。

多路显示移植看着复杂,实际上只要把硬件链路理清、dts 连接关系理顺、应用层映射对齐,剩下的都是可枚举的细节问题。希望这份实战记录能给正在做 OpenHarmony 显示适配的工程师提供一条可直接落地的路径,少走点弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询