Round 11: mainline U-Boot as payload — target, scanout driver, first flash

Board/defconfig branch built (OF_UPSTREAM bindings-shadowing trap
documented), mt8183_scanout video driver porting the validated revival/
LBIO logic, 64-byte Image-header wrapper script. Payload 1fc74a0a…
flashed and verified on-device. Reboot result pending.
This commit is contained in:
vhaudiquet
2026-08-30 01:28:19 +02:00
parent 99c5c9c9ce
commit 2e3e33df61
2 changed files with 136 additions and 0 deletions
+81
View File
@@ -466,3 +466,84 @@ of=/dev/mmcblk0p1 bs=4M conv=fsync`.
"Bad address", not EPERM as first assumed).
- qemu test updated to the same expectation (colors + held blue); it
exercises parser + fill logic, not the MMIO revival writes.
## Round 11 — U-Boot as payload: target, driver, first flash (result pending)
First mainline-U-Boot flash after the Round-10 pipeline validation.
### Build (milestone 1)
- Branch `krane` in `/home/vhaudiquet/u-boot` (mainline main @
`527115ef`); commits `29aec558` (board/defconfig/MAINTAINERS),
`923cc754` (dtc include order), `f0470c9b` (video driver).
- `configs/mt8183_kukui_krane_defconfig` forked from pumpkin: keeps
`CONFIG_POSITION_INDEPENDENT=y`, DEBUG_UART (0x11002000 @ 26 MHz,
goes nowhere — absence of colors is not failure), MTK serial/MMC/WDT;
drops fastboot/TPHY/mtu3/USB. `CONFIG_BOOTDELAY=-1` so the first boot
stops at the prompt instead of autobooting pmOS from p3.
- DT: `CONFIG_OF_UPSTREAM=y`, `CONFIG_DEFAULT_DEVICE_TREE="mediatek/
mt8183-kukui-krane-sku176"` — **with OF_UPSTREAM the name must include
the vendor dir**; no arch/arm/dts registration needed.
- **New trap found while building**: U-Boot's legacy
`include/dt-bindings/clock/mt8183-clk.h` (BSP numbering,
`CLK_TOP_CLK26M=0`) shadows the upstream
`dts/upstream/include/dt-bindings/clock/mt8183-clk.h`
(`CLK_TOP_CLK26M=112`) for OF_UPSTREAM builds — the krane tree failed
with undefined `CLK_CAM_LARB6`, and even fixing those macros would
have silently produced wrong clock numbers everywhere. Fix:
`scripts/Makefile.lib` prefers `dts/upstream/include` when
`CONFIG_OF_UPSTREAM=y`. Pumpkin's in-tree dts (different binding
generation) keeps working because its config does not set OF_UPSTREAM.
### Video driver (milestone 3, flashed before first reboot)
`drivers/video/mt8183_scanout.c` (`CONFIG_VIDEO_MT8183_SCANOUT`,
checkpatch-clean), binds the upstream `ovl0@14008000` node
(`mediatek,mt8183-disp-ovl`; the two 2L overlays match a different
compatible, so exactly one probe). probe():
1. revival identical to the stub's stage0: `OVL_EN=1` (+0x000C),
`OVL0_2L_EN=1` (+0x100C), GPIO dout set for pins 43/176;
2. LBIO parse at the fixed 0xffed9000 (ported from the stub's
Round-10-validated `find_framebuffer`; host regression test
compiled the function standalone against `lbio.bin`: record parsed,
bad signature rejected);
3. scanout = LBIO pa if >= 0x40000000, else `OVL_L0_ADDR` (+0x0F40)
(Round-9 ground truth: 0xFD536000); else probe fails gracefully;
4. geometry from the record (xRGB 32bpp required; U-Boot's BPP32
console default composes pixels exactly as r<<16|g<<8|b — checked in
video-uclass `video_index_to_colour`);
5. both the coreboot table and the fb sit above the DTB's 2 GiB DRAM
window (memory@40000000 is 0x80000000 long), so both regions are
identity-mapped with `mmu_map_region()` first (MMIO < 0x20000000 is
already mapped Device by `arch/arm/mach-mediatek/armv8-mem-map.c`);
`video_set_flush_dcache(true)` for the console writes.
Revival happens BEFORE parsing, so "backlit black" = ran but parse/
probe failed, "dark" = never reached the driver — same decision tree
as the stub. No autoboot: U-Boot banner + prompt should stay on panel.
### Wrap + flash (milestone 2)
`krane-fb-stub/build-uboot-payload.sh`: 64-byte arm64 Image header
(code0 `b +0x40` = 0x14000010, image_size = 64 + len(u-boot.bin),
flags bit3, magic at 0x38) prepended to `u-boot.bin`, mkdepthcharge
with the krane DTB, `vbutil_kernel --verify`. (Header-bytes were
checked with `od` after an edit mishap dropped the flags word — always
re-verify the raw header bytes.) depthcharge decompresses the FIT and
jumps to the first byte — U-Boot's `_start` lands at +0x40, PC-relative
(PIC) so the arbitrary 2 MiB slot is fine.
- Payload `krane-uboot-payload.bin` sha256 `1fc74a0a…`, flashed to
`mmcblk0p1` (dd 4M conv=fsync), `cmp` OK (589824 bytes), on-device
`vbutil_kernel --verify` → body verification succeeded.
- Backup `mmcblk0p1-pmos-backup.img` (sha256 `20951a54…`) copied onto
the USB stick (sda3) — recovery no longer depends on eMMC.
### Expected observation
Panel shows the U-Boot banner (white/light-gray text on black, portrait
1200×1920) and the prompt, frozen (BOOTDELAY=-1). Nothing on panel = boot
path or early crash; backlit black = reached handoff but driver probe
failed. The x0-FDT-zeros trap is bypassed: U-Boot uses its embedded DTB
and never reads the handoff FDT.
+55
View File
@@ -0,0 +1,55 @@
#!/bin/sh
# build-uboot-payload.sh — wrap /home/vhaudiquet/u-boot/u-boot.bin with the
# 64-byte arm64 Image header (same contract as stub.S: depthcharge jumps to
# the first byte of the image, so code0 must branch past the header) and
# pack it into a dev-signed depthcharge FIT for mmcblk0p1.
#
# Image header layout (linux/Documentation/arch/arm64/booting.rst, verified
# against depthcharge src/arch/arm/boot64.c):
# 0x00 code0 b +0x40 (branch past header; entry point)
# 0x04 code1 0
# 0x08 text_offset 0 (image sits AT the 2 MiB-aligned base)
# 0x10 image_size header + u-boot.bin size (LE, patched below)
# 0x18 flags bit3 = place anywhere (KASLR slot math)
# 0x20..0x37 reserved 0
# 0x38 magic 0x644d5241 "ARM\x64"
# 0x3c res5 0
set -e
cd "$(dirname "$0")"
UBOOT_BIN="${UBOOT_BIN:-/home/vhaudiquet/u-boot/u-boot.bin}"
DTB="${DTB:-krane-sku176.dtb}"
OUT_IMG=krane-uboot.bin
OUT_PAYLOAD=krane-uboot-payload.bin
python3 - "$UBOOT_BIN" "$OUT_IMG" <<'EOF'
import struct, sys
src, out = sys.argv[1], sys.argv[2]
uboot = open(src, 'rb').read()
hdr = bytearray(64)
# code0: b .+0x40 => 0x14000000 | (0x40 >> 2)
hdr[0:4] = struct.pack('<I', 0x14000010)
# text_offset = 0 (left as zero)
struct.pack_into('<Q', hdr, 0x10, 64 + len(uboot)) # image_size
struct.pack_into('<Q', hdr, 0x18, 1 << 3) # flags: bit3
hdr[0x38:0x3c] = b'ARM\x64' # magic
with open(out, 'wb') as f:
f.write(hdr)
f.write(uboot)
print("wrapped: %d = 64 + %d bytes" % (64 + len(uboot), len(uboot)))
EOF
PYTHONPATH=/root/krane-fb-stub/src/depthcharge-tools python3 -m depthcharge_tools.mkdepthcharge \
-A arm64 \
-o "$OUT_PAYLOAD" \
-n "krane u-boot framebuffer console" \
-d "$OUT_IMG" \
-b "$DTB"
echo "---- verify ----"
futility vbutil_kernel --verify "$OUT_PAYLOAD"
sha256sum "$OUT_PAYLOAD"