RK3568 的多路显示移植—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
驱动骨架到这里够用了。从今天起点屏。RK3568 能接好几种显示口,但这套系统同一时刻只能把一路当主屏。

背光亮了,画面却停在 U-Boot 那个 logo 上。你摸了一下屏,图标没反应。旁边 HDMI 口若还插着显示器,桌面说不定正跑在那台显示器上,这块真屏只是一块会发热的灯板。
第一反应通常是 panel 型号写错、DCS 序列缺了、时序不对。三种都可能,但开源鸿蒙在 RK3568 上最常见的原因更土:设备树里同时 okay 了两路显示。Linux 上 Weston 可以 LVDS 和 HDMI 一起亮,开源鸿蒙的 composer 不行。谁先向 DRM 注册,谁就被当成主显示。没接的那路若是 simple-panel,它会永远上报 connected,桌面就被渲到空气里。
这不是屏的事,是整条显示栈的所有权问题。HDMI、MIPI DSI、LVDS、RGB、eDP、RGB-VGA,同一时刻只允许一路 okay。后面几篇会按接口拆开写。这篇先把「为什么只能亮一块」钉死,否则你改 LVDS 时序、改 HDMI 的 EDID、改 MIPI 的 init sequence,全是在错误的路上加补丁。
官方两张图对着看。第一张是 HDF 的 Display 模型,第二张是图形子系统。你会在图里看到 composer、HDI、驱动,看不到 VOP2 的 Video Port——那是芯片 DRM 的事,图没画,板上天天咬人。


