diff --git a/krane-fb-stub-payload.bin b/krane-fb-stub-payload.bin index 38bed8a..9329efc 100644 Binary files a/krane-fb-stub-payload.bin and b/krane-fb-stub-payload.bin differ diff --git a/krane-fb-stub.bin b/krane-fb-stub.bin index a81aed5..135e283 100755 Binary files a/krane-fb-stub.bin and b/krane-fb-stub.bin differ diff --git a/main.c b/main.c index 1433853..b7a818d 100644 --- a/main.c +++ b/main.c @@ -233,6 +233,48 @@ static void fill_screen(const struct fbinfo *f, u64 val) } } +/* ---- display revival ---------------------------------------------------- + * + * Verified against the DEVICE's depthcharge (v0.0.22-10476, 2021/2022): + * display_cleanup() runs at CleanupOnHandoff before jumping here: + * 1. clear_screen(black) — LBIO framebuffer painted black + * 2. backlight_update(false) — GPIO 43 (DISP_PWM) and GPIO 176 + * (EN_LCD_BL) driven low + * 3. mtk_display_stop() — OVL_EN=0 and OVL0_2L_EN=0 + * The DSI link, panel and display MTCMOS stay up (no panel poweroff in this + * firmware generation). So the stub just needs to undo exactly those three + * steps — no DSI/panel re-init required. + */ + +#define DISP_OVL0_BASE 0x14008000u +#define DISP_REG_OVL_EN 0x0F00u /* 2021 mtk_ddp.c */ +#define DISP_REG_OVL0_2L_EN 0x100Cu /* 2021 mtk_ddp.c */ + +#define GPIO_BASE 0x10005000u +/* GpioValRegs: val@0, set@4, rst@8, 16 bytes per 32-pin group */ +#define GPIO_DOUT_SET(pin) (GPIO_BASE + 0x140 + ((pin) / 32) * 16 + 4) +#define GPIO_DOUT_BIT(pin) (1u << ((pin) % 32)) + +#define PAD_DISP_PWM 43 /* DISP_PWM */ +#define PAD_EN_LCD_BL 176 /* PERIPHERAL_EN13 */ + +static void wr32(u64 addr, u32 val) +{ + *(volatile u32 *)addr = val; +} + +/* Undo depthcharge's display_cleanup() so our fills are visible. */ +static void display_revive(void) +{ + /* Same buffer depthcharge scanned out for the menu. */ + wr32(DISP_OVL0_BASE + DISP_REG_OVL_EN, 1); + wr32(DISP_OVL0_BASE + DISP_REG_OVL0_2L_EN, 1); + + /* Backlight on (both pins), matching kukui_backlight_update(true). */ + wr32(GPIO_DOUT_SET(PAD_DISP_PWM), GPIO_DOUT_BIT(PAD_DISP_PWM)); + wr32(GPIO_DOUT_SET(PAD_EN_LCD_BL), GPIO_DOUT_BIT(PAD_EN_LCD_BL)); +} + /* ---- main checkpoint sequence ------------------------------------------- */ static void checkpoint(const struct fbinfo *f, int r, int g, int b) @@ -248,17 +290,20 @@ void cmain(u64 dtb) u32 lbio_size; /* - * Parse everything first (instantaneous); see deviation note above. - * If either stage fails we halt having painted nothing — the screen - * keeps depthcharge's output, which identifies the failure stage. + * Parse everything first (instantaneous). On failure halt unpainted: + * depthcharge blacked the screen and disabled the OVL engine, so the + * failure signature is a black screen right after the menu. */ if (find_coreboot_reg((const void *)dtb, &lbio_addr, &lbio_size)) - halt(); /* stuck on depthcharge output */ + halt(); /* black screen: DTB parse failed */ if (find_framebuffer(lbio_addr, &fb)) - halt(); /* stuck on depthcharge output */ + halt(); /* black screen: LBIO/fb record bad */ - /* Checkpoint 1: red — we entered, parsed, and can draw. */ + /* Re-enable scanout + backlight, then paint. */ + display_revive(); + + /* Checkpoint 1: red — we entered, parsed, revived the display. */ checkpoint(&fb, 1, 0, 0); /* red */ /* Checkpoint 2: yellow — DTB stage. */ checkpoint(&fb, 1, 1, 0); /* yellow */