From f3087399f255c042a226607d1728f781b9edaf67 Mon Sep 17 00:00:00 2001 From: BFE Engineering Date: Mon, 24 Aug 2026 19:31:37 -0600 Subject: [PATCH] =?UTF-8?q?kernel:=20M2=20DONE=20=E2=80=94=20self-built=20?= =?UTF-8?q?6.18=20boots=20on=20real=20RV1106=20hardware=20(warden-c8a3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_017wB8KB3MMQztRDXCMCkPrf --- kernel/docs/m2-boot-on-c8a3.md | 91 +++++++++++++++++++ kernel/rv1106-enablement/PORT-STATUS.md | 36 ++++++-- .../dts/rv1106-warden-m2.dts | 17 +++- 3 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 kernel/docs/m2-boot-on-c8a3.md diff --git a/kernel/docs/m2-boot-on-c8a3.md b/kernel/docs/m2-boot-on-c8a3.md new file mode 100644 index 0000000..8db254f --- /dev/null +++ b/kernel/docs/m2-boot-on-c8a3.md @@ -0,0 +1,91 @@ +# 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: +1. Back up `boot_b` (`dd .../by-name/boot_b -> /userdata/boot_b.bak`). +2. Write the test `boot.img` to **boot_b only** — `_a` (the shipped WardenOS) is + untouched. +3. 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 to `misc` sector 4. U-Boot's SPL then + picks _b once, decrements tries→0, and boots it. +4. If the test kernel fails/hangs, U-Boot auto-reverts to `_a` (SPL: "slot boot + failed, resetting" → next boot `A/B-slot: _a, successful: 1`). A hung kernel + just needs a Zigbee power-cycle; `_a` boots 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 with `FIT: No fit blob` / `No FIT image`. +- **A `resource` (multi) sub-image is mandatory.** rockchip reads the DTB via the + `RESC:` path from a resource image containing `rk-kernel.dtb` (+ logos), built + with `resource_tool --pack`. Without it: `Failed to load DTB, ret=-19`. +- **Sysmem sentinel load addresses.** fdt `load=0xffffff00`, kernel + `load=entry=0xffffff01`; U-Boot's sysmem places them (it chose kernel@0x8000, + fdt@0xc00000). Real low addresses collided → "No fit blob". +- `CONFIG_FIT_SIGNATURE` is **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=0x08000000` in the + FIT `.its` (see `boot5.its`). The real fix is a lean defconfig; multi_v7 is bloat. +- **`grf_ctx` NULL deref in clk-rv1106.** `rockchip_clk_register_branches(grf_ctx,…)` + crashed because the minimal DT had no `rockchip,rv1106-grf-cru` node to set + `grf_ctx`. Fix: add the `grf-clock-controller` child to the grf syscon (now in + `dts/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. diff --git a/kernel/rv1106-enablement/PORT-STATUS.md b/kernel/rv1106-enablement/PORT-STATUS.md index 718ae1f..d9755d2 100644 --- a/kernel/rv1106-enablement/PORT-STATUS.md +++ b/kernel/rv1106-enablement/PORT-STATUS.md @@ -70,14 +70,36 @@ The first full kernel build with our SoC drivers, 2026-08-24: console baud (1.5M assumed). A wrong DDR/clock value silently hangs before or just after earlycon. -## M2 — boot: NEXT (on hardware) -Package `zImage` + `rv1106-warden-m2.dtb` into a boot image and load on a bench unit -(c8a3 / w7159, both with a proven recovery net), watching the debug UART — or the -coprocessor USB console (R5) — for the earlycon "it's alive". A hang is expected to be -one of the PORT-VERIFY values above; iterate with recovery ready. This is an attended -step (brick-adjacent), not an unattended one. +## M2 — boot: ✅ DONE — "it's alive" on warden-c8a3 (2026-08-24) +The self-built **Linux 6.18.46 boots on real RV1106 hardware**, through our ported +drivers, verified over the serial console. It reaches earlycon, the arch timer +(BogoMIPS calibrated), **our `clk-rv1106` CRU driver**, pinctrl, and the mainline +8250 bound to uart2 **clocked by our CRU** (`ttyS2 … 16550A`), then hands off to the +real console and mounts a rootfs. See `../docs/m2-boot-on-c8a3.md` for the method +(the A/B `_b`-slot safe-test framework worked first try) and the boot-image format +(external-data FIT + resource, `mkimage -E -p 0x800`). -Then M3: `dw_mmc` DT + rootfs on our Buildroot userspace. +Three bring-up bugs were found and fixed on hardware, all captured in the DT: +1. **boot.img format** — rockchip U-Boot needs the external-data FIT + a `resource` + (multi) sub-image with `rk-kernel.dtb`, else `No fit blob` / `Failed to load DTB`. +2. **DTB overrun** — the bloated multi_v7 zImage decompresses to ~20 MiB and overran + the DTB at 0xc00000, so the kernel got `r2=0` (`invalid dtb`). Fix: place the fdt + high (`load=0x08000000`). A lean RV1106 defconfig would also fix this and is the + right long-term move. +3. **grf-cru NULL deref** — `clk-rv1106` registers a second branch set against a GRF + clock-controller (`grf_ctx`), set only by a `rockchip,rv1106-grf-cru` node. The + minimal DT omitted it → `grf_ctx` NULL → panic in `rockchip_clk_register_branches`. + Fix: add the `grf-clock-controller` child to the grf syscon. + +**clk-rv1106 PORT-VERIFY (armclk mux, PLL rates) is now partially retired**: the CRU +comes up far enough to clock the UART and the arch timer on hardware. A wrong CPU +mux/PLL would show later (cpufreq / peripheral rates), still to be checked. + +## M3 — rootfs boot: NEXT +The M2 kernel mounts the 5.10 WardenOS rootfs_b but the userspace/module vermagic +mismatches (5.10 `.ko` won't load on 6.18). M3 = a lean RV1106 defconfig (drop +multi_v7), `dw_mmc`/`sdhci` DT wired to our CRU (eMMC already probes — `MMC0: HS200`), +and our Buildroot userspace rebuilt against 6.18. Then M4 display, M5 wifi, M6 rest. ## Upstream tracking (decision 2026-08-23) Base stays the vendor forward-port (applies to 6.18; we control it). The unmerged upstream diff --git a/kernel/rv1106-enablement/dts/rv1106-warden-m2.dts b/kernel/rv1106-enablement/dts/rv1106-warden-m2.dts index 91413f0..acc143e 100644 --- a/kernel/rv1106-enablement/dts/rv1106-warden-m2.dts +++ b/kernel/rv1106-enablement/dts/rv1106-warden-m2.dts @@ -36,13 +36,14 @@ }; chosen { - stdout-path = "serial2:1500000n8"; + stdout-path = "serial2:115200n8"; /* * earlycon with no baud = reuse the divisor the bootloader left in - * uart2, so the first prints work regardless of our clock tree. The - * ttyS console rate (1.5M) is PORT-VERIFY against the board. + * uart2, so the first prints work regardless of our clock tree. The ttyS console is + * pinned to 115200 to stay readable on the CP2102 bench adapter; + * production WardenOS uses 1.5M. */ - bootargs = "earlycon=uart8250,mmio32,0xff4c0000 console=ttyS2,1500000n8 earlyprintk rootwait"; + bootargs = "earlycon=uart8250,mmio32,0xff4c0000 console=ttyS2,115200n8 earlyprintk rootwait"; }; memory@0 { @@ -91,6 +92,14 @@ grf: syscon@ff000000 { compatible = "rockchip,rv1106-grf", "syscon", "simple-mfd"; reg = <0xff000000 0x68000>; + + /* The CRU's clk-rv1106 registers a second branch set against this + * GRF clock-controller (grf_ctx); without the node grf_ctx is NULL + * and of_clk_init NULL-derefs in rockchip_clk_register_branches. */ + grf_cru: grf-clock-controller { + compatible = "rockchip,rv1106-grf-cru"; + #clock-cells = <1>; + }; }; cru: clock-controller@ff3a0000 {