The Linux 6.18.46 forward-port boots on the panel through our ported drivers, verified on the serial console: earlycon, arch timer (BogoMIPS calibrated), our clk-rv1106 CRU, pinctrl, and the mainline 8250 bound to uart2 clocked by our CRU (ttyS2 16550A), then rootfs mount. Two DT fixes got it past "Starting kernel": - fdt placed high (load=0x08000000) so the bloated multi_v7 zImage (~20 MiB decompressed) stops overrunning the DTB at 0xc00000 (was: r2=0, "invalid dtb"). - added the rockchip,rv1106-grf-cru node (grf-clock-controller child of grf) so clk-rv1106's grf_ctx isn't NULL (was: panic in rockchip_clk_register_branches). Console pinned to 115200 (readable on the CP2102 bench adapter; prod uses 1.5M). The boot-image format and the A/B _b-slot safe-test method (which auto-reverted to _a on every failed attempt) are in docs/m2-boot-on-c8a3.md. M3 next: lean defconfig + dw_mmc DT + our Buildroot userspace rebuilt on 6.18. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017wB8KB3MMQztRDXCMCkPrf
4.8 KiB
M2 boot bring-up on warden-c8a3 (live notes)
Booting the self-built 6.18 kernel on real hardware (warden-c8a3), 2026-08-24.
The build side (zImage + dtb) is in ../rv1106-enablement/; this is the on-target
half. The safe-test framework and the boot-image format below are the reusable
findings — they worked on the first hardware try.
The safe test path (A/B slot _b, never touch _a)
c8a3 is the XPS-connected Warden: eth0 [bench-ip] over USB-gadget ([bench-creds],
dropbear — use scp -O, no sftp-server), plus the serial console on xps
/dev/ttyUSB2 @115200 and Zigbee power (plug_cmd.py cycle). It runs an A/B
firmware (boot_a=mmcblk0p5 / boot_b=mmcblk0p6, 32 MiB each; rootfs_a/_b; AvbABData
in misc sector 4 / byte 2048).
The test never risks the working system:
- Back up
boot_b(dd .../by-name/boot_b -> /userdata/boot_b.bak). - Write the test
boot.imgto boot_b only —_a(the shipped WardenOS) is untouched. - Flip AvbABData to a one-shot _b:
craft_ab.py 14 0 1 15 1 0 1→ A(prio14, tries0,ok1) B(prio15,tries1,ok0); write tomiscsector 4. U-Boot's SPL then picks _b once, decrements tries→0, and boots it. - If the test kernel fails/hangs, U-Boot auto-reverts to
_a(SPL: "slot boot failed, resetting" → next bootA/B-slot: _a, successful: 1). A hung kernel just needs a Zigbee power-cycle;_aboots WardenOS back. Zero manual recovery needed — verified across three failed attempts.
earlycon=uart8250,mmio32,0xff4c0000 is confirmed correct: it is in the live
5.10 cmdline, and U-Boot's own DDR probe reports Adding bank: 0x0 - 0x10000000
(256 MiB) — so the M2 DT's memory node and earlycon are right.
The boot-image format (this was the whole fight)
rockchip U-Boot (this build) needs a very specific boot.img, NOT a plain FIT:
- External-data FIT.
mkimage -f its -E -p 0x800. The FDT metadata stays tiny (totalsize ≈ 1536 B, matching boot_a); the kernel/fdt/resource data is appended after it. A normal embedded-data FIT (totalsize = whole image) is rejected withFIT: No fit blob/No FIT image. - A
resource(multi) sub-image is mandatory. rockchip reads the DTB via theRESC:path from a resource image containingrk-kernel.dtb(+ logos), built withresource_tool --pack. Without it:Failed to load DTB, ret=-19. - Sysmem sentinel load addresses. fdt
load=0xffffff00, kernelload=entry=0xffffff01; U-Boot's sysmem places them (it chose kernel@0x8000, fdt@0xc00000). Real low addresses collided → "No fit blob". CONFIG_FIT_SIGNATUREis off in this U-Boot, so the image need not be signed. Template:sdk/sysdrv/source/kernel/boot.its; builder recipe:sdk/project/scripts/mk-fitimage.sh(mkimage -E -p 0x800).
With the correct format, U-Boot loaded my kernel + my DTB and printed my DT model
string (Model: WardenOS 86-Panel (RV1106) — M2 earlycon bring-up), then
Starting kernel ....
Result: ✅ M2 achieved — the 6.18 kernel boots on hardware
Six attempts, each auto-recovering to _a, then a clean boot:
[0.000000] Linux version 6.18.46 … #2 SMP
[0.000000] CPU: ARMv7 Processor [410fc075]
[0.000000] OF: fdt: Machine model: WardenOS 86-Panel (RV1106) — M2 earlycon bring-up
[0.000000] earlycon: uart8250 at MMIO32 0xff4c0000
[0.000000] cma: Reserved 64 MiB at 0x0c000000
[0.040693] Calibrating delay loop … 48.00 BogoMIPS ← arch timer up
[0.343810] pinctrl core: initialized pinctrl subsystem
[1.968703] ff4c0000.serial: ttyS2 … is a 16550A ← 8250 on our CRU clock
Two more bugs, found via the DEBUG_LL rebuild (DEBUG_LL_UART_8250, PHYS
0xff4c0000, shift 2, 32-bit word + earlyprintk — the decompressor prints
pre-MMU), then fixed:
- DTB overrun →
r2=0/invalid dtb. The multi_v7 zImage decompresses to ~20 MiB from 0x8000, overrunning the DTB at 0xc00000, so the decompressor handed the kernel a null DTB pointer. Fix: place the fdt high —load=0x08000000in the FIT.its(seeboot5.its). The real fix is a lean defconfig; multi_v7 is bloat. grf_ctxNULL deref in clk-rv1106.rockchip_clk_register_branches(grf_ctx,…)crashed because the minimal DT had norockchip,rv1106-grf-crunode to setgrf_ctx. Fix: add thegrf-clock-controllerchild to the grf syscon (now indts/rv1106-warden-m2.dts).
Console baud gotcha: console=ttyS2,115200. earlycon is readable at 115200
(U-Boot leaves uart2 there), but the vendor's 1.5M console rate is garbage on the
CP2102 bench adapter — so the M2 DT pins 115200 for readable bring-up; production
overrides to 1.5M.
Next (M3)
The kernel mounts the 5.10 rootfs_b but the userspace/modules are 5.10 (vermagic
mismatch). M3: lean RV1106 defconfig, dw_mmc/sdhci DT (eMMC already probes —
MMC0: HS200), and our Buildroot userspace rebuilt on 6.18.