From 8cda58518bc55768d91a414ce2c6e18f7c0c8f3c Mon Sep 17 00:00:00 2001 From: vhaudiquet Date: Sun, 30 Aug 2026 17:50:00 +0200 Subject: [PATCH] WIP (temporary): framebuffer text logger and abort dump for bring-up --- arch/arm/lib/interrupts_64.c | 6 ++ drivers/video/mt8183_scanout.c | 119 +++++++++++++++++++++++++++++++-- 2 files changed, 118 insertions(+), 7 deletions(-) diff --git a/arch/arm/lib/interrupts_64.c b/arch/arm/lib/interrupts_64.c index b3024ba514e..4ee24aec805 100644 --- a/arch/arm/lib/interrupts_64.c +++ b/arch/arm/lib/interrupts_64.c @@ -194,6 +194,12 @@ void do_bad_error(struct pt_regs *pt_regs) */ void do_sync(struct pt_regs *pt_regs) { + extern void krane_fb_log_abort(unsigned long esr, unsigned long elr); + + /* TEMPORARY bring-up diagnostics (krane Round 30) — do not + * upstream: draw the abort registers on the panel. */ + krane_fb_log_abort(pt_regs->esr, pt_regs->elr); + if (CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK) && smh_emulate_trap(pt_regs)) return; diff --git a/drivers/video/mt8183_scanout.c b/drivers/video/mt8183_scanout.c index e3d71bdf743..bdc46632fba 100644 --- a/drivers/video/mt8183_scanout.c +++ b/drivers/video/mt8183_scanout.c @@ -21,6 +21,7 @@ #include #include +#include /* Get font data, width and height */ #include #include #include @@ -33,8 +34,6 @@ * src/drivers/video/mtk_ddp.c (ChromeOS R93, the generation shipped on * kukui); both agree on 0x000c for OVL_EN. The 2L sub-engine enable * (DISP_REG_OVL0_2L_EN) lives in the same register block on MT8183. - * The layer-0 source address register (DISP_REG_OVL_L0_ADDR) is not reset - * by depthcharge's stop() and holds the live scanout address. */ #define DISP_REG_OVL_L0_ADDR 0x0f40 #define DISP_REG_OVL_EN 0x000c @@ -42,6 +41,111 @@ /* TEMPORARY bring-up diagnostics (krane Round 24) — do not upstream: * paint a band into the live depthcharge scanout. */ + +/* TEMPORARY bring-up diagnostics (krane Round 30) — do not upstream: + * minimal framebuffer text logger using the built-in 8x16 font, so + * abort dumps and probe logs are readable on the panel even before + * the console exists. */ +static void krane_fb_log_char(const struct video_fontdata *f, + u32 base, u32 x0, u32 y0, char c, u32 color) +{ + const u8 *glyph = &f->video_fontdata[(u8)c * f->height]; + u32 r, b; + + if (c < 32 || c > 126) + c = '?'; + glyph = &f->video_fontdata[(u8)c * f->height]; + + for (r = 0; r < (u32)f->height; r++) { + u32 *row = (u32 *)(uintptr_t)(base + + (u64)(y0 + r) * 4800 + (u64)x0 * 4); + u8 bits = glyph[r]; + + for (b = 0; b < (u32)f->width; b++) + if (bits & (0x80 >> b)) + row[b] = color; + } +} + +static void krane_fb_log(const char *s) +{ + const struct video_fontdata *f = &fonts[0]; + static u32 line, col; + u32 base = readl((void __iomem *)0x14008f40); + + if (base < 0x40000000) + return; + + if (dcache_status()) + mmu_map_region(base, 0x8ca000, false); + + for (; *s; s++) { + if (*s == '\n' || col + f->width > 1200) { + line++; + col = 0; + if (*s == '\n') + continue; + } + krane_fb_log_char(f, base, col, 1700 + line * f->height, + *s, 0x00ffffff); + col += f->width; + } + + if (dcache_status()) + flush_dcache_range((uintptr_t)(base + 1690ULL * 4800), + (uintptr_t)(base + 1920ULL * 4800)); +} + +static void krane_fb_log_hex(const char *prefix, unsigned long v) +{ + char buf[32], *p = buf; + int i; + const char hexdigits[] = "0123456789abcdef"; + + for (i = 0; prefix[i] && i < 15; i++) + *p++ = prefix[i]; + *p++ = '0'; + *p++ = 'x'; + for (i = (sizeof(v) * 8) - 4; i >= 0; i -= 4) + *p++ = hexdigits[(v >> i) & 0xf]; + *p = 0; + krane_fb_log(buf); + krane_fb_log("\n"); +} + +/* Called from the arm64 abort handlers (temporary wiring in + * arch/arm/lib/interrupts_64.c): draw ESR/ELR/FAR on the panel. */ +void krane_fb_log_abort(unsigned long esr, unsigned long elr) +{ + unsigned long far, cvel; + + asm volatile("mrs %0, CurrentEL" : "=r"(cvel)); + switch (cvel >> 2) { + case 1: + asm volatile("mrs %0, far_el1" : "=r"(far)); + break; + case 3: + asm volatile("mrs %0, far_el3" : "=r"(far)); + break; + default: + asm volatile("mrs %0, far_el2" : "=r"(far)); + } + + krane_fb_log("\nABORT!\n"); + krane_fb_log_hex("ESR=", esr); + krane_fb_log_hex("ELR=", elr); + krane_fb_log_hex("FAR=", far); +} + + +/* + * Backlight GPIOs. The MT8183 GPIO controller is at 0x10005000; the dout + * block starts at +0x100 with 16 bytes per 32-pin group and set@+4 (layout + * of GpioRegs/GpioValRegs in device-era depthcharge src/drivers/gpio/ + * mt8183.h). On kukui the backlight is driven by two dedicated GPIOs: + * + * TEMPORARY bring-up diagnostics (krane Round 24) — do not upstream: + * paint a band into the live depthcharge scanout. */ static void krane_diag_band(u32 y0, u32 rows, u32 color) { u32 base = readl((void __iomem *)0x14008f40); @@ -60,12 +164,7 @@ static void krane_diag_band(u32 y0, u32 rows, u32 color) if (dcache_status()) flush_dcache_range((uintptr_t)p, (uintptr_t)(p + n)); } - /* - * Backlight GPIOs. The MT8183 GPIO controller is at 0x10005000; the dout - * block starts at +0x100 with 16 bytes per 32-pin group and set@+4 (layout - * of GpioRegs/GpioValRegs in device-era depthcharge src/drivers/gpio/ - * mt8183.h). On kukui the backlight is driven by two dedicated GPIOs: * DISP_PWM (pin 43) and EN_LCD_BL (PERIPHERAL_EN13, pin 176); depthcharge's * kukui_backlight_update() drives both high to turn the backlight on. */ @@ -169,6 +268,7 @@ static int mt8183_scanout_probe(struct udevice *dev) int ret; krane_diag_band(500, 40, 0x00ff00ff); /* magenta: probe entered */ + krane_fb_log("PROBE"); ovl = dev_read_addr(dev); if (ovl == FDT_ADDR_T_NONE) { @@ -189,6 +289,7 @@ static int mt8183_scanout_probe(struct udevice *dev) writel(MTK_GPIO_DOUT_BIT(PAD_EN_LCD_BL), (void __iomem *)MTK_GPIO_DOUT_SET(PAD_EN_LCD_BL)); krane_diag_band(520, 20, 0x0000ff80); /* mint: revival writes done */ + krane_fb_log(" REVIVE"); /* * The coreboot table sits above the DRAM window described by the @@ -196,6 +297,7 @@ static int mt8183_scanout_probe(struct udevice *dev) */ mmu_map_region(COREBOOT_TABLE_ADDR, SZ_4K, false); krane_diag_band(540, 20, 0x008000ff); /* violet: table mapped */ + krane_fb_log(" MAPTBL"); ret = find_framebuffer(COREBOOT_TABLE_ADDR, &fb); if (ret) { @@ -203,6 +305,7 @@ static int mt8183_scanout_probe(struct udevice *dev) return log_msg_ret("lbio", ret); } krane_diag_band(560, 20, 0x00ffff80); /* pale yellow: LBIO found */ + krane_fb_log(" LBIO"); if (fb.bits_per_pixel != 32 || fb.red_pos != 16 || fb.red_size != 8 || fb.green_pos != 8 || fb.green_size != 8 || @@ -211,6 +314,7 @@ static int mt8183_scanout_probe(struct udevice *dev) return log_msg_ret("fmt", -ENOTSUPP); } krane_diag_band(580, 20, 0x0080ffff); /* pale cyan: fmt OK */ + krane_fb_log(" FMT"); /* * Use the address from the coreboot table when it is a plausible @@ -227,6 +331,7 @@ static int mt8183_scanout_probe(struct udevice *dev) return log_msg_ret("scanout", -ENODEV); } krane_diag_band(620, 40, 0x00aaaaaa); /* gray: geometry resolved */ + krane_fb_log(" GEO"); plat->base = addr; plat->size = fb.bytes_per_line * fb.y_resolution;