diff --git a/u-boot-krane-panel-prompt.md b/u-boot-krane-panel-prompt.md new file mode 100644 index 0000000..e77662b --- /dev/null +++ b/u-boot-krane-panel-prompt.md @@ -0,0 +1,148 @@ +# Task: proper MT8183 display pipeline bring-up (MIPI DSI host + PHY + BOE TV101WUM-NL6 panel driver) for U-Boot on the Lenovo IdeaPad Duet (google,krane sku176) + +You are taking over an in-progress U-Boot port on this machine. U-Boot already +boots on the device with a working rotated vidconsole. Today's display path is +a "scanout" driver that *revives* the display pipeline left running by the boot +firmware (coreboot + depthcharge) instead of bringing it up itself. Your job is +to add a real display pipeline: a MediaTek MT8183 MIPI DSI host driver, the +MIPI TX PHY, and a proper driver for the panel (BOE TV101WUM-NL6), so U-Boot +brings the panel up from scratch and no longer depends on firmware handoff. + +## Hard requirement: upstreamable work + +Everything must be written to be sent to the U-Boot mailing list with minimal +rework: + +- `scripts/checkpatch.pl` clean; Kconfig/Makefile style matching neighbouring + drivers; DM/uclass APIs (`UCLASS_DSI_HOST`, `UCLASS_PANEL`, `VIDEO`, + `vidconsole`). +- Commit history: small, single-purpose, upstream-ready commits. Commit as you + go; never leave the tree with a broken build. +- Document every magic register with its source (Linux driver file or + coreboot file you ported it from), in the style of the existing + `drivers/video/mt8183_scanout.c`. +- Board-specific glue stays in board code; common drivers stay generic. + +## Where things are + +- U-Boot tree: `/home/vhaudiquet/u-boot` (mainline ~2026-08 + local + `krane-updates` branch commits; HEAD has everything working — do not rebase + or rewrite existing commits, add on top). +- Previous bring-up research (read first — it contains device facts confirmed + on the real hardware): `/home/vhaudiquet/krane-fb-stub/RESEARCH.md` and + `/home/vhaudiquet/krane-fb-stub/U-BOOT.md`. +- The current fallback display driver: `drivers/video/mt8183_scanout.c` — its + header comment documents the platform handoff model and the OVL register + facts. +- Board files: `board/mediatek/mt8183/`, `configs/mt8183_kukui_krane_defconfig`. +- Control DTB: OF_UPSTREAM, krane DTs at + `dts/upstream/src/arm64/mediatek/mt8183-kukui*.dtsi` — the DSI host node and + the panel child node (compatible `"boe,tv101wum-nl6"`) already exist there. + Do not fork the DT; bind from it. +- Toolchain: `aarch64-linux-gnu-gcc`. Build: + `make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)`. +- Network access works: fetch reference sources (see below) with curl from + raw.kernel.org / github raw, e.g. + `https://raw.githubusercontent.com/torvalds/linux/master/drivers/gpu/drm/panel/panel-boe-tv101wum.c`. +- **The user flashes and tests on the real device.** You cannot test display + output yourself. Build the payload, prepare exact flashing instructions + (depthcharge-tools `mkdepthcharge` + `futility vbutil_kernel` + dd to + `/dev/mmcblk0p1`, as used in this project), and instrument your code with + clearly-prefixed serial prints (e.g. `[dsi] phase N`) so the user can report + where bring-up stalls. + +## Reference implementations to port from + +Fetch these (do not invent register values): + +1. Linux panel driver (authoritative init sequence + timings for this panel): + `drivers/gpu/drm/panel/panel-boe-tv101wum.c` — the `"boe,tv101wum-nl6"` + entry: 1200x1920 @ 60Hz, 4 data lanes, DSC-less, init sequence of DSI + commands, AVDD/AVEE supplies + reset GPIO handling. +2. Linux MIPI TX PHY (MT8183 variant): `drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c` + (and the shared `phy-mtk-mipi-dsi.c` if the 8183 variant pulls from it). +3. Linux DSI host: `drivers/gpu/drm/mediatek/mtk_dsi.c` — register map for the + DSI host block, timing parameter computation (phy timing, HPW/VPW etc.), + command-mode panel init flow. +4. coreboot 4.14 (the generation on this device): + `src/mainboard/google/kukui/display.c` and the kukui panel files, plus + `src/soc/mediatek/mt8183/{dsi,mipi_tx,mmsys}.c` — a second opinion on + sequencing and on which MMSYS gates/clocks matter. Note what coreboot does + *not* touch: it relies on clocks already on at boot. +5. U-Boot's existing DSI infrastructure: `drivers/video/mipi_dsi.c` + + `include/mipi_dsi.h` (CONFIG_VIDEO_MIPI_DSI helpers — use them for D-PHY + timing computation and packet encoding), `drivers/video/dw_mipi_dsi.c` as an + example DSI_HOST uclass driver, `drivers/video/panel_uclass.c` / + `simple_panel.c` for the PANEL uclass. + +## Confirmed hardware facts (verified on this device — do not re-derive) + +- Panel: BOE TV101WUM-NL6, 1200x1920 native portrait, 4-lane MIPI DSI, + mounted rotated 270° in the chassis; the console is therefore used with + `uc_priv->rot = 3` (see mt8183_scanout.c). +- At payload entry the panel is *powered and initialized* (coreboot ran the + full DSI init sequence), the DSI link is up, but depthcharge's + `display_cleanup()` stopped the overlay engines and turned the backlight + off. OVL0 base register block: `OVL_EN +0x0c`, `OVL0_2L_EN +0x100c`, + `OVL_L0_ADDR +0x0f40` (layer-0 scanout address, still holds the last-used + address across handoff). +- Backlight: two dedicated GPIOs driven high — DISP_PWM (pin 43) and EN_LCD_BL + (pin 176) on the MT8183 GPIO controller at 0x10005000 (dout set@+0x100, + 16 bytes per 32-pin group). +- Coreboot table: fixed at 0xffed9000 on this device (LB_TAG_FRAMEBUFFER + record; physical_address may be 0, then OVL_L0_ADDR is authoritative). +- The scanout framebuffer address is outside the DTB DRAM description; any + buffer you allocate must be mapped with `mmu_map_region()` (see the existing + driver) and *reserved* (see the FDT/LMB reservation pattern already in + mt8183_scanout.c — reuse it for your own framebuffer). +- `drivers/clk/mediatek/clk-mt8183.c` exists in-tree. CHECK which clocks it + registers and whether the MMSYS display gates (OVL0, OVL0_2L, RDMA0, COLOR0, + DSI0, and the MMSYS CG registers) are covered. If display gates are missing, + either extend the clock driver (preferred, upstreamable) or sequence the + MMSYS CG registers directly with documented offsets — pick one and justify. +- Power domains (SCPSYS display domain) are on at handoff; for full cold + bring-up you may need `mtk_scpsys` — check what exists in-tree + (`drivers/power/domain/`); if absent, document the gap rather than + half-implementing it. + +## Architecture guidance (use judgment, document decisions) + +- New DSI host driver: `drivers/video/mtk_dsi.c` + `drivers/video/mtk_mipi_tx.c` + (PHY), bound from the existing DSI node in the upstream krane DT. Use + UCLASS_DSI_HOST ops (enable/phy_set_mode/dsi transfers) and the + VIDEO_MIPI_DSI helpers. +- Panel driver: `drivers/video/panel_boe_tv101wum.c`, UCLASS_PANEL, driven + from the panel child node of the DSI node (compatible `"boe,tv101wum-nl6"`), + porting the init sequence from the Linux panel driver. Supplies/reset GPIO + handling via regulator uclass/GPIO uclass as described by the DT node. +- Integrate with the video uclass: the display driver (`mt8183_scanout.c` or a + successor) must decide between (a) full cold bring-up through your new + pipeline and (b) the existing firmware-handoff revival path. Suggested + shape: try full bring-up first; fall back to handoff revival if the panel + fails to respond, logging which path was taken. Keep both paths Kconfig + selectable so each can be tested in isolation. +- The framebuffer you allocate for bring-up must be reserved exactly like the + scanout buffer is today (FDT memreserve + LMB), or the kernel will corrupt + it after handoff — this was a real bug, see commit 1ae771d9f90. +- Endianness/format: VIDEO_BPP32 XRGB like today; `line_length` from the + panel mode (1200 px * 4). + +## Deliverables and acceptance criteria + +1. DSI host + PHY + panel drivers in-tree, Kconfig-gated, krane defconfig + selecting them; existing boot path unchanged when the fallback is chosen. +2. Full bring-up path verified on device by the user: with the fallback + path disabled, the vidconsole comes up on the panel from cold (i.e. your + code performs clock gating, PHY, DSI init, panel init sequence, framebuffer + setup, backlight). Instrument each phase with serial prints and give the + user a step-by-step test recipe; iterate on their serial reports. +3. `make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu-` builds clean; + checkpatch clean; each commit compiles and is upstream-shaped. +4. `RESEARCH.md` in `/home/vhaudiquet/krane-fb-stub/` updated with numbered + findings (what was ported from where, what you measured/guessed). +5. Final report: what works, what is untested, known gaps (e.g. missing + SCPSYS cold-power sequencing if that applies). + +Work incrementally: fetch references, map the register model, write the PHY + +DSI host first with bring-up prints, get the panel's first frame, then clean +up into upstream-shaped commits. diff --git a/u-boot-krane-prompt.md b/u-boot-krane-prompt.md new file mode 100644 index 0000000..a978dd1 --- /dev/null +++ b/u-boot-krane-prompt.md @@ -0,0 +1,160 @@ +# 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.