上个月给一块 RK3399 平台的板子调 MIPI 屏,换了分辨率和时序参数后,我把kernel侧的 DTS 改完、重编resource.img、刷机、重启,屏幕在 Android 起来后正常点亮。隔天硬件同事跑过来问了一句:U-Boot 里的 DTS 不用同步改吗?我愣了一下,因为在他的印象里,屏幕能不能亮、时序对不对,应该由 DTS 统一说了算。但实际上在 Rockchip 平台,调屏这件事的"真正控制权"经常不在 U-Boot DTS 里。这篇就把 RK 显示链路中 U-Boot 和 kernel 各自负责什么、为什么常见的调屏操作可以不动 U-Boot DTS、以及什么情况下必须回头动它,完整梳理一遍。
先说结论:RK 平台调屏"无需修改 U-Boot DTS"是有前提的——它指的是单纯调整屏幕时序、分辨率这一类"屏参"时,U-Boot 侧多数情况下并不是靠改 DTS 来生效的,而是依赖 U-Boot 代码里的屏幕参数表;而最终用户看到的画面又是 kernel 启动后由 DRM 子系统重新初始化的。理解这条链路,你就不会被"两个 DTS 要不要同步改"这个问题卡住。
1. 显示链路拆解:U-Boot 和内核各管哪一段
想弄明白"要不要改 U-Boot DTS",先得看清 RK 平台从上电到系统起来的显示流程到底经历了什么。
1.1 U-Boot 阶段:为开机 logo 做最小初始化
板子上电后,U-Boot 要完成 DDR 初始化、时钟配置、外设探测,然后才是显示相关初始化。Rockchip 的 U-Boot 里有一套独立的显示驱动,路径通常在u-boot/drivers/video/drm/rockchip/下,核心文件包括rockchip_display.c、rk_screen.c、rk_mipi_screen.c等。U-Boot 会根据它自己那份 DTS 中display-timings节点或者代码里的屏幕参数表,配置 VOP(Video Output Processor)、DSI/LVDS/HDMI 等输出控制器,分配一块 framebuffer,把 logo 画上去。
注意这里有一个容易混淆的点:U-Boot 使用的 DTS 和 kernel 使用的 DTS 在 RK SDK 里是两套独立的东西。U-Boot 编出来的rk3399-evb.dtb放在 U-Boot 分区,kernel 使用的 DTS 则打进resource.img或boot.img。它们在源码树里可能有相似的结构,但并不是同一份文件,改了 kernel DTS 不会自动同步到 U-Boot DTS。
1.2 内核阶段:DRM 接管并重新初始化显示
内核启动后,DRM/KMS 子系统会接管显示设备。RK 平台的 DRM 驱动会读取内核自己那份 DTS 中的 panel、route、output 节点,重新做一次完整的显示链路初始化。U-Boot 阶段分配好的 framebuffer、时序参数,在内核初始化后会被重新配置,最终用户看到的桌面、UI 实际上是内核 DRM 驱动工作的结果。
因此从结果上看:只要内核 DTS 配置正确,就算 U-Boot 阶段的 logo 显示参数是旧的,甚至 U-Boot 下画面偏移、花屏,内核起来后也会被修正。这就是很多人"只改 kernel DTS 也没出问题"的根本原因。
1.3 U-Boot 传给内核的显示参数是什么
这里还要补一个细节。U-Boot 在跳转内核前,会把自己初始化好的显示信息通过设备树或 bootargs 传递给内核,比如分辨率、像素时钟、framebuffer 地址等。内核的 DRM 驱动在早期会参考这些参数做显示继承,避免内核起来的一瞬间屏幕闪黑或花掉。但这些参数只是"过渡参考",DRM 驱动仍然会以内核自身 DTS 为准重新配置。如果两套参数差得太多,就可能出现内核起来时屏幕先闪一下、再正常的情况。
所以,U-Boot 的显示体系和内核的显示体系,是"接力棒"关系,不是"同一套配置都被两个系统读取"的关系。
2. 调屏真正改的是哪套文件:内核 DTS 为主,代码表为辅
既然最后显示效果由内核接管,那调屏的主战场就很清楚了:绝大多数情况下,你要改的是 kernel DTS。但 U-Boot 那侧有它自己的"存货地点",搞清楚这些文件,就能理解为什么标题里说"无需修改 U-Boot DTS"。
2.1 U-Boot 侧的屏参实际放在代码表里
RK 的 U-Boot 中,屏幕的时序参数并不总是写在 DTS 里。特别是 MIPI 屏,U-Boot 维护了一张屏幕面板表,常见位置是u-boot/drivers/video/drm/rockchip/rk_mipi_screen.c。文件里定义了一组rk_mipi_panel_data数组,每种屏幕对应一个面板名、一组时序参数、以及初始化序列:
static const struct rk_mipi_panel_data rk_mipi_panel_data[] = { { .name = "boe_tv055wxm", .panel_id = 0x00000000, .hactive = 1920, .vactive = 1080, .clock = 148500, .hsync_len = 44, .hback_porch = 148, .hfront_porch = 88, .vsync_len = 5, .vback_porch = 36, .vfront_porch = 4, ... }, };U-Boot 在选择显示模式时,会先匹配面板名或 ID,从这张表里取参数。所以当你只是调整了某款屏的 porch、clock 这类参数时,U-Boot DTS 根本不会参与,对应的改动在代码层,或者跟开发板配置相关。这也是很多 RK 工程师习惯把"调屏"和"改 U-Boot"分开看的原因。
2.2 Kernel DTS 里真正生效的节点
到了内核侧,时序参数就得老老实实写进 DTS 了。RK 的 kernel DTS 中,常见结构是在对应输出接口下挂 panel 节点,然后在 panel 节点内部写display-timings。以 MIPI DSI 为例:
&dsi { status = "okay"; panel@0 { compatible = "simple-panel"; reg = <0>; backlight = <&backlight>; enable-gpios = <&gpio7 15 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; display-timings { timing0 { clock-frequency = <89000000>; hactive = <1280>; vactive = <800>; hfront-porch = <32>; hback-porch = <32>; hsync-len = <1>; vfront-porch = <20>; vback-porch = <8>; vsync-len = <3>; hsync-active = <0>; vsync-active = <0>; pixelclk-active = <0>; }; }; }; };clock-frequency、hactive、vactive、各个 porch 和 sync len 这些参数,就是屏厂规格书里最核心的一组数字。改错一个 HFP 或 VFP,画面上可能出现整屏偏移、局部闪烁、刷新率不对等问题。另外还要注意route系列节点,例如route_mipi、route_hdmi、route_edp,它们控制具体哪条输出通路被启用。新屏接入时,要确保对应 route 的status = "okay",并且connect属性正确指向你要用的接口。
2.3 什么情况下内核 DTS 能完全覆盖 U-Boot 显示
只要内核的 DRM 驱动能正常 probe,它就会把显示链路完整重跑一遍:VOP 重新分配 overlay、DSI 重新触发控制器、panel 重新执行初始化序列。所以哪怕 U-Boot 阶段用的还是旧屏参,内核起来后也会准确切换到新的配置。这也是"U-Boot DTS 不一定要改"的最直接原因。
但反过来,如果你连 U-Boot 阶段都看着不顺眼,或者产品要求从上电到开机的整个过程都显示正常,那就不能完全不管 U-Boot。这里的"管"不一定是改 DTS,更可能是更新代码层屏幕表或者编译配置。
3. 两套 DTS 对齐:为什么偶尔还是要补 U-Boot
讲到这里,肯定会有人问:"既然内核能覆盖,那 U-Boot 侧不管行不行?"多数场景行,但有些边界情况会翻车。问题的核心在于 RK SDK 里 U-Boot DTS 和 kernel DTS 之间存在一种"弱关系"。
3.1 U-Boot DTS 与 Kernel DTS 的关系
RK 各平台的 U-Boot DTS 通常会从 kernel DTS 的基础文件裁剪而来,比如rk3399.dtsi、rk3399-evb.dts,再叠加一个rk3399-u-boot.dtsi来声明引导阶段需要的节点。你可以把 U-Boot DTS 理解为"kernel DTS 的精简版 + 启动专用配置"。它只保留 U-Boot 需要的外设节点,比如串口、PMIC、GPIO、显示通路、存储等。
所以如果你在 kernel DTS 里新增了一个backlight节点或一个pinctrl配置,U-Boot 那边并不会有。如果 U-Boot 阶段恰好需要这个 GPIO 来点亮背光或拉高 panel 复位脚,那 U-Boot DTS 里也得有对应节点,否则 U-Boot 的显示驱动会找不到 pin,导致 logo 阶段黑屏。
3.2 时序参数不一致时会发生什么
另一种让人头疼的情况是:U-Boot 代码表里那组屏参和 kernel DTS 里那组不一致。U-Boot 先按旧参数点亮屏幕,内核起来后按新参数重启显示链路,切换瞬间屏幕会闪、会黑,甚至在某些严格的 panel 上出现不进状态机、白屏的问题。这个细节在量产阶段特别容易被忽略——单机测试可能看不出来,但同一批板子中电源、时钟时序稍有差异,问题就暴露了。
我的做法是每次调屏都先把屏厂规格书里那组 H/V 参数整理出来,分别填到 U-Boot 代码表和 kernel DTS 里,保证两边完全一致。省得后续排查问题时,分不清是驱动 bug 还是两套配置打架。
3.3 GPIO 与电源控制也要对齐
显示链路不只是时序,还有 panel 的供电、复位、背光时序。比如屏的reset-gpio在 U-Boot 阶段要拉高拉低,这组 pinctrl 如果只在 kernel DTS 里使能,而 U-Boot DTS 里没配,那 U-Boot 连 logo 都起不来。生产调试时如果发现 U-Boot 阶段黑屏、内核起来后正常,优先查的就是这类 GPIO/regulator 节点,而不是反复改时序参数。
4. 哪些场景需要动 U-Boot DTS
聊完原理,列一个更直接的判断框架。下表是我在实际项目中总结出来的场景对照。
| 场景 | 是否需要改 U-Boot DTS | 说明 |
|---|---|---|
| 只调整分辨率、porch、clock 等屏参 | 通常不用 | U-Boot 侧靠代码表,kernel 侧改 DTS |
| MIPI 换 LVDS、EDP 换 RGB 等接口切换 | 必须改 | U-Boot 也要切换输出通路和 route 配置 |
| 新增面板 GPIO 控制、背光 PWM、regulator | 可能要改 | 如果 U-Boot 阶段就要点亮 panel,必须同步节点 |
| 多屏同显或副屏显示 logo | 必须改 | 要在 U-Boot DTS 中同时使能多个 route 和输出节点 |
| 只关心系统起来后的 UI 显示 | 不用改 | 内核 DRM 会重新初始化,但注意切换瞬时闪屏 |
逐个展开说。
4.1 换屏参:U-Boot DTS 可以不动
这是最常见的场景。屏厂发来新规格书,分辨率从 720p 升到 1080p,porch 改了几个数值,时钟频率变了。这种改动主要落在 kernel DTS 的display-timings上。U-Boot 侧如果代码表里正好有对应面板,你可以在rk_mipi_screen.c或rk_screen.c里同步改一下,让 logo 阶段也正确显示。如果 U-Boot 侧没有这张屏的表,U-Boot 默认走它自己的兜底模式,只要 kernel 起来后正常,通常不会影响功能。
4.2 接口通路切换:U-Boot DTS 必须改
比如原来走 MIPI DSI,现在改成 LVDS。这种改动不只是加一个 panel 节点,而是要把输出控制器从&dsi换成&lvds,同时确认对应 VOP 端口和 route 节点改成okay。U-Boot 如果没有这些节点配置,它根本不知道往哪个接口输出画面,logo 阶段就黑了。严格来说这不算"调屏参",而是"改显示通路",必须两套 DTS 一起动。
4.3 电源、复位、背光控制:看 U-Boot 阶段是否需要
如果产品对开机 logo 有要求,那么 U-Boot 阶段就要保证 panel 上电、复位、背光亮,这些 GPIO/PWM/regulator 控制必须出现在 U-Boot DTS 里。反过来,如果产品允许开机阶段黑屏或只要求 logo 能出个大概,那这部分可以先放一放,等内核起来再点亮。
4.4 多屏显示场景:U-Boot 阶段也要调度
RK 平台支持 HDMI + MIPI 同显这类需求。如果 U-Boot 阶段就要在副屏上显示 logo,就必须在 U-Boot DTS 中配置好两个 route 节点和对应输出控制器。这里没有捷径,两套 DTS 都要仔细对齐,否则 U-Boot 只会默认点亮主屏,副屏一路黑到内核起来。
5. 真机调屏复盘:从黑屏到点亮的过程
讲一个最近的真实排障过程,算是把上面的理论落到实操。
板子是 RK3288,配一块 7 寸 MIPI 屏,1024x600。现象是 U-Boot logo 正常,内核起来后屏幕全黑,只有背光亮。客户坚持认为"U-Boot DTS 里也要改时序",但当时 U-Boot 阶段已经是正常的,问题大概率出在内核侧。
5.1 第一步:确认 U-Boot 阶段是否真的正常
先把 U-Boot 串口日志拉出来,看到dsi初始化、vop配置、framebuffer分配都是成功的,logo 也确实显示过。这就说明屏本身、线序、供电、背光、U-Boot 的显示通路都没问题。排障重心立刻转向内核侧。
5.2 第二步:查内核日志里 panel 和 dsi 的状态
抓dmesg,过滤关键字:
adb shell dmesg | grep -iE "dsi|panel|vop|clk|dclk|fb"日志里卡在panel-simple: probe failed。进一步查看完整 log,发现reset-gpio对应的 GPIO 被另一个驱动占用了。原来 kernel DTS 里 panel 的reset-gpios配的是&gpio0 6,但这个 GPIO 同时被 touch 驱动注册成中断脚,导致 probe 时序错乱。
这里有一个非常典型的点:U-Boot DTS 是极简的,不会挂 touch 驱动,所以 GPIO 没有冲突;内核 DTS 设备多,同一个 GPIO 可能被多个节点描述,不改 pinctrl 就会冲突。
5.3 第三步:修正 GPIO 复用并重新验证
把 touch 节点里冲突的 GPIO 换掉,或者在 panel 节点里显式声明pinctrl-0,把该 GPIO 先申请为gpio功能。重新编译内核、打包resource.img、刷机。开机后dmesg里能看到 panel 的display-timings被正确解析,屏幕正常点亮。
5.4 如果 U-Boot 阶段也黑屏,该怎么查
如果 U-Boot 阶段同样黑屏,排查顺序应该是:
- 先看 U-Boot DTS 里
route_mipi/route_lvds的 status 是否 okay。 - 看 U-Boot 代码里是否已登记这块屏的 panel 表:
rk_mipi_screen.c中有没有对应屏名,没有就按规格书补一组数据。 - 看 U-Boot 的编译配置,确认
CONFIG_ROCKCHIP_DRM、MIPI DSI 相关宏是否打开。 - 再看 U-Boot DTS 中的 GPIO、背光节点是否存在,panel 的供电是否在 U-Boot 阶段完成。
这一步一步走下来,就会发现大多数"U-Boot 不亮"的问题,根因并不在时序,而在节点缺失或配置开关没开。
6. 说点经验之外的话:新屏适配的操作顺序
最后分享一套我个人在新屏项目上固定使用的流程,也是我判断"要不要动 U-Boot DTS"时的依据。
先确认接口类型和硬件连接方式,包括 lane 数、电平、供电电压、复位脚极性,这些信息决定了后续要动哪些节点。然后在 U-Boot 阶段想办法把屏点亮,哪怕只是点亮背光和输出纯色信号,这一步能尽早暴露硬件连接问题。接着把屏参同步到 U-Boot 代码表和 kernel DTS,逐一验证时序参数。内核起来后重点看dmesg里 DSI/panel/clock 相关日志,出现 probe 失败就从上到下排查 GPIO、regulator、时钟树。最后如果产品对开机 logo 有要求,再回头整理 U-Boot DTS 的必要节点,和 kernel 保持同一份屏参标准。
调屏调久了你会发现,"U-Boot DTS 改不改"这个问题真正想问的是:两套显示配置到底以谁为准。RK 平台的设计逻辑是 U-Boot 负责快速点亮、内核负责完整接管,所以屏参层面的改动通常落在内核 DTS 上,U-Boot 侧靠代码表就能覆盖大部分场景。只有碰到接口切换、多屏显示、早期 GPIO 控制这类"显示通路"层面的需求,U-Boot DTS 才会成为必改项。下次再有人问"要不要同步 U-Boot DTS",你可以先反问一句:U-Boot 阶段现在正常吗?正常就不用动,不正常再去查代码表和节点,别上来就埋头改 DTS。