LVDS 是差分、时序手写。今天换 MIPI DSI:手机同款软排,要按屏厂的初始化表来。

背光亮了。玻璃上没有桌面,也没有 U-Boot 那张图。旁边 HDMI 口若还插着显示器,图标在那台显示器上。你摸这块竖着的 MIPI 屏,HDF 也许还在报点,点的是空气。

第一反应通常是 panel 型号写错、DCS 序列缺了、lanes 不对。三种都可能。开源鸿蒙在 RK3568 上最常见的原因更土:&dsi1 和 &hdmi 同时 okay。HDMI 抢主显示。DSI 的 panel 照样 probe,reset-gpio 照样翻转,背光 PWM 照样转,composer 把帧交给了另一路连接器。

这块底板常用 DSI1,四 lane,800×1280 竖屏,像素时钟 72 MHz。初始化靠一组 DCS 包,不是 LVDS 那种只写 timing。触摸常见 FT5406,I2C2 地址 0x38,和 LVDS 上那颗 GT911 不是同一颗。

产品名 rk3568_evb。改的文件:

device/board/rk/rk3568_evb/kernel/rk3568-evb-linux.dts

官方这张图画的是 DSI 发送和接收。对着看:SoC 是 DSI host,屏是 device,中间是差分 lane 和一条用来发命令的通道。DCS 就走这条命令通道。没有它,时序写得再漂亮,玻璃停在休眠。 

四选一在显示总论那篇。这里当已经成立:开 DSI1,HDMI / LVDS / RGB / eDP / DSI0 全部关掉。


现象:只有背光,HDMI 上有桌面

dmesg 里有 bound fe070000.dsi,panel 已经 attach。37 秒那批 disabling 列表里没有 MIPI 那路供电——说明 panel 把 regulator 占用了,背光该亮。桌面却不在这块玻璃上。

原因

&dsi1 接到 VP1,&hdmi 接到 VP0,两路都 okay。开源鸿蒙的 composer 同一时刻只驱动一块屏。HDMI 插着线就是真 connected。DSI 是 simple-panel-dsi,节点 okay 也是 connected。谁被选成主显示,帧就跟谁走。日志里偶尔能看到竖屏 720×1280 的 framebuffer 被硬塞进 HDMI 的 VP0,然后 vop2 crtc atomic disable。人眼看 MIPI:背光,没有画。

拔掉 HDMI 线再启动,若这块屏出了 UI,型号和 DCS 就不是第一嫌疑。永久修法不是「拔线」,是 dts 里把 HDMI 四件套关掉。

代码:打开 DSI1,关掉会撒谎的那些口

&video_phy1 { status = "okay"; };

&dsi1 {
    status = "okay";
    /* panel@0 写在控制器里面,见下一节 */
};

&dsi1_in_vp0 { status = "disabled"; };
&dsi1_in_vp1 { status = "okay"; };
&route_dsi1 {
    connect = <&vp1_out_dsi1>;
    status = "okay";
};

&hdmi { status = "disabled"; };
&hdmi_in_vp0 { status = "disabled"; };
&hdmi_in_vp1 { status = "disabled"; };
&route_hdmi { status = "disabled"; };

&video_phy0 { status = "disabled"; };
&lvds { status = "disabled"; };
&lvds_in_vp2 { status = "disabled"; };
&route_lvds { status = "disabled"; };
&lvds_panel { status = "disabled"; };

&rgb { status = "disabled"; };
&rgb_in_vp2 { status = "disabled"; };
&route_rgb { status = "disabled"; };
&tft_lcd_panel { status = "disabled"; };

&edp { status = "disabled"; };
&edp_in_vp0 { status = "disabled"; };
&edp_panel { status = "disabled"; };

connect 必须和 dsi1_in_vp1 一致。写成 VP0 的出口、入口却在 VP1,扫描和连接器不在一路,黑屏,dmesg 不一定骂你。这块底板竖屏走 VP1 是常见接法。VP0 留给 HDMI / eDP 那种带宽更大的口。不要两个入口一起 okay。

PHY 是 video_phy1,不是 LVDS 用的 video_phy0。开错 PHY,DSI 控制器也许还在,差分出不去。


现象:HDMI 已经关掉,仍然没有 [drm] Initialized 的可用连接器

/dev/dri/card0 不建,或者 HDF 日志写 PanelEntryInit of_find_compatible_node fail。你盯着 &dsi1 { status = "okay"; } 看了三遍,它确实 okay。

原因

HDF 的 Display 入口会做一次:

of_find_compatible_node(NULL, NULL, "simple-panel-dsi");

这个查找按 compatible 字符串走,不一定跳过 status=disabled 的节点。DSI0 的 panel@0 若仍叫 simple-panel-dsi,HDF 先抓住 DSI0。DSI0 控制器是 disabled,panelManager 空,后面 /dev/dri/card0 都不建。DSI1 配得再对,桌面也出不来。

