# 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 ` 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.