Files
krane-fb-stub/u-boot-krane-prompt.md
2026-09-01 18:42:25 +02:00

8.8 KiB
Raw Permalink Blame History

Task: bring up mainline U-Boot on the Lenovo IdeaPad Duet (google,krane sku176, MT8183)

You are taking over a bring-up that just passed its first milestone: a minimal bare-metal payload ("krane-fb-stub") boots via depthcharge and draws to the panel. Your job is to replace it with mainline U-Boot as the payload, with a working framebuffer console, in a form that is upstreamable to mainline U-Boot later.

Hard requirement: upstreamable work

All changes must be written so they can be sent to the U-Boot mailing list with minimal rework:

  • Follow U-Boot conventions: scripts/checkpatch.pl clean, Kconfig/Makefile style of neighbouring drivers, DM/uclass APIs (vidconsole, VIDEO, MMC, serial), proper bind()/probe() structure.
  • Board support as a proper target: board/mediatek/, configs/*_defconfig, MAINTAINERS entry, defconfig minimal and matching pumpkin's style.
  • Any DT additions must match the upstream Linux DTS files (the krane DTs are already synced from Linux into dts/upstream/src/arm64/mediatek/ — reuse them, do not fork them).
  • Keep board-specific workarounds in board code, never inside common drivers; document every magic register with its source (see the device facts below).
  • Small, reviewable, single-purpose commits.

Current state and where things live

  • U-Boot shallow clone: /home/vhaudiquet/u-boot (mainline main, ~2026-08). SoC support exists: arch/arm/mach-mediatek/mt8183/. Reference target: configs/mt8183_pumpkin_defconfig (CONFIG_POSITION_INDEPENDENT=y, MTK serial, mtk-sd MMC, WDT, USB). dts/upstream/src/arm64/mediatek/mt8183-kukui-krane-sku176.dts exists; there is NO krane/kukui defconfig or board dir yet — that is your starting point.
  • Validated stub project (read it first): /home/vhaudiquet/krane-fb-stub/ — contains main.c (the working payload: display revival + parse + fills), build.sh, build-payload.sh (packing via depthcharge-tools mkdepthcharge + vbutil devkeys), the stub's ARM64 Image-header wrapper stub.S, and RESEARCH.md — the full lab notebook of the display bring-up. READ RESEARCH.md before touching anything; it documents every [REVERSED] claim.
  • The stub's working payload is currently flashed to mmcblk0p1; keep it as the regression test. Its payload hash and the exact flash/verify procedure are in RESEARCH.md.

Environment

  • The target device is this machine. It boots postmarketOS from USB (sda); you work inside a chroot into the internal rootfs (/dev/mmcblk0p3 mounted at /). The boot firmware (coreboot + depthcharge) lives in SPI and is NEVER modified.
  • mmcblk0p1 (32 MiB, ChromeOS kernel partition) is the only thing you flash. Tools available: aarch64-linux-gnu-gcc, futility vbutil_kernel, depthcharge-tools (mkdepthcharge), dtc.
  • Flash procedure (same as the stub): dd if=payload of=/dev/mmcblk0p1 bs=4M conv=fsync, then cmp -n <size> against the payload, then futility vbutil_kernel --verify /dev/mmcblk0p1. After flashing, hand the device to the user to reboot into internal — the user reports what the screen shows. Never flash anything else. Recovery exists: USB boot
    • ~/mmcblk0p1-pmos-backup.img (see RESEARCH.md).
  • There is NO serial console. The framebuffer is the only output channel; the user photographs/describes the screen.

Boot contract (verified on device, RESEARCH.md Round 10)

depthcharge (R93-era, in SPI) boots the dev-signed FIT from mmcblk0p1, decompresses the kernel subimage to an arbitrary 2 MiB-aligned DRAM slot, checks the ARM64 Image header magic (0x644d5241), and jumps to the first byte with x0 = FDT pointer, x1-x3 = 0, MMU off. U-Boot's u-boot.bin has no Image header — wrap it: 64-byte header (branch past header, text_offset=0, image_size patched at 0x10 LE, flags bit 3, magic at 0x38) exactly like krane-fb-stub/stub.S, then pack with mkdepthcharge.

Device facts for the display (all verified — do not re-derive)

  • Panel: BOE TV101WUM_NL6, 1200×1920, 32bpp xRGB (r@16/8 g@8/8 b@0/8), 4-lane DSI, xres*bpl-style geometry comes from the coreboot LBIO record (1200×1920, bpl 4800, bpp 32).
  • coreboot initializes the panel and DSI before depthcharge; at payload handoff the display pipeline is live but STOPPED: depthcharge's display_cleanup() disabled the overlay engines and killed the backlight. The panel/DSI link stays up — no panel re-init is needed.
  • Revive = three MMIO/GPIO writes (offsets verified against device-era depthcharge sources; the two Round-1 misreads cost nine rounds — trust these):
    • OVL_EN = 1 at OVL0 base + 0x000C (OVL0 base 0x14008000)
    • OVL0_2L_EN = 1 at OVL0 base + 0x100C
    • backlight GPIOs high: GPIO controller 0x10005000, dout block at +0x100 (NOT 0x140), 16 B per 32-pin group, set@+4: pin 43 (DISP_PWM) → 0x10005114, pin 176 (EN_LCD_BL) → 0x10005154.
  • Scanout address: read OVL_L0_ADDR at OVL0 base + 0x0F40. The coreboot LBIO record (fixed address 0xffed9000, size 0x380, verified live via sysfs + /sys/firmware/fdt) may report physical_address = 0; upstream coreboot 4.14 kukui does that, and libpayload's cbgfx rejects pa=0. The live scanout on this unit was 0xFD536000 (top-of-DRAM reserved). Strategy: geometry from the LBIO record, address from the record if non-zero else from OVL_L0_ADDR (guard: >= 0x40000000).
  • The LBIO table parse reference implementation is krane-fb-stub/main.c (find_framebuffer); its layout comments are verified.
  • Panel geometry facts also matter for the console: portrait 1200 wide; pick a font/rotation accordingly.

Known trap (open bug — carry it, don't trip on it)

depthcharge hands off x0 = _fit_fdt_start = 0x5F800000 (its internal FDT buffer; the kernel reserves 5f800000-5f815fff for it), but at payload entry that buffer reads as ALL ZEROS. The kernel boot path works (the kernel sees a valid FDT there), the payload path does not — root cause open, leading suspicion cache-flush asymmetry between depthcharge's cached writes and our MMU-off reads (pmOS kernel ~30 MB vs 18 KB stub is the variable). Consequence: U-Boot MUST NOT depend on the handoff FDT. Use U-Boot's own embedded control DTB (CONFIG_DEFAULT_DEVICE_TREE with the krane dts), and get the coreboot table from the fixed 0xffed9000 when needed. Investigating/fixing the zeros (e.g., adding cache clean to the wrapper's handoff, or reading with cache disabled) is a stretch goal.

Milestones

  1. Buildable target: board/mediatek/ krane board + configs/mt8183_kukui_krane_defconfig forked from mt8183_pumpkin_defconfig; CONFIG_DEFAULT_DEVICE_TREE=mt8183-kukui-krane-sku176; keep CONFIG_POSITION_INDEPENDENT=y (depthcharge's slot is arbitrary), DEBUG_UART params (0x11002000 @ 26 MHz) as harmless default, drop pumpkin-specific bits (fastboot, TPHY, mtu3 gadget) for now. Deliverable: make mt8183_kukui_krane_defconfig && make -j with aarch64 toolchain produces u-boot.bin.
  2. Boot wrapper + flash: prepend the 64-byte ARM64 Image header (reuse/wrap krane-fb-stub/stub.S pattern; patch image_size = header + u-boot.bin size), pack with mkdepthcharge, flash, verify. User reboots. Expected: something — U-Boot's debug UART goes nowhere visible, so absence of colors is NOT failure. This milestone is only worth flashing together with 3, or with a crude framebuffer "hello" (write RGB stripes at the scanout address early in U-Boot, e.g. from board_early_init) as a life sign.
  3. Framebuffer console: minimal U-Boot video driver + vidconsole using the facts above (no full display init — reuse the live pipeline): revive writes, scanout discovery (LBIO @0xffed9000 / OVL_L0_ADDR), a simple 8x16 font vidconsole drawing into the framebuffer. Upstreamable shape: a drivers/video/ driver + Kconfig (e.g. VIDEO_MT8183_SCANOUT or a proper "coreboot framebuffer" video driver — check what exists in tree first and fit the uclass). Deliverable: U-Boot banner + prompt visible on the panel; user confirms.
  4. Then: eMMC via the krane DT (mtk-sd should work out of the box), bootflow/distro boot of the pmOS kernel from mmcblk0p3, USB keyboard (Duet keyboard is USB over the pogo connector) for a real shell.

Working rules

  • Update /home/vhaudiquet/krane-fb-stub/RESEARCH.md with one numbered round per experiment: observation, root cause, fix, verification. That notebook is the project's memory.
  • Commit every verified step (the stub repo history shows the expected style); U-Boot work happens in /home/vhaudiquet/u-boot on a branch (e.g. krane).
  • Verify before every reboot: build → wrap → mkdepthcharge → vbutil_kernel --verify → dd → cmp → on-device vbutil verify. Never yield an unverified flash claim.
  • The user performs reboots and reports the screen; frame your asks as one flash-reboot per experiment with the expected observation spelled out.