节点不能删。dsi0_out 的 endpoint 还引用 panel_in_dsi。删节点,dtc 报 unresolved reference。解法是改名字。

公版 dtsi 还可能给 vcc3v3_lcd1_n 配一只在这块板上不存在的 gpio。regulator 注册失败。dsi1_panel 若写了 power-supply = <&vcc3v3_lcd1_n>,panel probe 无限 EPROBE_DEFER,没有一句显眼的报错。内核没有 DSI connector。删掉那只错误的 gpio,regulator 才能起来。

代码

&dsi0 { status = "disabled"; };
&dsi0_panel { compatible = "simple-panel-dsi-disabled"; };
&dsi0_in_vp0 { status = "disabled"; };
&dsi0_in_vp1 { status = "disabled"; };
&route_dsi0 { status = "disabled"; };

&vcc3v3_lcd1_n {
    /delete-property/ gpio;
    /delete-property/ enable-active-high;
};

真要开 MIPI 时,DSI1 的 panel 必须叫回 simple-panel-dsi。关 MIPI、开别的口时,DSI1 的 panel 也改成 simple-panel-dsi-disabled。两头都叫 simple-panel-dsi,HDF 抓谁是碰运气。


现象:连接器有了,玻璃仍是黑的,背光却亮

summary 里已经是 DSI-1,时钟也在。屏不认。

原因

MIPI 屏上电要一组 DCS。常见两步:0x11 退出休眠,0x29 开显示。前面往往还有一串厂商私有寄存器:gamma、lane、扫向。LVDS 没有这套,RGB 也没有。你把 LVDS 的 timing 改成 800×1280 就指望 MIPI 亮,玻璃停在休眠。

序列写在 panel-init-sequence。编码是 panel-simple-dsi 认的那种:第一字节命令类型,后面是等待和 payload。抄错一个长度,屏可能花、可能白、可能完全无响应。不要凭感觉改。以屏厂提供的 init 表为准。

这块板默认那组 800×1280 的数字:

控制器DSI1
lanes4
格式RGB888
模式video + burst + LPM + EOT
时钟72000000
分辨率800 × 1280(竖)
RSTGPIO4_C1,低有效
触摸FT5406 @ 0x38

规格书封面写 1280×800,那是横着说。设备树按扫出的方向写 800×1280。窗口层再决定横屏还是竖屏。两套数字混用,触摸和画面差 90 度。

代码:panel@0

&dsi1 {
    status = "okay";

    dsi1_panel: panel@0 {
        compatible = "simple-panel-dsi";
        reg = <0>;
        backlight = <&backlight>;
        reset-gpios = <&gpio4 RK_PC1 GPIO_ACTIVE_LOW>;    /* GPIO4_C1 = 145 */
        reset-delay-ms = <60>;
        enable-delay-ms = <60>;
        prepare-delay-ms = <60>;
        unprepare-delay-ms = <60>;
        disable-delay-ms = <60>;

        dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
                      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
        dsi,format = <MIPI_DSI_FMT_RGB888>;
        dsi,lanes = <4>;

        panel-init-sequence = [
            39 00 03 e0 ab ba
            39 00 03 e1 ba ab
            39 00 02 b0 00
            39 00 05 b1 10 01 47 ff
            39 00 07 b2 0c 0e 04 14 14 14
            39 00 04 b3 56 d3 00
            39 00 04 b4 22 30 04
            39 00 02 b5 00
            39 00 08 b6 b0 00 00 10 00 10 00
            39 00 09 b7 0e 00 ff 08 08 ff ff 00
            39 00 08 b8 05 12 29 49 48 00 00
            39 00 04 c5 e8 85 76
            39 00 03 c6 20 20
            39 00 04 d0 27 10 80
            39 00 05 d1 00 0d ff 0f
            39 00 04 e4 08 55 03
            39 00 03 e3 20 21
            05 c8 01 11
            05 14 01 29
        ];

        panel-exit-sequence = [
            05 05 01 28
            05 78 01 10
        ];

        display-timings {
            native-mode = <&mipi_timing>;
            mipi_timing: timing0 {
                clock-frequency = <72000000>;
                hactive = <800>;
                vactive = <1280>;
                hfront-porch = <48>;
                hsync-len = <20>;
                hback-porch = <48>;
                vfront-porch = <16>;
                vsync-len = <6>;
                vback-porch = <15>;
                hsync-active = <0>;
                vsync-active = <0>;
                de-active = <0>;
                pixelclk-active = <0>;
            };
        };

        port {
            dsi1_panel_in: endpoint {
                remote-endpoint = <&dsi1_out>;
            };
        };
    };

    ports {
        port@1 {
            dsi1_out: endpoint {
                remote-endpoint = <&dsi1_panel_in>;
            };
        };
    };
};

