驱动骨架到这里够用了。从今天起点屏。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 一路

切换必须成对。四件套是:

  1. panel 节点(lvds-panel / tft-lcd-panel / DSI 里的 panel@0 / edp-panel
  2. 控制器(&lvds / &hdmi / &dsi1 / &rgb / &edp
  3. 入口(&lvds_in_vp2 / &hdmi_in_vp0 / &dsi1_in_vp1 / &rgb_in_vp2 / &edp_in_vp0
  4. 路由(&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 连接器常见 VPpanel 写法热插拔
HDMI`card0-HDMI-A-1`VP0无 simple-panel,走 EDID有,没插线 = disconnected
MIPI DSI1`card0-DSI-1`VP1`simple-panel-dsi`,带 DCS
MIPI DSI0DSI-0 / DSI-1VP0/VP1同上
LVDS`card0-LVDS-1`VP2`simple-panel`,无 DCS
RGB 并行`card0-DPI-1`VP2`simple-panel`
eDP`card0-eDP-1`VP0simple-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.dtblogo.bmplogo_kernel.bmplogo.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=4display 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常被接到备注
VP0HDMI、eDP、有时 DSI带宽最大,4K 级优先用它
VP1MIPI DSI竖屏面板常见走这里
VP2LVDS、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-1card0-LVDS-1card0-DSI-1card0-DPI-1card0-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 okayLVDS/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 从哪取 resourceU-Boot 读了 eMMC 的 p4
`[drm] Initialized` 从不出现四件套、PHY、endpoint内核显示没起来,不是 SystemUI
有 Initialized,有 logo,无桌面`pidof render_service`;hap 签名;layer map用户态合成,不是 panel 时序
`failed to init overlay plane`能不能出桌面的旧镜像是否也有这行经常是红鲱鱼
`render_service` 退 255vendor 里 mali / composer 的 soconfig.json 没声明 rockchip_products
约 22 秒后黑屏,hdc 还在`power-shell wakeup`;hilog 的 blank电源超时关屏
约 37 秒后黑屏,有 `disabling`regulator 有没有 always-on / consumerLVDS 供电被 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@5dtouchscreen@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 属性带结尾的 \0cat 会把下一行粘上。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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