HDMI 那根线怎么接到连接器上,图放在 HDMI 那篇。MIPI DSI 的发送接收图放在 MIPI 那篇。这篇不靠连线图,靠注册顺序和分区。
产品名按全书约定:rk3568_evb。板级设备树:
device/board/rk/rk3568_evb/kernel/rk3568-evb-linux.dts
厂商配置在 vendor/rk/rk3568_evb/。编译:
./build.sh --product-name rk3568_evb --ccache
你仓库目录名不同,全局替换即可。判断问题的方法不换。
现象:真屏只有背光,HDMI 上有桌面
玻璃屏背光亮着,画面停在 logo。HDMI 显示器上桌面在跑。或者反过来:HDMI 无信号,LVDS 上有桌面——你以为要测 HDMI。
原因
开源鸿蒙的 composer 同一时刻只喂一路主显示。DRM 连接器列表里谁先以 connected 出现,谁就被选中。
HDMI 是真热插拔。没插线是 disconnected,插上是 connected。LVDS、RGB、很多 MIPI、很多 eDP 写成 compatible = "simple-panel"。simple-panel 没有 HPD,节点 okay 的那一刻就永远 connected。哪怕排线没插,DRM 也认为有屏。
rockchip-drm 把 VOP、HDMI、LVDS、DSI 当 component 绑。LVDS 常常比 DSI 早零点几秒完成绑定。composer 取列表第一个 connected 的连接器。于是 MIPI 屏背光亮着(enable-gpio 被 panel 点了),画面停在 U-Boot logo(内核曾在这块屏上画过,后来主显示切走了),桌面渲到 LVDS-1 上,那头没接屏。
bootanimation 的 ready / finished 照样打出来,因为渲染栈认为自己成功提交了帧。串口看起来「显示已经好了」。人眼看真屏,只有 logo。
Linux 的 Weston 可以 LVDS-1 和 DSI-1 一起 enable。拿 Linux 日志当「两块屏都该亮」会误判。开源鸿蒙不是 Weston。
RGB 和 RGB-VGA 抢同一组 LCDC 管脚,更不是两路同亮。eDP 和 RGB 在 Linux 镜像里有时双开当扩展桌面,开源鸿蒙不要学。
代码:同一时刻只 okay 一路
切换必须成对。四件套是:
- panel 节点(
lvds-panel/tft-lcd-panel/ DSI 里的panel@0/edp-panel) - 控制器(
&lvds/&hdmi/&dsi1/&rgb/&edp) - 入口(
&lvds_in_vp2/&hdmi_in_vp0/&dsi1_in_vp1/&rgb_in_vp2/&edp_in_vp0) - 路由(
&route_lvds/&route_hdmi/&route_dsi1/&route_rgb/&route_edp)
忘关 &hdmi,是 MIPI 或 LVDS 只亮背光的头号原因。HDMI 控制器 okay 了,连接器一旦 connected,composer 优先跟它走。真屏的 panel 驱动照样 probe、背光照样亮,只是没人往那条 VP 提交桌面帧。
只开 HDMI、其余全关:
&hdmi { status = "okay"; };
&hdmi_in_vp0 { status = "okay"; };
&hdmi_in_vp1 { status = "disabled"; };
&route_hdmi { connect = <&vp0_out_hdmi>; status = "okay"; };
&video_phy0 { status = "disabled"; };
&lvds_in_vp2 { status = "disabled"; };
&lvds { status = "disabled"; };
&route_lvds { status = "disabled"; };
&lvds_panel { status = "disabled"; };
&rgb_in_vp2 { status = "disabled"; };
&rgb { status = "disabled"; };
&route_rgb { status = "disabled"; };
&tft_lcd_panel { status = "disabled"; };
&edp_in_vp0 { status = "disabled"; };
&edp { status = "disabled"; };
&edp_panel { status = "disabled"; };
&dsi1 { status = "disabled"; };
&dsi1_in_vp0 { status = "disabled"; };
&dsi1_in_vp1 { status = "disabled"; };
&route_dsi1 { status = "disabled"; };
&dsi0 { status = "disabled"; };
&dsi0_panel { compatible = "simple-panel-dsi-disabled"; };
&dsi0_in_vp0 { status = "disabled"; };
&dsi0_in_vp1 { status = "disabled"; };
&route_dsi0 { status = "disabled"; };
只开 LVDS:
&video_phy0 { status = "okay"; };
&lvds_in_vp2 { status = "okay"; };
&lvds { status = "okay"; };
&route_lvds { connect = <&vp2_out_lvds>; status = "okay"; };
&lvds_panel { status = "okay"; };
&hdmi { status = "disabled"; };
&hdmi_in_vp0 { status = "disabled"; };
&hdmi_in_vp1 { status = "disabled"; };
&route_hdmi { status = "disabled"; };
&rgb_in_vp2 { status = "disabled"; };
&rgb { status = "disabled"; };
&route_rgb { status = "disabled"; };
&tft_lcd_panel { status = "disabled"; };
&edp_in_vp0 { status = "disabled"; };
&edp { status = "disabled"; };
&edp_panel { status = "disabled"; };
&dsi1 { status = "disabled"; };
&dsi1_in_vp0 { status = "disabled"; };
&dsi1_in_vp1 { status = "disabled"; };
&route_dsi1 { status = "disabled"; };
&dsi0 { status = "disabled"; };
&dsi0_panel { compatible = "simple-panel-dsi-disabled"; };
&dsi0_in_vp0 { status = "disabled"; };
&dsi0_in_vp1 { status = "disabled"; };
&route_dsi0 { status = "disabled"; };
DSI 的 panel 不能只改 status。HDF Display 入口可能做一次 of_find_compatible_node(..., "simple-panel-dsi")。这个查找按字符串走,不一定跳过 disabled 节点。抓住一份你已经关掉的屏,后面 panelManager 空,/dev/dri/card0 可能不建。所以 compatible 改成 simple-panel-dsi-disabled。节点本身不能删,endpoint 还引用着,删了 dtc 报 unresolved reference。
PHY 也要配套。LVDS 用 &video_phy0。切到 RGB 并行时关掉它,否则 PHY 和 RGB 管脚打架。MIPI 常用 &video_phy1。HDMI 有自己的 PHY。切屏时 PHY 不当成第五件套,回头会在 RGB 镜像上留下一个无意义的 LVDS PHY。
&lvds 里还要有 endpoint,指向 panel 的 panel_in_lvds。缺这段,控制器 okay 了也连不上屏。完整节点在 LVDS 那篇。
为什么必须成组?status 是四个独立开关。你关了 &hdmi,忘了 &route_hdmi,路由还指着 VP0。你关了 &lvds_panel,忘了 &lvds,simple-panel 没了,控制器仍可能建一个无 panel 的连接器。四件套一起改。
口和连接器名字对照:
| 接口 | DRM 连接器 | 常见 VP | panel 写法 | 热插拔 |
|---|---|---|---|---|
| HDMI | `card0-HDMI-A-1` | VP0 | 无 simple-panel,走 EDID | 有,没插线 = disconnected |
| MIPI DSI1 | `card0-DSI-1` | VP1 | `simple-panel-dsi`,带 DCS | 无 |
| MIPI DSI0 | DSI-0 / DSI-1 | VP0/VP1 | 同上 | 无 |
| LVDS | `card0-LVDS-1` | VP2 | `simple-panel`,无 DCS | 无 |
| RGB 并行 | `card0-DPI-1` | VP2 | `simple-panel` | 无 |
| eDP | `card0-eDP-1` | VP0 | simple-panel 或带 HPD | 看有没有 `hpd-gpios` |
| RGB-VGA | 走 RGB 管脚 | VP2 | 和 RGB 共脚 | 视 DAC |
现象:改了 dts,重启屏还是旧的
设备树里 &hdmi 已经 okay,LVDS 已经 disabled。重启以后 /proc/device-tree 里 LVDS 还是 okay。
原因
真正生效的 DTB 是 resource 分区 p4 里的 rk-kernel.dtb,不是 boot_linux 里的 toybrick.dtb。U-Boot 在这块平台上常常从 resource 取出 dtb 再启动内核。你刷 p5 换的是那份不上班的 dtb。
/dev/block/by-name/ 下面那些名字永远指向 eMMC,哪怕你现在从 SD 启动。U-Boot 也常从 eMMC 取 resource 和 boot_linux。从 SD 启动、只刷了 mmcblk1p4,eMMC 的 p4 还是旧的,启动仍走旧树。
dd 写成 /dev/mmcblk1p4。这个路径常常不是块设备,dd 会在 /dev 下新建一个普通文件,返回成功,字节数对,md5 也对,重启画面不变。必须写 /dev/block/mmcblkXpY。
内核 GN 经常不盯 board 目录。你改了 rk3568-evb-linux.dts,ninja 认为内核没变,out/ 里躺着昨天的 resource.img。打包脚本把它拿走,你「编过了」仍是旧 dtb。
代码
刷之前先看介质,不要凭记忆。SD 是 mmcblk1,eMMC 是 mmcblk0,以容量为准。resource = p4,boot_linux = p5。
hdc shell "cat /proc/partitions"
hdc shell "mount | grep ' on / '"
hdc shell "ls -l /dev/block/mmcblk0p4 /dev/block/mmcblk1p4"
hdc shell "ls -l /dev/block/by-name/resource /dev/block/by-name/boot_linux"
hdc shell "ls -l /dev/mmcblk1p4 /dev/block/mmcblk1p4"
/dev/mmcblk1p4 若是普通文件,先删掉。只认 /dev/block/ 那一份 brw。
hdc file send resource.img /data/resource.img
hdc file send boot_linux.img /data/boot_linux.img
hdc shell "dd if=/data/resource.img of=/dev/block/mmcblk1p4 bs=4M conv=fsync"
hdc shell "dd if=/data/resource.img of=/dev/block/mmcblk0p4 bs=4M conv=fsync"
hdc shell "dd if=/data/boot_linux.img of=/dev/block/mmcblk1p5 bs=4M conv=fsync"
hdc shell reboot
SD 启动也写 mmcblk0p4。两块介质的 p4 写成一样,U-Boot 无论读谁都是新树。
主机上先确认 resource 里的 dtb 是新的:
ls -l out/rk3568_evb/packages/phone/images/resource.img
# 解开后:
resource_tool --unpack --image=out/rk3568_evb/packages/phone/images/resource.img
dtc -I dtb -O dts -o /tmp/now.dts rk-kernel.dtb
grep -n 'hdmi\|lvds-panel\|simple-panel-dsi\|clock-frequency' /tmp/now.dts | head -50
resource 是 RSCE 包,里面至少有 rk-kernel.dtb、logo.bmp、logo_kernel.bmp。logo.bmp 换了但 dtb 没换,开机画面变、屏口不变。旧 resource.img 躺在 out/ 里会被直接拿走,改 dts 之后要删:
rm -rf out/kernel/checkpoint
rm -f out/kernel/src_tmp/linux-5.10/resource.img
rm -f out/rk3568_evb/packages/phone/images/resource.img
./build.sh --product-name rk3568_evb --ccache
板上验收生效的是哪一份树:
hdc shell "cat /proc/device-tree/lvds-panel/status; echo"
hdc shell "find /proc/device-tree -name compatible | xargs grep -a simple-panel"
hdc shell "find /proc/device-tree -iname '*hdmi*' | head"
status 是带结尾空字符的原始属性,cat 之后要自己加个换行。和你刚改的 dts 对不上,就是刷错分区或刷错介质。
现象:卡在 logo,串口还能敲命令
屏上停着 U-Boot 或内核 logo。hdc 已经能连。你开始改 panel 时序。
原因
先把两个「亮」分开。它们看起来都是屏上有东西,出事的层完全不同。
上电之后,U-Boot 按自己那份设备树把 VOP 打开,把 logo.bmp 踢到帧缓冲。内核接棒,DRM 起来,可能再刷一张 logo_kernel.bmp。串口看到:
[drm] Initialized rockchip 1.0.0 ...
再加上 /dev/dri/card0 出现,内核显示已经活了。logo 能停在屏上,说明 VP、PHY、连接器、时序至少跑通了一路。
桌面是另一件事。应用画到 Surface,RenderService 合成,HDF 的 Display 把层交给用户态 composer,composer 再通过 HDI 把帧提交给 DRM。哪一个进程没起来,屏就停在最后那张内核 logo 上。你盯着 logo 改 panel 时序,改一百次也还是那张图。
所以看见「卡 logo」先问:[drm] Initialized 出现过没有?
从没出现,才是内核显示没起来。VOP 没绑上、输出组件没到齐、设备树把唯一的屏口关掉了。/dev/dri/card0 往往也不在。display-subsystem bound fe040000.vop 反复出现,说明 VOP 等组件,输出侧没到齐。
出现过,logo 也在,卡的是用户态。常见三条。SystemUI / Launcher 没起来,窗口服务器没有层可交。hap 没签名,BMS 首启拒装,SystemUI 静默缺席,HWC 的 layer map 就是空的,composer 刷 layer map is empty, drop this frame。RenderService 自己退了,255 先查 vendor 的 GPU / composer so。plane 分给了 disabled 的 VP,summary 里 ACTIVE 的 VP 下面没有 overlay。
还有第三层:桌面其实起来了,屏被关掉。串口有 bootanimation.finished,有 wms.fullscreen.ready。dmesg 里 blank=4、display off。这是电源管理的超时休眠源。首启在装一堆应用,没人点屏,计时器走到就 blank。power-shell wakeup 能唤醒的话,显示栈是好的。真正被加载的配置在 /system/etc/power_config/power_suspend.json,往 /vendor 放一份盖不住。
第四层:你看的那块屏根本不是主显示。simple-panel 抢主显示,第一节写过。
还有一个不是休眠、也黑屏的:regulator late cleanup。LVDS 供电节点只有 regulator-boot-on、没有 consumer,大约 37 秒内核把「没人用的 boot-on 电源」关掉。dmesg 出现 vcc3v3_lcd_lvds: disabling。这是 LVDS 那篇的主角,HDMI 遇不到。
failed to init overlay plane Cluster0-win0 这种字,能出桌面的镜像里也有,不出桌面的镜像里也有。它不是判据。VOP2 的 Cluster plane 在这块芯片上经常 init 失败,驱动会退到 Smart / ESMART。别被它带去改 cursor、改 plane 掩码,除非你已经证明 VP 把唯一能用的 plane 分给了一个 disabled 的 Video Port。
代码
hdc shell "dmesg | grep -iE '\\[drm\\] Initialized|rockchip-drm|vop|simple-panel'"
hdc shell "ls -l /dev/dri/"
hdc shell "pidof render_service composer_host"
hdc shell "hidumper -s RenderService | head -80"
hdc shell "hilog | grep -iE 'RenderService|composer|layer map|dlopen|255|blank'"
hdc shell "power-shell wakeup"
[drm] Initialized 没有:查四件套、PHY、endpoint、HDF 有没有误抓 DSI panel。不要查 SystemUI。
有 Initialized、pidof render_service 为空:查 so 和 hilog,不要改 porch。
pid 在、屏黑:先 wakeup。醒了就是超时。不醒,看 summary 是不是扫错连接器,再看 37 秒有没有 disabling。
现象:render_service 退 255,DRM 是好的
有 logo,有 card0,桌面永远出不来。hilog 里进程退出码 255,夹着 dlopen 失败。
原因
GPU 不在显示线的中间,在旁边。Mali 提供 GLES,RenderService 拿它画 UI。缺 Mali 的 so,RenderService 起不来,DRM 仍然可以显示内核 logo。所以「有 logo 没桌面」和「连 logo 都没有」必须分开查。
vendor 分区里这几份库,少一个都可能让 render_service 以 255 退出:
libdisplay_composer_vdi_impl.z.so
libdisplay_gfx.z.so
libdisplay_composer_vendor.z.so
libdisplay_buffer_vdi_impl.z.so
librga.z.so
libmali-bifrost-g52-g2p0-ohos.so
缺的原因通常不是没编译,是板级 vendor/rk/rk3568_evb/config.json 没声明 rockchip_products 这一类部件。部件没进产品清单,install 阶段不会把 so 拷进 vendor.img。编是成功的,包是缺的。
代码
hdc shell "ls -l /vendor/lib/libdisplay_composer_vdi_impl.z.so"
hdc shell "ls /vendor/lib/chipsetsdk/ | grep -iE 'mali|rga|display'"
hdc shell "pidof render_service"
hdc shell "hilog | grep -iE 'render_service|dlopen|255'"
文件不在,重打 vendor,不要改 dts。config.json 里要让芯片的 composer / RGA / Mali 被产品认领。drivers_peripheral_display_vdi_default 那种通用实现不要和芯片实现抢。文件在、进程仍退,hilog 里 dlopen 的名字会告诉你还缺哪一个。
现象:三个 Video Port,亮错了那个
summary 里 VP0 是 ACTIVE,你接的是 LVDS。或者 VP2 ACTIVE,plane 却写在一个 DISABLED 的 VP 下面。
原因
RK3568 的显示控制器叫 VOP2。不要把它理解成「一块屏的驱动」。它是一个能同时开好几路扫描输出的引擎,每路叫 Video Port。这块芯片常见三个:
| Video Port | 常被接到 | 备注 |
|---|---|---|
| VP0 | HDMI、eDP、有时 DSI | 带宽最大,4K 级优先用它 |
| VP1 | MIPI DSI | 竖屏面板常见走这里 |
| VP2 | LVDS、RGB 并行 | 这块底板的 LVDS 1024×600 走 VP2 |
每个 VP 是 DRM 意义上的 CRTC。连接器通过 in_vp 和 route 接到某一个 VP 上:
&hdmi_in_vp0 { status = "okay"; };
&route_hdmi { connect = <&vp0_out_hdmi>; status = "okay"; };
读成人话:HDMI 这个连接器,从 VP0 的出口接出来。in_vp1 若也 okay,同一连接器挂两个入口,路由会乱。HDMI 那篇把 VP0 打开、VP1 关掉,原因在这里。
VP 上面铺的是 plane。VOP2 的 plane 分几档。Cluster 能做缩放、AFBC,适合当主 UI 层,这块芯片上经常 failed to init overlay plane,失败就别用。ESMART / Smart 是普通 overlay,桌面、开机动画最后都落在这些上面。
plane 要分给某个 VP。分给一个 disabled 的 VP,等于把能画的层挂到一条不通电的扫描线上。composer 去提交帧,硬件不扫,屏上还是 U-Boot 留下的那张图。debugfs 的 summary 里能看见某个 VP 是 ACTIVE、plane 却写在另一个 DISABLED 的 VP 下面——这才是 plane 分配出问题,不是那行 Cluster 初始化失败。
有的设备树会给 VP 写 cursor-win-id,指到 Cluster0:
&vp0 {
cursor-win-id = <ROCKCHIP_VOP2_CLUSTER0>;
};
&vp1 {
cursor-win-id = <ROCKCHIP_VOP2_CLUSTER1>;
};
Cluster 没起来,光标 plane 就是空的,连带把主 plane 的分配搞乱。公版能出桌面的 DTB 往往根本不写这两行。你要对着一份能进桌面的 DTB 做 diff,先看 vop@fe040000 下面是不是多了 cursor。多了就删,不要发明一套 plane 掩码。
带宽也要认。三个 VP 同时扫描高分辨率,PLL 和总线会撑不住。开源鸿蒙这边反正只开一路,带宽不是主矛盾。主矛盾是 composer 只认一个主显示。
图形那张官方图从上往下,落到这块 RK3568 上是这样走的:
ArkTS / Ability
→ 窗口 / RenderService (用户态,system 分区)
→ HDI Display
→ composer_host (用户态,vendor 分区的 so)
→ /dev/dri/card0 (DRM/KMS 节点)
→ VOP2
VP0 / VP1 / VP2
→ HDMI PHY / MIPI DPHY / LVDS PHY / RGB 并行
→ 连接器或屏
HDF Display 模型卡在「HDI 到 DRM」这一截。panel 入口有时还要在内核里被 HDF 用 of_find_compatible_node 找一遍。找不到,/dev/dri/card0 都可能不建。MIPI 那路的 simple-panel-dsi 尤其容易踩。
/sys/class/drm/ 每个文件管什么
验收命令里那一串 cat,拆开看才不会误判。
card0 是 DRM 设备。card0/device/uevent 能看到驱动名。Mali 的 render 节点是 renderD128 一类,那是 GPU,不是连接器。桌面没有,去查 card0,不要去查 renderD。
card0-HDMI-A-1、card0-LVDS-1、card0-DSI-1、card0-DPI-1、card0-eDP-1 是连接器。名字由驱动登记,板子没接的口只要 dts okay,simple-panel 也会出现。目录里有 LVDS-1 不表示玻璃插着。
每个连接器下面常见:
status connected / disconnected
enabled enabled / disabled
modes 可用模式列表
edid 二进制 EDID,HDMI 才有意义
status 对 HDMI 是 HPD。对 simple-panel 永远是 connected。所以 LVDS 的验收不能停在 status。
enabled 表示有没有被某个 CRTC 用着。connected 且 enabled=disabled,就是「插头在,主显示不是它」。回去看 summary 的 ACTIVE 是谁。
modes 对 HDMI 来自 EDID,对 LVDS 来自 dts 的 display-timings。LVDS 的 modes 里有 1024x600,只说明驱动拿了这份 timing,不证明排线插着。
debugfs 的 summary 把 VP、connector、时钟写在一起,是唯一一张「现在到底在扫谁」的表。/sys/class/drm/ 是零件柜,summary 是装配图。两份都要。
hdc shell "ls -l /sys/class/drm/"
hdc shell "for n in /sys/class/drm/card0-*; do echo ==== \$n; echo -n status=; cat \$n/status; echo -n enabled=; cat \$n/enabled; echo; done"
hdc shell "mount -t debugfs none /sys/kernel/debug 2>/dev/null"
hdc shell "cat /sys/kernel/debug/dri/0/summary"
hdc shell "hidumper -s RenderService | head -40"
hidumper 没有输出、pidof render_service 为空,零件柜再漂亮也没有桌面。那是用户态,回头查 so 和签名。
只开 HDMI、显示器已插好时,你希望看到:
/sys/class/drm/card0-HDMI-A-1/status = connected
/sys/class/drm/card0-HDMI-A-1/enabled = enabled
summary 里 VP0 ACTIVE,connector HDMI-A-1
只开 LVDS 时,你希望看到:
summary 里 VP2 ACTIVE,connector LVDS-1,clk 约 51200
U-Boot 阶段有:VOP update mode to: 1024x600p0, type: LVDS0 for VP2
LVDS-1 的 status 是 connected 只能当「驱动认为有屏」,不能当「这块玻璃在」。时钟对了,才算扫的是这条 LVDS。
HDMI 的分辨率跟显示器走,modes 文件里会列出 EDID 给的模式。不要因为 LVDS 是 1024×600,就在 HDMI 的设备树里写死同一组 timing。写死了,遇到 1080p 显示器不是黑就是居中一块小屏。
验收:先认盘,再认连接器,再认合成
下面这组命令按顺序跑。跳过 partitions 直接 dd,是把镜像写成普通文件的最快办法。
# 1. 介质。mmcblk0 一般是 eMMC,mmcblk1 一般是 SD。以容量为准,不要背。
hdc shell "cat /proc/partitions"
hdc shell "mount | grep ' on / '"
hdc shell "ls -l /dev/block/by-name/resource /dev/block/by-name/boot_linux"
# 2. 内核显示有没有起来
hdc shell "dmesg | grep -iE '\\[drm\\] Initialized|rockchip-drm|vop'"
hdc shell "ls -l /dev/dri/"
hdc shell "cat /sys/class/drm/card0/device/uevent"
# 3. 连接器清单。HDMI 看 status;LVDS/DPI/DSI 的 connected 不可全信
hdc shell "ls /sys/class/drm/"
hdc shell "for n in /sys/class/drm/card0-*; do echo ==== \$n; cat \$n/status 2>/dev/null; cat \$n/enabled 2>/dev/null; echo; done"
# 4. 真正扫的是哪一路、时钟多少
hdc shell "mount -t debugfs none /sys/kernel/debug"
hdc shell "cat /sys/kernel/debug/dri/0/summary"
# 5. 设备树是不是你刚刷的那份
hdc shell "cat /proc/device-tree/compatible; echo"
hdc shell "cat /proc/device-tree/lvds-panel/status; echo"
# 6. 用户态合成还活着吗
hdc shell "pidof render_service composer_host"
hdc shell "hidumper -s RenderService | head -80"
hdc shell "hilog | grep -iE 'RenderService|composer|layer map|dlopen'"
改屏之前的顺序。以后从 HDMI 切到 LVDS、从 LVDS 切到 RGB,按这个走,少走两天假成功。
先改 rk3568-evb-linux.dts 的四件套和 PHY,panel 时序按目标屏那篇的数字钉死。HDMI 不要写死 1024×600。DSI 的 compatible 该改就改。
再改触摸。HDF 的 input_config.hcs 里 solutionX / solutionY 跟逻辑分辨率走。LVDS、RGB 常见 1024×600;MIPI 常见 800×1280。只改屏不改触摸,划起来整块玻璃是歪的。内核那颗 gt911@5d 或 touchscreen@38 保持 disabled,总线留给 HDF。HDF 那篇写过抢总线。
然后清内核 checkpoint,重打 dtb 和 resource,顺手重打 boot_linux。Image 里用 strings 或 grep -a 确认新 compatible、新时钟出现过。
刷机先 cat /proc/partitions。resource 写 /dev/block/mmcblkXp4,boot_linux 写 p5。SD 启动也写 eMMC 的 p4。路径带 block。
起来之后用 summary 对 VP、connector、clk。对不上就不要进应用。对上了再看 RenderService 和触摸。
现象对照
表当听诊器。对上现象再动手,别按行号从上改到下。
| 现象 | 先查 | 常见原因 |
|---|---|---|
| 真屏只有背光,logo 不动,旁边 HDMI 有桌面 | `dri/0/summary` 的 connector | `&hdmi` 没关,HDMI 抢主显示 |
| 真屏只有背光,没插 HDMI | 是否还有另一路 simple-panel okay | LVDS/RGB/DSI 谁先注册谁赢 |
| 改了 dts,重启屏还是旧的 | `/proc/device-tree`;刷的是 p4 还是 p5 | 生效 DTB 在 resource,只刷了 boot_linux |
| dd 成功、md5 对、画面不变 | `ls -l /dev/block/mmcblkXpY` | 写成了 `/dev/mmcblkXpY`,建了普通文件 |
| SD 启动、刷了 mmcblk1p4 仍旧 | `by-name` 指向谁;U-Boot 从哪取 resource | U-Boot 读了 eMMC 的 p4 |
| `[drm] Initialized` 从不出现 | 四件套、PHY、endpoint | 内核显示没起来,不是 SystemUI |
| 有 Initialized,有 logo,无桌面 | `pidof render_service`;hap 签名;layer map | 用户态合成,不是 panel 时序 |
| `failed to init overlay plane` | 能不能出桌面的旧镜像是否也有这行 | 经常是红鲱鱼 |
| `render_service` 退 255 | vendor 里 mali / composer 的 so | config.json 没声明 rockchip_products |
| 约 22 秒后黑屏,hdc 还在 | `power-shell wakeup`;hilog 的 blank | 电源超时关屏 |
| 约 37 秒后黑屏,有 `disabling` | regulator 有没有 always-on / consumer | LVDS 供电被 late cleanup 关掉 |
| 桌面出来是竖的一条 | 窗口取向、触摸 HCS 的 solutionX/Y | 显示几何和触摸几何不是同一份配置 |
| Linux 镜像双屏都亮,开源鸿蒙只亮一块 | —— | 预期行为,不是回归 |
| Cluster 失败且 cursor-win-id 指 Cluster | 和能进桌面的 dtb 做 diff | 删掉 cursor-win-id |
最后一行单独说一句。你拿厂商 Linux 的 Weston 当对照,会觉得开源鸿蒙「少亮了一块屏」。Weston 按连接器列表扩展桌面。开源鸿蒙标准系统的 composer 按单主显示设计。不要把 Linux 的双开 DTS 原样抄过来。抄过来的结果不是双屏,是真屏停 logo。
横竖屏是窗口层的事。应用请求竖屏、合成按 600×1024 排,触摸却按 1024×600 报,点就会飞。显示和触摸要一起改。
HDMI 物理口怎么接、EDID 怎么看、黑屏时线插错会怎样,下一篇只谈这一路。LVDS 的 51.2 MHz 和 37 秒断电,再下一篇。MIPI 的 DCS、RGB 的管脚裁剪、eDP 的 HPD,各自一篇。这篇只把「四选一」和「刷哪张分区」放到你会反射的位置。
反射是这两句。同一时刻只 okay 一路;忘关的那路如果是 simple-panel,它会谎称自己还在。改显示刷 p4,只刷 p5 是在跟一份不上班的 dtb 较劲。
现象:U-Boot 有 logo,内核起来之后花了或黑了
两边用的不是同一份设备树。U-Boot 有自己的 dtb,内核用 resource 里的 rk-kernel.dtb。U-Boot 打出 type: LVDS0 for VP2,只能证明 U-Boot 那份树开了 LVDS。内核若仍开着 HDMI,会出现「有过画面,进系统没了」。
反过来也成立。你把内核 dts 改成 LVDS,没刷 p4,U-Boot 继续按旧树在 LVDS 上画 logo,内核切到 HDMI,玻璃停在最后一张 U-Boot 图上。人眼以为内核显示没起来,其实内核在另一口上扫。
所以 U-Boot 那行是旁证,不是内核验收。内核验收永远是 /proc/device-tree 加 dri/0/summary。两份树都要开同一路,切屏才干净。U-Boot 的 dtb 若暂时改不了,至少保证内核四件套和物理屏一致,不要让内核去扫一根空的 HDMI。
resource 里的 logo.bmp 是 U-Boot 画的,logo_kernel.bmp 是内核 DRM 起来后可能再刷的。换 logo 刷 p4 即可,不必动内核 Image。换屏口必须换 dtb,logo 顺便打进同一个 resource。两件事不要拆成「我只换了 logo 怎么屏口也变了」——你刷的是整包 p4。
hdc shell "dmesg | grep -iE 'VOP update mode|type: LVDS|type: HDMI|Initialized'"
hdc shell "cat /proc/device-tree/lvds-panel/status; echo"
hdc shell "cat /sys/kernel/debug/dri/0/summary"
U-Boot 说 LVDS、summary 说 HDMI-A-1,就是两份树在打架。先刷 p4。
现象:RGB 和 VGA 一起 okay,脚乱了
RGB 并行屏和 RGB-VGA 不是两个独立控制器。VGA 插座常常是 RGB 管脚后面接一颗 DAC。同一组 LCDC 脚,不能既喂玻璃又喂 VGA。设备树里 &rgb 打开一次就够,再给 VGA 写一个 simple-panel,等于两颗永远 connected 的连接器抢 VP2。
GPIO3_C3 在 LVDS 上是 panel 使能,在 RGB 上可能是 DEN。两路同时 okay,pinctrl 后写的赢,先写的那路使能脚变成别的功能。LVDS 看起来「控制器 okay 了但不亮」,其实脚已经不是 GPIO。
切镜像时把不用的那路 panel、控制器、route、in_vp 全部 disabled,pinctrl 只留当前这一路。不要靠「后注册的赢」这种时序运气。
eDP 走 VP0,RGB 走 VP2,看起来不抢 VP。Linux 上有人双开当扩展桌面。开源鸿蒙 composer 只认一个主显示,双开的结果仍然是一块屏停 logo。eDP 那篇会写 HPD。这里只要记住:开 RGB 就关 eDP,开 eDP 就关 RGB。
hidumper 和 layer map 怎么读
hidumper -s RenderService 能看到层的尺寸。你希望主层是当前屏的逻辑分辨率:LVDS / RGB 常见 1024×600,HDMI 常见 1920×1080,MIPI 常见 800×1280。看到 720×1280 而屏是 1024×600,窗口取向或产品配置还按竖屏手机走。那不是 timing 错。
composer 日志刷 layer map is empty, drop this frame,表示有合成进程,但窗口服务器没有交出任何层。SystemUI 没起来、Launcher 被 BMS 拒装,都会这样。屏上停着内核 logo,summary 里 planes_changed=0,VP 还在扫开机那张 fb。
hdc shell "hidumper -s RenderService | grep -iE '1024|600|1920|1080|720|1280|layer'"
hdc shell "hilog | grep -i 'layer map is empty'"
hdc shell "bm dump -n | grep -iE 'SystemUI|Launcher'"
有层、有正确分辨率、屏仍黑:回到 DRM 侧,看 summary 扫的是哪一个连接器。没有层:不要改 dts,去查签名和进程。
改屏之前把触摸几何一起改。HDF input_config.hcs 的 solutionX / solutionY 必须跟逻辑分辨率一致。只改屏不改触摸,划起来整块玻璃是歪的。内核 gt911@5d、touchscreen@38 保持 disabled。
从应用画到管脚,中间哪一层死了
图形那张官方图从上往下是 ArkTS、窗口、RenderService、HDI、composer。落到这块 RK3568 还要再往下走 DRM、VOP2、PHY、连接器。每一层的死法不一样,用药不一样。
应用没画:Ability 没起来,窗口服务器空。hap 签名拒装走这里。
RenderService 没画:缺 Mali / composer 的 so,进程退 255。vendor 的 config.json 没声明 rockchip_products 走这里。
composer 没提交:layer map empty。SystemUI 缺席走这里。
DRM 没扫:没有 [drm] Initialized,没有 card0。四件套、PHY、HDF 误抓 DSI 走这里。
扫错口:有 Initialized,summary 的 connector 不是你眼前这块屏。simple-panel 抢主显示走这里。
扫对了但玻璃没电:37 秒 disabling,LVDS 那篇。HDMI 遇不到。
扫对了但被 blank:blank=4,wakeup 能救。电源超时走这里。
把这张清单贴在显示器边上。卡 logo 时从下往上问:有没有 Initialized,summary 扫谁,pidof 有没有号,wakeup 能不能醒。问完再动手,少改三次 porch。
编产品时 vendor/rk/rk3568_evb/config.json 要把芯片显示部件写进去。不写,so 会编,不会进 vendor.img。查:
hdc shell "ls -l /vendor/lib/libdisplay_composer_vdi_impl.z.so"
hdc shell "ls /vendor/lib/chipsetsdk/ | grep -iE 'mali|rga|display'"
文件不在,重打 vendor。文件在、进程仍退,hilog 的 dlopen 会点名。
内核配置三处同步。CONFIG_DRM_ROCKCHIP、HDMI / LVDS 相关开关,写在 source defconfig、out 里那份、build_kernel.sh 里拷进去的那份。缺一处,下次重建丢配置,连接器节点写得再漂亮也没有 card0-HDMI-A-1。新 Image 里 grep -a 能搜到驱动字符串,再刷。
改 dts 不一定要全量用户态。system / vendor 已经能进桌面时,只换显示,刷 resource + boot_linux 就够。缺 GPU 库是另一张镜像的事,和这次切屏口无关。
GN 不盯 board 目录。改 device/board/rk/rk3568_evb/kernel/rk3568-evb-linux.dts 之后删 checkpoint,让 build_kernel.sh 把 dts 拷进内核树再编 dtb。只碰显示开关时不必重编 vmlinux,但 resource.img 必须重打。
rm -rf out/kernel/checkpoint
rm -f out/rk3568_evb/packages/phone/images/resource.img
./build.sh --product-name rk3568_evb --ccache
主机 dtc 反编译,看到你改的 status 再送上板。看不到,编的是旧树。
by-name 永远指 eMMC。ls -l /dev/block/by-name/resource 指向 mmcblk0p4 时,从 SD 启动写 by-name 就是在写 eMMC。这不一定错,因为 U-Boot 可能正是读 eMMC。但你要知道自己在写哪块芯片。保险做法:p4 写两块介质,路径都带 /dev/block/。
活着的树从哪读
/proc/device-tree 是内核解开的那份。改显示之后第一件事不是看屏,是对这棵树。
hdc shell "tr -d '\0' < /proc/device-tree/lvds-panel/status; echo"
hdc shell "find /proc/device-tree -iname '*hdmi*' -o -iname '*lvds*' | head -20"
hdc shell "find /proc/device-tree -name clock-frequency | head"
status 属性带结尾的 \0,cat 会把下一行粘上。tr -d '\0' 之后 okay / disabled 一眼能看出来。和你刚改的 dts 对不上,刷错分区或刷错介质,后面所有 drm 命令都是在盘一份旧树。
/sys/firmware/devicetree/base 和 /proc/device-tree 是同一棵。你更熟哪条路用哪条。不要去 boot_linux 的 ext2 里翻 toybrick.dtb 来证明「我刷过了」——那份不上班。
系列第 16 篇 · 芯片:瑞芯微 RK3568 · OpenHarmony 4.1(API 11) · Linux 5.10
更多推荐



所有评论(0)