第6篇:设备树翻译实战:把 Android 4.19 的 DTS 搬到 OpenHarmony 6.6

3 阅读4分钟

本文是《从零到一:把一块 RK3568 开发板移植到 OpenHarmony 6.1 全记录》系列的第 6 篇。讲一次真实的"设备树翻译"全过程:两块系统、两个内核版本、同一块硬件,说明书怎么搬。

上一篇文章认识了设备树。这篇讲实战:同一块板子,Android(内核 4.19)已经有一份能用的说明书,怎么把它变成 OpenHarmony 6.6 内核能读的版本。

我的方法是标准的工程三件套:diff 找差异 → 逐项翻译 → dtc 快速验证

一、先打破一个信息差:OH 6.1 的内核是 6.6

刚开始移植时,我照着网上的旧资料,把板级补丁全放在了 linux-5.10 目录下。等真正编译时才发现:

OpenHarmony 6.1 的默认内核是 Linux 6.6,不是 5.10。

(build/ohos/kernel/kernel.gnilinux_kernel_version = "linux-6.6",网上的 5.10 资料全是旧版本遗留。)

这是整个移植中信息成本最高的一课:方向错了,之前写的设备树全部返工。写这篇文章,就是希望你别再踩。

二、翻译的三个步骤

第 1 步:diff 找差异

原厂 Android 源码里,这块板的说明书在 rk3568-evb1-ddr4-v10.dtsi 等文件里(4.19 语法);OH 6.6 内核自带的是官方参考板(toybrick)的说明书。两者一 diff,差异就出来了:

# 以太网部分的差异(节选)
<     phy-mode = "rgmii";                          # 官方参考板:RGMII
>     phy-mode = "rmii";                           # 这块板:RMII
<     snps,reset-gpio = <&gpio2 RK_PD3 ...>;      # 官方板:复位接 gpio2_D3
>     snps,reset-gpio = <&gpio0 RK_PD5 ...>;      # 这块板:复位接 gpio0_D5

差异就是"这块板与官方参考板不同的地方"——移植的本质就是把这些差异用新语法重新表达。

第 2 步:逐项翻译

我把差异归纳成一张对照表,然后逐项写进新说明书:

硬件官方参考板(6.6)CHESHIT10 这块板翻译动作
以太网gmac0/gmac1 双 RGMIIgmac0 单路 RMII(RTL8201F)覆盖 gmac0;gmac1 禁用
屏幕主屏接 DSI0主屏 7 寸接 DSI1关 DSI0 通路,开 DSI1+VP1
触摸i2c1 上有 gt1xi2c3 上 4 颗候选芯片删 gt1x,重写 i2c3
摄像头ov13855/gc8034 单通路GC2053+GC2093 双通路删旧传感器,写新通路
USB5V 接 gpio0_A65V 接 gpio2_D3,多一个 Hub 复位覆盖引脚
RTC 时钟官方板无HYM8563 挂 i2c1新增节点
WiFi 使能无使能引脚gpio2_D1 控制补属性

每项翻译后的真实代码长这样(节选):

/* 以太网:官方板 RGMII → 这块板 RMII */
&gmac0 {
    phy-mode = "rmii";
    clock_in_out = "output";
    snps,reset-gpio = <&gpio0 RK_PD5 GPIO_ACTIVE_LOW>;
    assigned-clock-parents = <&cru SCLK_GMAC0_RMII_SPEED>;
    pinctrl-0 = <&gmac0_miim &gmac0_tx_bus2 &gmac0_rx_bus2 &gmac0_clkinout>;
    phy-handle = <&rmii_phy0>;
    status = "okay";
};

第 3 步:dtc 快速验证

写一段就用 dtc 编译验证一段(方法见第 5 篇),30 秒出结果。别攒到最后让几小时的内核编译来告诉你语法错误。

三、翻译中的"雷区":版本方言差异

4.19 → 6.6,设备树的"方言"变了,踩了三个真实的雷:

雷 1:宏改名了

屏幕 flags 里,4.19 时代用 MIPI_DSI_MODE_EOT_PACKET(发送 EOT 包),6.6 的头文件里这个宏不存在了,改名成了 MIPI_DSI_MODE_NO_EOT_PACKET(语义反转:不带 NO_EOT 即默认发 EOT)。

/* 4.19 写法 */
dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
              MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
/* 6.6 等价写法(不带 NO_EOT 即默认发 EOT) */
dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
              MIPI_DSI_MODE_LPM)>;

雷 2:基座文件换了

4.19 时代板级说明书基于 rk3568-evb1-ddr4-v10.dtsi;6.6 内核里这个文件不存在了,官方参考板的基座是 rk3568-toybrick.dtsi + rk3568-toybrick-x0.dtsi。板级内容(电源/内存/存储的通用配置)要从新基座复用。

雷 3:删除节点前必须查引用

翻译时经常要"删掉官方板的设备、换成这块板的"。直接删会撞上"悬空引用":

ERROR (phandle_references): /rt5672-sound/dais/dai0:
Reference to non-existent node or label "rt5670"

官方板声卡节点引用了我要删的音频芯片。规则:被引用的节点用 status = "disabled" 禁用,不要 delete;只有无引用(或引用一并删除)的节点才用 delete。

/* 正确做法:禁用而非删除 */
&rt5670 { status = "disabled"; };

/* 无引用的才直接删 */
/delete-node/ &rgmii_phy0;

另外还有个纯语法坑:/delete-node/ 必须放顶层(不能写在 &overlay { } 块内),新版 dtc 会直接报语法错误。

四、最终产物:一份可复用的补丁结构

翻译完成的说明书,我打包成了标准的内核补丁结构:

kernel/linux/patches/linux-6.6/cheshit10_patch/
├── kernel.patch    # 板级补丁(构建时自动应用)
├── hdf.patch       # HDF 框架接线补丁
└── dts/            # 说明书源文件(维护用)
    ├── rk3568-cheshit10.dtsi               # 板级公共说明书
    ├── rk3568-cheshit10-7inch.dts          # 入口(总目录)
    ├── panel-cheshit10-7inch-jh071.dtsi    # 屏幕章节
    └── touch-cheshit10.dtsi                # 触摸章节

构建时,这个补丁会在瑞芯微官方补丁之后自动应用,顺序是:

干净内核源码 → 瑞芯微 BSP 补丁(55MB) → CHESHIT10 板级补丁 → 编译出 DTB