8.8 KiB
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.plclean, Kconfig/Makefile style of neighbouring drivers, DM/uclass APIs (vidconsole,VIDEO,MMC,serial), properbind()/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-sdMMC, WDT, USB).dts/upstream/src/arm64/mediatek/mt8183-kukui-krane-sku176.dtsexists; 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/— containsmain.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 wrapperstub.S, andRESEARCH.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/mmcblk0p3mounted 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, thencmp -n <size>against the payload, thenfutility 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 = 1at OVL0 base + 0x000C (OVL0 base 0x14008000)OVL0_2L_EN = 1at 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_ADDRat OVL0 base + 0x0F40. The coreboot LBIO record (fixed address 0xffed9000, size 0x380, verified live via sysfs + /sys/firmware/fdt) may reportphysical_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
- Buildable target:
board/mediatek/krane board +configs/mt8183_kukui_krane_defconfigforked from mt8183_pumpkin_defconfig;CONFIG_DEFAULT_DEVICE_TREE=mt8183-kukui-krane-sku176; keepCONFIG_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 -jwith aarch64 toolchain producesu-boot.bin. - Boot wrapper + flash: prepend the 64-byte ARM64 Image header
(reuse/wrap
krane-fb-stub/stub.Spattern; 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. - 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
vidconsoledrawing into the framebuffer. Upstreamable shape: adrivers/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. - 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.mdwith 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-booton 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.