7.6 KiB
U-Boot on krane — final state and operating manual
Status as of 2026-08-30 (RESEARCH.md Rounds 1–36). Milestones reached: payload pipeline → framebuffer console → USB pogo keyboard at the prompt → landscape (rotated 270°) console, all verified on the device. The user owns the U-Boot config from here on.
Boot chain
BootROM → coreboot → TF-A BL31 → depthcharge (.12573.351.0)
→ krane-uboot-payload.bin @ 0x40000000 (mmcblk0p1, devkeys)
→ entry shim @ 0x40000040 → U-Boot _start @ 0x40001000
→ banner + vidconsole3 prompt on the panel + usbkbd input
The SPI firmware is never modified; only the kernel partition
mmcblk0p1 is reflashed.
Payload layout (LOAD-BEARING constants)
| offset | content |
|---|---|
| 0x0000 | 64-byte arm64 Image header (code0 = b +0x40, image_size, flags bit3, magic ARM\x64 at 0x38) |
| 0x0040 | uboot-wrapper.S entry shim (OVL_EN=1, OVL0_2L_EN=1, backlight GPIOs 43/176 on, b to U-Boot — imm26 patched at build time) |
| 0x1000 | u-boot.bin contiguous (no interior padding) |
CONFIG_TEXT_BASE=0x4C001000(8-aligned, so no linker fill skews_start); the file is placed so runtime_start = 0x40001000(4K-aligned — required by U-Boot's PIE fixup, checked by the build script viau-boot.sym:_start == __image_copy_start).- The shim cannot be removed: depthcharge jumps to payload+0x40, and U-Boot cannot execute there (PIE/alignment). The diagnostic magenta fill + blink train + 5 s hold were removed in Round 37; the shim now only revives the display and branches.
Build
U-Boot
cd /home/vhaudiquet/u-boot
export CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm
make mt8183_kukui_krane_defconfig # ONLY when changing the defconfig
make -j8
Warning: re-running the defconfig regenerates .config and wipes
any hand edits. If you tune .config directly (like the current
16×32 font setup), just run make -j8. After ANY defconfig edit +
re-run, verify the full load-bearing set in .config:
grep -E "CONFIG_USB=|DM_USB|XHCI|USB_KEYBOARD|USB_STORAGE|CMD_USB|USE_PREBOOT|PREBOOT=|PHY_MTK_TPHY|VIDEO_MT8183|CONSOLE_ROTATION|TEXT_BASE" .config
grep -E " _start$|__image_copy_start" u-boot.sym # both 0x4c001000
(Round 36 lesson: an elided-line edit dropped CONFIG_USB=y and USB
silently disappeared.)
Payload
cd /home/vhaudiquet/krane-fb-stub
./build-uboot-payload.sh
Assembles header + wrapper + u-boot.bin → krane-uboot-payload.bin,
packs with mkdepthcharge (devkeys, PYTHONPATH=/root/krane-fb-stub/src/depthcharge-tools),
asserts _start == 0x4C001000 from u-boot.sym, prints sha256.
Flash + verify (always all three)
SZ=$(stat -c%s krane-uboot-payload.bin)
dd if=krane-uboot-payload.bin of=/dev/mmcblk0p1 bs=4M conv=fsync
cmp -n $SZ krane-uboot-payload.bin /dev/mmcblk0p1 && echo CMP-OK
futility vbutil_kernel --verify /dev/mmcblk0p1 # "Body verification succeeded"
Then: reboot → depthcharge dev menu → "Internal storage".
Recovery
- Backup of the original kernel partition:
~/mmcblk0p1-pmos-backup.img(sha25620951a54…), also on the USB stick (sda3).ddit back tommcblk0p1to restore pmOS's FIT. - pmOS still boots from the USB stick (sda) via the depthcharge menu.
- pmOS chroot lives on
mmcblk0p3.
U-Boot tree state (branch krane-updates, on top of mainline 527115ef)
Kept features (upstreamable):
drivers/video/mt8183_scanout.c— UCLASS_VIDEO scanout driver on the upstreamovl0@14008000node: revives the depthcharge scanout (OVL_EN/OVL0_2L_EN + backlight GPIOs 43/176), parses the coreboot table LBIO at0xffed9000, falls back toOVL_L0_ADDR(0x14008f40), setsuc_priv->rot = 3(270° CW landscape console). The shared handoff code lives inmt8183_disp.c/mt8183_disp.h.drivers/video/mt8183_display.c— full cold bring-up driver (Kconfig choiceVIDEO_MT8183_DISPLAY, now the defconfig default;VIDEO_MT8183_SCANOUTkeeps the old behavior): MMSYS display gates, SMI LARB0, panel init viadrivers/video/mtk_dsi.c+drivers/phy/phy-mtk-mipi-tx.c+drivers/video/panel_boe_tv101wum.c, overlay scanout of a framebuffer at 0xFC000000 (FDT memreserve + LMB), backlight. Falls back to the handoff revival, logging the stage. Serial prints:[dsi] phase 0/9/F.drivers/gpio/mt8183_gpio.c— minimal MT8183 GPIO driver (dir/dout/ din; pinmux left to firmware) for the panel reset / supply-enable pads.drivers/clk/mediatek/clk-mt8183.c— now also models the MMSYS display gates (CLK_MM_*) as a clock provider onmmsys@14000000.board/mediatek/mt8183/mt8183.c—get_page_table_size()override (0x40000): the fb and coreboot-table dynamic mappings exhaust the default page-table budget (Round 31). Any new post-relocmmu_map_regionrelies on this headroom.arch/arm/dts/mt8183-kukui-krane-sku176-u-boot.dtsi— overlay (NOT a DT fork): addssimple-mfdto the mtu3 ssusb node (so DM scans its children and binds xhci — Round 34) andippcreg +physonusb@11200000(whatxhci-mtk.cexpects; upstream puts those on the parent for Linux's mtu3 driver).board/mediatek/mt8183/krane.env—stdin=serial,usbkbd,stdout=serial,vidconsole,stderr=serial,vidconsole.- defconfig: USB stack (
USB,DM_USB,USB_XHCI_HCD,USB_XHCI_MTK,USB_KEYBOARD,USB_STORAGE,CMD_USB),PHY_MTK_TPHY,USE_PREBOOT(preboot defaults tousb start),CONSOLE_ROTATION,ENV_IS_NOWHERE+ENV_SOURCE_FILE="krane".
Still WIP/temporary in the tree (revert before upstreaming; see
git log --oneline | grep -i wip):
- fb text logger + diag bands (
krane_fb_log/krane_diag_bandin mt8183_scanout.c, band calls in video-uclass.c/board_f.c/main.c/ mt8183.c), abort dump hook ininterrupts_64.c(do_syncdraws ESR/ELR/FAR on the panel), CONFIG_PANIC_HANG=y(freeze + dump on abort; production wants it off — otherwise panic silently resets),CONFIG_WATCHDOG_AUTOSTART=n(decide for production),CONFIG_BOARD_LATE_INIT=y(only used by a diag band).
Behavior notes
- Console: 16×32 font (user's
.config), white-on-black, rotated 270° CW ⇒ landscape 60×75 text grid. To change rotation:uc_priv->rotinmt8183_scanout_probe(0=portrait-native, 1/3=the two landscape orientations, 2=upside-down portrait). - Keyboard: pogo keyboard = USB HID behind the GL610 hub on
usb@11200000. Enumeration happens at preboot (usb start); the usb_kbd probe re-muxesstdinfrom the env. If keys die, first check.configstill has the full USB set (Round 36). - USB stick (sda) enumerates too (
USB_STORAGE) — distro_bootcmd is the next milestone. - MMIO 0x0–0x20000000 is pre-mapped device memory (armv8-mem-map.c);
only DRAM-above-0x40000000/
0xffed9000regions need dynamicmmu_map_region(done in the scanout driver).
The 2021-era display handoff (why the shim exists)
depthcharge (device-era, R93) display_cleanup() before the jump:
clear_screen(black), backlight GPIOs low, OVL_EN=0 (0x14008000+0xc),
OVL0_2L_EN=0 (+0x100c). OVL_L0_ADDR (+0xf40) still holds the menu
scanout address. Both the shim and the scanout driver undo this; the
panel/DSI link is never reinitialized.
Quick reference
# change rotation / code, then:
cd /home/vhaudiquet/u-boot && export CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm && make -j8
cd /home/vhaudiquet/krane-fb-stub && ./build-uboot-payload.sh
SZ=$(stat -c%s krane-uboot-payload.bin) && \
dd if=krane-uboot-payload.bin of=/dev/mmcblk0p1 bs=4M conv=fsync && \
cmp -n $SZ krane-uboot-payload.bin /dev/mmcblk0p1 && \
futility vbutil_kernel --verify /dev/mmcblk0p1