
rk-forge 已经开源带你从零把一颗几乎没人理的 RK3506用主线 Linux7.1 主线 U-Boot 一路跑到rk3506 login:——可按序打上去的补丁库、诚实的差距报告、完整 bringup 教程都在这。欢迎观摩喜欢点个⭐仓库地址https://github.com/Awesome-Embedded-Learning-Studio/rk-forge静态网页https://awesome-embedded-learning-studio.github.io/rk-forge/有朋友反馈说希望有PDF渲染的版本您可以戳戳https://github.com/Awesome-Embedded-Learning-Studio/rk-forge/releases/tag/pdf%2F2026-06-23-1120或者有其他更新的版本。因为我怕放百度网盘会被发文平台一脚踹飞所以如果不方便上Github的朋友可以私信我要一下百度网盘链接Ch1 把工具链钉死了这一章我们往地基上放第一块砖主线 U-Boot。但 RK3506 的 U-Boot 不是编出来就能跑那么简单——它前面卡着一颗闭源的 rkbin方案 A 自己写 SPL 又崩在乱码里Ch0 讲过。所以这章其实是笔者和那颗闭源 blob 在板子的咽喉上拔河的全过程三个它单方面定的隐性契约加上 bringup 路上四个把我们按在地上摩擦的坑。挺过去你才能在串口里看到主线 U-Boot 的 banner。前言第一块砖就撞上闭源咽喉工具链既然稳了按计划下一步就是编 U-Boot。主线 U-Boot 对 RK3506 这颗 SoC 是有驱动的——pinctrl、clock、甚至 sdram 初始化的框架都在——但它没有板级没有这块具体板子的 defconfig没有设备树。这恰恰是 rk-forge 要补的patches/uboot/0001那个补丁干的就是这件事。编出来是一回事跑起来是另一回事。RK3506 的启动链U-Boot proper 是被 SPL 请出来的而 SPL 这一环目前我们自己的写不出来方案 A 崩了。所以现阶段走的是方案 B借 vendor 的 DDR/SPL/OP-TEE blob 把链的前半段跑通再把主线 U-Boot proper 装进 vendor 能认的 FIT 里。诚实地讲这不是纯主线 boot——前半段还在借厂商 blob。但它能让主线 U-Boot 在真板上真正跑起来这是整条链的第一座里程碑也是后面塞内核的前提。这条链前段长什么样rkbin 内部要和 rkbin 拔河得先看清它的招式。RK3506 从上电到 U-Boot 出 banner前半段是这样跑的ROM → idblock(DDR blob usbplug SPL) → SPL → FIT(optee0x1000 uboot0x200000 fdt) → OP-TEE → 降回 NS 世界 → U-Boot properBootROM 先从存储的扇区0x40把 idblock 读进来。idblock 里塞着三段DDR blob把 DRAM 点亮、usbplug下载模式用的、还有 SPL。SPL 起来之后去扇区0x2000找 uboot 的 FIT 镜像按 FIT 里的conf把 optee 装到0x1000、uboot 装到0x200000、fdt 装好然后先跳进 OP-TEE 把安全世界搭起来再降回非安全世界把控制权交给 U-Boot proper。这里有一堆 RK bootrom 和 SPL 单方面定死、我们只能对齐的契约idblock 在0x40、uboot FIT 在0x2000、optee 装在0x1000、uboot 装在0x200000。vendor 那套打包层——make.sh、boot_merger、一堆.ini、make_fit_optee.sh——在主线其实能塌缩成一次 binman 调用详见notes/01的对照表。但方案 B 阶段我们还混着用既然借了 vendor 的 SPL就得喂它认的格式。接下来的坑大多就出在主线格式和vendor 格式的接缝上。坑之一vendor SPL 读不懂主线 FIT第一斧就劈在 FIT 上。我们把主线 U-Boot 装进一个 FIT指望 vendor SPL 来加载——结果 SPL 甩一句Unsupported hash algorithm死活不认。这报错极具误导性笔者一开始真以为是 hash 算法的事。直到老老实实拿dumpimage把 vendor 那个已知能跑的uboot.img解开看结构optee 是Firmware装在0x1000、uboot 是Standalone装在0x200000、fdt 是 Flat DTconf里firmwareoptee, loadablesuboot, fdtfdt。再去翻 vendor 的fit_nodes.sh人家自己生成的节点里写的也是hash { algo sha256; }——vendor 自己就用 sha256。所以根本不是算法问题是 vendor fork 的 FIT 节点结构、命名、conf 定义和主线 binman 生成的那套对不上。正解不是换算法而是结构复刻手写一个rk3506-mainline.its100% 照搬 vendor 已经跑通的 FIT 结构只把 uboot 节点里那块二进制换成主线编出来的u-boot-nodtb.bin。这一步是整个方案 B 最有价值的发现——把一个模糊的hash 问题收敛成了可操作的照着抄结构。坑之二TEXT_BASE 差了 6MB还有 OP-TEE 到底跳哪里结构照抄但有一处不能照抄一照抄就崩。主线u-boot-nodtb.bin是按CONFIG_TEXT_BASE0x00800000链接的而 vendor FIT 里 uboot 的 load 写的是0x00200000——差了整整 6MB。代码按0x800000链接你却把它装到0x200000所有绝对寻址全错必崩。所以 ITS 里 uboot 的load得改成主线的0x800000不能盲抄 vendor 的0x200000。但这又引出一个让人睡不着觉的悬念。vendor 的链是SPL → optee(0x1000) → 降 NS → 跳 uboot那 OP-TEE 跑完到底跳去哪个地址如果它从 SPL 传进来的 loadable 信息里取地址这是标准做法那 SPL 把我们的 uboot 装到0x800000OP-TEE 就跳0x800000自洽可如果 OP-TEE 把跳转地址硬编码成 vendor 原来的0x200000那我们0x800000的代码就跳空了崩。问题是——tee.bin是 rkbin 预编译的 blob源码根本不在我们手里这个跳转地址事先没法确定只能上板试。实测的结果让人松了口气串口里清清楚楚打着I/TC: Next entry point address: 0x00800000——OP-TEE 走的是标准做法从 loadable 取地址不是硬编码。这个悬在头上好几天的最大风险被一行 log 打消了。坑之三banner 出来了却 hang 在 misc_init_r照上面改完上板——U-Boot 2026.07-rc4的 banner 终于蹦出来了。笔者刚要庆祝紧接着就是一盆冷水initcall misc_init_r() failed然后### ERROR ### Please RESET the board ###死在那里进不了提示符。banner 都出来了还崩这种最磨人。顺着misc_init_r往里挖根因链是这样misc_init_r要调rockchip_cpuid_from_efuse读 SoC ID它内部uclass_get_device_by_driver去找 OTP 设备可我们那份最小 dtsi根本没给 OTP 节点于是找不到设备、返回-ENODEV一路链式失败而 U-Boot 的 initcall 机制对返回非 0 的回调默认是 hang——直接卡死。有意思的是主线那个 OTP 驱动其实已经认得rockchip,rk3506-otp它共用 rk3568 的读法缺的只是 DT 里那个节点和它的物理地址。rk3506 的 OTP 基地址不在主线 dtsi 里最后是从 vendor dtb 的预处理产物里抠出来的0xff4f0000。于是给 dtsi 补上otpff4f0000照主线 rk3528 的最小写法不带 clocks实测也不需要重编上板——这次SoC: RK3506B顺顺当当打印出来意味着 OTP 读到了、misc_init_r过了板子稳稳停在提示符。主线 U-Boot从上电一路跑到了交互 shell。rkbin 的三个隐性契约入门税把上面这些加上打包烧录时踩的归拢一下其实就是闭源 rkbin SPL 给我们立的三个规矩——详见pitfalls/01这里浓缩讲。第一个规矩是 chip tag。打包出来的update.img头里有一个 chip tag烧录前工具会拿它跟 loader 里写死的CHIP_NAME比对对不上当场拒烧。坑在于RK3506B 这颗 loader 的真实名字其实是RK350F对不是 RK3506——你要是手滑硬编一个-RK3506tag 就对不上工具翻脸不认人RKBOOT-RK3506B-aes.ini第 13 行NAMERK350F就是铁证。正解是永远从 loader 动态读这个 tagRK$(dd ifloader bs1 count4 skip21 | rev)别图省事硬编。第二个规矩是 OP-TEE 的 hash。整条 FIT 里uboot 是 loadable、不被校验fdt 也不被锁唯一被 SPL verified-boot 拿 sha256 锁死的就是 optee 节点那颗 tee.bin。方案 B 阶段我们借的是 vendor SPL它锁的 hash 对应 tee v2.1093603ca22c...。你要是把 tee 换成公开仓里的 v2.40hash 算出来变成616f8152...SPL 当场报optee Bad hash——boot-sdl-202606152121里这个过程记得一清二楚。所以当时 tee 必须钉死 v2.10。这里笔者得诚实交代一句后续后来我们把整条 loader 都换成公开 rkbinSPL v1.12 tee v2.40那条全公开的链自洽、板上能跑——所以必须 v2.10是方案 B 那条借 vendor SPL 的链的规矩不是普适真理。但那是打包纯化阶段的事了方案 B 当时锁的就是 v2.10。第三个规矩是 FIT 的字节布局。就算你 tee 用对了 v2.10只要这个 FIT 是用主线mkimage -E打的optee 照样 Bad hash——只不过这次 hash 变成7b78fe4e...boot-sdl-202606152144。原因很阴主线 mkimage 和 vendor mkimage 都叫-Eexternal data但两者的外部数据字节布局不一样vendor SPL 按它自己那套布局硬读 optee 节点读错位了sha256 算的是错位的字节当然不等于期望值。所以 uboot FIT 必须用 vendor 那颗 2017.09 的 mkimage 打。这是 rkbin SPL 收的一笔隐性税。同样诚实一句后来我们用纯 Python 写了fit-pack.py把 vendor mkimage 那套 SPL 兼容布局字节级复刻了出来才算彻底摆脱了 vendor mkimage。但方案 B 那会儿老老实实用 vendor mkimage 是最快的路。三条规矩看下来本质是同一件事rkbin SPL 闭源它的 chip tag 表、verified boot 锁的 hash、读 FIT 的字节布局全是它单方面定的契约我们只能对齐、改不动。主线侧真正自由的只有 kernel FIT那是主线 U-Boot 加载的根本不经 SPL verified boot。要干净掉这三条唯一的办法是换掉 rkbin SPL——那是远期的事这章我们先交了入门税。把镜像凑出来烧到板上讲完规矩说说怎么把东西真的弄进板子。forge 现在的打包分几步pack-loader.sh用 Rockchip 的boot_merger从公开 rkbin 把 loader/idblock 打出来DDR usbplug SPLpack-fit.sh打 uboot 的 FIT最后 assemble 成一个完整的update.img。诚实地讲方案 B 那会儿是 vendor mkimage boot_merger 手写 ITS 混着上的后来才一点点纯化成 fit-pack.py 全公开 rkbin——纯化是另一条弧线这章讲的是 bringup 过程混着用没毛病。烧录有两条路走哪条取决于板子从哪儿启动。这块 RK3506B 实测是SPI-NAND 优先启动的notes/01Stage 3 验证过——SD 卡你裸写一个镜像进去bootrom 根本不选转头就去起 NAND 里的出厂 vendor。所以主线落地走的是 NAND用 RKDevTool 把update.img烧进板载 SPI-NANDchip tag 对了才烧得下去这就是上面第一个规矩。SD 卡这条呢是作为开发和恢复用的第二媒体flash-sd.sh用dd把 sd.img 写进卡——这脚本是一堆安全检查裹出来的拒绝写挂载着的设备、拒绝写系统盘、拒绝分区节点、写之前还非要你手敲一遍设备名确认生怕你把宿主盘抹了。WSL2 用户记得 SD 卡得先走usbipd-win透传进来。成功长这样交完三笔入门税、爬完四个坑板子上终于跑出了我们想要的那行。下面这段是从方案 B 的里程碑 logboot-sdl-202606142052里截的一个字没合成U-Boot 2026.07-rc4-g5ca1a73c7d30 (Jun 14 2026 - 20:47:09 0800) Model: Rockchip RK3506 Evaluation Board (ATK RK3506B) SoC: RK3506B DRAM: 512 MiB Core: 33 devices, 15 uclasses, devicetree: separate ... Hit any key to stop autoboot: 0 每一行都值回票价U-Boot 2026.07-rc4是主线版本不是 vendor 的 2017SoC: RK3506B打印出来说明 OTP 读到了、misc_init_r那个坑已经填平DRAM: 512 MiB是借来的 vendor DDR blob 点亮的内存最后停在意味着主线 U-Boot 从上电一路跑到了交互 shell。方案 B 的里程碑到此达成。主线 U-Boot 在 RK3506B 真板上活了。诚实的边界还是要再强调一遍它赖以运行的 DDR/SPL/OP-TEE 还是借的 vendor blob这不是纯主线 boot。但有了这块能跑的 U-Boot 当底座下一章我们就能往上面塞内核——看主线 Linux 认不认我们亲手写的那块板级设备树能不能一路跑到Starting kernel。我们 Ch3 见。