最后两包 05 c8 01 11 和 05 14 01 29 就是 sleep out 和 display on,中间带等待。缺这两包,前面的私有寄存器写得再完整,屏也不开。换一块屏,整段 panel-init-sequence 要按那块屏的表换掉,不要只改 hactive

背光仍走 PWM4 的 &backlight&pwm5 保持 disabled,别抢相机的 PWDN。

RST 低有效。probe 时驱动会拉一把。这只脚若被别的节点占成别的功能,芯片停在复位,I2C 上的触摸也可能一起不在。先确认 GPIO4_C1 空闲:

hdc shell "mount -t debugfs none /sys/kernel/debug"
hdc shell "cat /sys/kernel/debug/gpio | grep -E '145|PC1'"

现象:画面在,手指没反应,或坐标差 90 度

原因

这块 MIPI 玻璃上的触摸常是 FT5406,0x38,不是 GT911 的 0x5d。HCS 只留得下一套 device_touch_chip。LVDS 那套 GT911 的 INT/RST 打在 GPIO0_C7 / GPIO2_D0 上,MIPI 这颗 FT5406 的脚是另一组:INT = GPIO2_C2(82),RST = GPIO1_A4(36)。写错组,地址也许还能扫到(芯片靠硬件上电),复位脉冲打到空脚上,寄存器是垃圾。

内核 edt-ft5x06 节点保持 disabled。桌面走 HDF。两边一起 okay,抢 I2C2。

分辨率:屏是 800×1280 竖的,HCS 的 solutionX/Y 必须跟它走。留着 LVDS 的 1024×600,点下去整块玻璃是歪的。窗口取向也要按竖屏处理,否则桌面在 800×1280 的玻璃上横着铺一截。

I2C2 降到 100 kHz。总线上挂着 FPC 和相机分支,400 kHz 下 FT5406 可以全部 NACK。看起来像「没这颗芯片」。

代码

&i2c2 {
    status = "okay";
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&i2c2m1_xfer &mipi_ft5406_int &mipi_ft5406_rst>;

    ft5406_rgb: touchscreen@38 {
        compatible = "edt,edt-ft5406";
        reg = <0x38>;
        status = "disabled";
    };

    gt911_lvds: gt911@5d {
        compatible = "goodix,gt911";
        reg = <0x5d>;
        status = "disabled";
    };
};

HCS:moduleName = "HDF_TOUCH_FT5406"busNum = 2intGpio = 82rstGpio = 36solutionX = 800solutionY = 1280。RGB 并行屏那颗 FT5406 用 GPIO3_B2/B1,不要混。细节在 FT5406 那篇。

验收:

hdc shell "i2cdetect -y -r 2"
hdc shell "i2cget -y 2 0x38 0xa3"
hdc shell "cat /proc/bus/input/devices"

期望 0x38 有应答,0x5d 没有。两个都在,先拔掉不用的那路 FPC。


真正生效的 DTB 在 resource

从 LVDS 切到 MIPI,只刷 p5,U-Boot 仍加载 p4 的旧树。summary 仍是 LVDS-1clk 51200。你会以为 DCS 坏了。

hdc shell "cat /proc/partitions"
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"

路径带 /dev/block/。少了 block,dd 建普通文件,md5 对,画面不变。

主机上确认 dtb 里 DSI panel 叫回了 simple-panel-dsi,HDMI 是 disabled:

dtc -I dtb -O dts -o /tmp/now.dts 那份.dtb
grep -n 'simple-panel-dsi\|hdmi\|800\|1280' /tmp/now.dts | head -40

board 目录经常不在内核 DEPS 里。改 dts 之后删 checkpoint,让 build_kernel.sh 把 rk3568-evb-linux.dts 拷进内核树。最小重建那篇的档 2:先拷,再 make rockchip/rk3568-evb-linux.dtb,目标带 rockchip/ 前缀。

rm -rf out/kernel/checkpoint
rm -f out/rk3568_evb/packages/phone/images/resource.img
./build.sh --product-name rk3568_evb --ccache

只换显示时,刷 resource + boot_linux 就够。


验收:先认盘,再认 DSI-1,再认 72 MHz

hdc shell "cat /proc/partitions"
hdc shell "mount | grep ' on / '"

hdc shell "dmesg | grep -iE '\\[drm\\] Initialized|dsi|simple-panel|vop'"
hdc shell "ls -l /dev/dri/"

hdc shell "ls /sys/class/drm/"
hdc shell "cat /sys/class/drm/card0-DSI-1/status"
hdc shell "cat /sys/class/drm/card0-DSI-1/enabled"
hdc shell "cat /sys/class/drm/card0-HDMI-A-1/status 2>/dev/null"

hdc shell "mount -t debugfs none /sys/kernel/debug"
hdc shell "cat /sys/kernel/debug/dri/0/summary"

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 "pidof render_service composer_host"
hdc shell "i2cdetect -y -r 2"

合格大致是:

summary:VP1 ACTIVE,connector DSI-1,clk 约 72000
card0-DSI-1/status:connected(simple-panel,只能当「驱动认为有屏」)
card0-HDMI-A-1:没有,或 disconnected 且未被选中
lvds-panel/status:disabled
dmesg:有 bound ...dsi,没有无限 EPROBE_DEFER
i2cdetect:0x38 在,0x5d 不在
pidof render_service:有号

时钟是 51200,你还在扫 LVDS。时钟是 HDMI 那档,主显示没切过来。DSI-1 的 connected 和 LVDS-1 一样不可全信,要以 summary 的 connector 名为准。

failed to init overlay plane 能出桌面的包里也有,不是判据。


和 LVDS、HDMI 对打

同一份内核,换 dts 就能在三路之间切。建议真的切一次,否则「HDMI 会抢」只是句子。

切到 MIPI:DSI1 四件套 + video_phy1 + DCS 打开,HDMI / LVDS / RGB / eDP / DSI0 全关,DSI0 panel 改 compatible。刷 p4 和 p5。插不插 HDMI 线,summary 的 ACTIVE 都必须是 DSI-1。若 HDMI 又把桌面抢走,就是 &hdmi 没关干净。

切回 LVDS:按 LVDS 那篇把 1024×600、JEIDA、video_phy0 打开,把 &dsi1 关掉,DSI1 panel 改成 simple-panel-dsi-disabled。HCS 的 solutionX/Y 改回 1024×600,芯片改回 GT911。只换屏不换触摸,划起来是骗子。

HDMI 那路没有 DCS,也没有 800×1280。不要把 MIPI 的 timing 写进 &hdmi


黑屏对照表

现象先查常见原因
真屏只有背光,旁边 HDMI 有桌面`dri/0/summary` 的 connector`&hdmi` 没关,抢主显示
拔掉 HDMI 仍只有背光compatible;DCS;是不是这块玻璃HDF 抓了 DSI0,或 init 序列不是这块屏的
无 `[drm] Initialized` / 无 card0HDF of_find;vcc3v3_lcd1_n误抓 disabled 的 simple-panel-dsi;regulator EPROBE_DEFER
有 DSI-1,屏全黑,背光亮`panel-init-sequence` 最后的 0x11/0x29缺 DCS,玻璃在休眠
花屏、偏色lanes、format、porch四 lane 写成二 lane;时钟不是 72 MHz
改了 dts,仍是 LVDS 时钟`/proc/device-tree`;p4没刷 resource
dd 成功画面不变`ls -l /dev/block/mmcblkXp4`路径少了 `/block/`
能亮不能点i2cdetect 0x38;HCS 脚仍按 GT911 配,或 400 kHz NACK
点下去差 90 度solutionX/Y 800×1280;窗口取向横竖和触摸几何不是同一份
Cluster plane init failed旧包是否也有红鲱鱼

MIPI 比 LVDS 多两件事:DCS,以及 HDF 按 compatible 字符串抓 panel。比 HDMI 多一件事:没有热插拔,connected 不能当验收。三件事叠在「只亮背光」上,看起来像一块屏的三种病,其实是三条链。


现场一条最短路径

dts 已按本文打开 DSI1、关掉其余,DCS 是这块屏的表。串口 1500000 开着。

上电看 Linux version,看 [drm] Initialized,看有没有 bound 到 DSI。没有,停。去查 DSI0 的 compatible 和 lcd1_n 那只 gpio。

hdc 连上。cat /proc/partitions。resource、boot_linux 按 /dev/block/ 写到 p4、p5,eMMC 的 p4 也写。reboot。

起来后读 summary。VP1、DSI-1、clk 72000。对不上:先看 HDMI-A-1 在不在。在,回去关 HDMI。不在而时钟是 51200,刷的还是 LVDS 那份 dtb。

对上了再看 pidof render_service。空的去查 so 和 hilog,不是 DCS。有号、屏黑:DCS 和 RST。背光亮、完全无画,优先怀疑 init 序列不是这块玻璃的。

触摸放到画面稳定之后。i2cdetect -y -r 2 看到 0x38,再划。看到 0x5d,你接的是 LVDS 那块。

这条路径里没有「给 MIPI 写 JEIDA」这一步。JEIDA 是 LVDS 的通道映射。MIPI 讲 lane 和 DCS。


系列第 19 篇 · 芯片:瑞芯微 RK3568 · OpenHarmony 4.1(API 11) · Linux 5.10

Logo

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

更多推荐