From 8e92d068c32e2c0f9272c3c40f60cd506edb8adf Mon Sep 17 00:00:00 2001 From: snlavaise Date: Thu, 17 Sep 2026 01:13:01 -0300 Subject: [PATCH] rtwo: replace debug blink instrumentation with a boot progress bar Confirmed on hardware that the chainload boots. The per-call blink instrumentation lived in hot paths (clk_enable/qcom_gate_clk_en/serial probe) and did a full 10 MiB framebuffer clear + cache flush on every call, noticeably slowing boot. Replaced with a single progress bar hooked once per INITCALL step (include/initcall.h) plus an explicit 100% draw at the end of board_late_init(), touching only the bar's rectangle instead of the whole screen. Kept the real fixes from the same patch (qcom,kalama-gcc-v2 GCC compatible, the IS_ERR(clk) handling in serial_msm_geni.c) untouched. --- arch/arm/mach-snapdragon/board.c | 147 ++++++++++++++++--------------- drivers/clk/clk-uclass.c | 13 +-- drivers/clk/qcom/clock-qcom.c | 20 +---- drivers/clk/qcom/clock-sm8550.c | 5 -- drivers/serial/serial_msm_geni.c | 21 ----- include/initcall.h | 8 +- 6 files changed, 85 insertions(+), 129 deletions(-) diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index f5b6e670..d394022a 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -519,6 +519,8 @@ void __weak qcom_late_init(void) #define lmb_alloc(size, addr) lmb_alloc_mem(LMB_MEM_ALLOC_ANY, SZ_2M, addr, size, LMB_NONE) +void rtwo_boot_progress_done(void); + /* Stolen from arch/arm/mach-apple/board.c */ int board_late_init(void) { @@ -578,6 +580,8 @@ int board_late_init(void) /* Configure the dfu_string for capsule updates */ qcom_configure_capsule_updates(); + rtwo_boot_progress_done(); + return 0; } @@ -756,36 +760,42 @@ void enable_caches(void) } /* - * Instrumentacion temporal de bring-up (rtwo, SM8550): sin UART, la unica - * senal visible que este ABL deja disponible es el framebuffer que deja - * prendido en 0xb8000000 (splash_region). Cada zona de codigo (board_init_f - * generico, board_init_r generico, probe de serial, camino de clk_enable) - * llama a rtwo_debug_blink_zone() con su propio numero de zona, que se - * dibuja como DOS DIGITOS GRANDES ESTILO 7-SEGMENTOS (blanco sobre negro, - * el numero de zona en decimal, directo). Los esquemas anteriores (bandas - * horizontales para contar, luego un codigo binario de 6 barras) resultaron - * fragiles con luz/reflejo del vidrio: dos lecturas distintas del mismo - * codigo de barras (una por foto, otra mirando el telefono directo) sobre - * la misma pantalla congelada -- ver memoria rtwo-uboot-chainload. Un - * numero grande no necesita interpretacion. Cada sitio instrumentado en - * board.c/serial_msm_geni.c/clk-uclass.c/clock-qcom.c/clock-sm8550.c tiene - * su propio numero GLOBAL y UNICO de zona (1, 2 para los INITCALL - * genericos de board_init_f/board_init_r; 10-39 para los pasos de probe de - * serial y del camino de clk_enable). rtwo_debug_blink() (zona 1/2 segun - * GD_FLG_RELOC) es la que llama include/initcall.h en cada INITCALL de - * board_init_f/board_init_r. - * Mantenimiento de cache manual porque el framebuffer lo lee el - * controlador de display directamente de DRAM, sin pasar por la CPU. + * Barra de progreso de arranque (rtwo, SM8550): dibuja en el framebuffer que + * el ABL deja prendido en 0xb8000000 (splash_region), la unica senal visible + * sin UART. Reemplaza la instrumentacion de bring-up anterior (digitos de + * 7 segmentos por zona de codigo en board.c/serial_msm_geni.c/clk-uclass.c/ + * clock-qcom.c/clock-sm8550.c, ver historial en memoria rtwo-uboot-chainload) + * una vez confirmado que el chainload arranca: aquella instrumentacion vivia + * dentro de rutas calientes (clk_enable/qcom_gate_clk_en/probe de serial, con + * un flush de cache de los 10 MiB completos del framebuffer en CADA llamada) + * y se disparaba decenas de veces por segundo, alargando bastante el arranque. + * Esta version solo se engancha una vez por paso de `include/initcall.h` + * (rtwo_boot_progress_step(), UN llamado por entrada de + * init_sequence_f[]/init_sequence_r[], no por operacion de bajo nivel) y solo + * toca/flushea el rectangulo de la barra, no la pantalla entera. + * Mantenimiento de cache manual porque el framebuffer lo lee el controlador + * de display directamente de DRAM, sin pasar por la CPU. */ #define RTWO_FB_BASE 0xb8000000UL #define RTWO_FB_SIZE 0xA00000UL /* 10 MiB: cubre 1080x2400x4 con margen */ #define RTWO_FB_STRIDE_WORDS 1080UL /* ancho en palabras de 32 bits */ -#define RTWO_DIGIT_W 360UL -#define RTWO_DIGIT_H 700UL -#define RTWO_DIGIT_THICK 70UL -#define RTWO_DIGIT_GAP 60UL -#define RTWO_DIGIT_Y0 850UL /* deja libre la zona de la camara punch-hole arriba */ +#define RTWO_BAR_X0 140UL +#define RTWO_BAR_X1 940UL /* 800 px de ancho, centrada */ +#define RTWO_BAR_Y0 1150UL +#define RTWO_BAR_Y1 1250UL /* 100 px de alto */ +#define RTWO_BAR_BORDER 6UL + +/* + * Estimacion aproximada de cuantos pasos de INITCALL hay entre + * board_init_f() y board_init_r() en esta config -- no hace falta que sea + * exacta, solo que la barra avance de forma pareja y no llegue a 100% antes + * de tiempo. rtwo_boot_progress_done() (llamada al final de + * board_late_init(), justo antes de bootcmd) la fuerza a 100% siempre, sin + * depender de haber contado bien. + */ +#define RTWO_BOOT_STEPS_ESTIMATE 40U +#define RTWO_BOOT_PROGRESS_CAP 96U /* tope hasta el 100% explicito */ static void rtwo_fill_rect(volatile unsigned int *fb, unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1, unsigned int color) @@ -800,59 +810,56 @@ static void rtwo_fill_rect(volatile unsigned int *fb, unsigned long x0, unsigned } } -/* Mascara de segmentos por digito: bit0=A(arriba) bit1=B(sup-der) - * bit2=C(inf-der) bit3=D(abajo) bit4=E(inf-izq) bit5=F(sup-izq) bit6=G(medio), - * codificacion estandar de un display de 7 segmentos. - */ -static void rtwo_draw_digit(volatile unsigned int *fb, unsigned long x0, unsigned int digit) +static void rtwo_flush_bar_cache(void) { - static const unsigned char segs[10] = { - 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, - }; - unsigned char m = digit < 10 ? segs[digit] : 0; - unsigned long y0 = RTWO_DIGIT_Y0; - unsigned long yh = y0 + RTWO_DIGIT_H / 2; - unsigned long y1 = y0 + RTWO_DIGIT_H; - unsigned long t = RTWO_DIGIT_THICK; - unsigned int on = 0xFFFFFFFFu; - - if (m & 0x01) /* A */ - rtwo_fill_rect(fb, x0 + t, y0, x0 + RTWO_DIGIT_W - t, y0 + t, on); - if (m & 0x40) /* G */ - rtwo_fill_rect(fb, x0 + t, yh - t / 2, x0 + RTWO_DIGIT_W - t, yh + t / 2, on); - if (m & 0x08) /* D */ - rtwo_fill_rect(fb, x0 + t, y1 - t, x0 + RTWO_DIGIT_W - t, y1, on); - if (m & 0x20) /* F */ - rtwo_fill_rect(fb, x0, y0, x0 + t, yh + t / 2, on); - if (m & 0x02) /* B */ - rtwo_fill_rect(fb, x0 + RTWO_DIGIT_W - t, y0, x0 + RTWO_DIGIT_W, yh + t / 2, on); - if (m & 0x10) /* E */ - rtwo_fill_rect(fb, x0, yh - t / 2, x0 + t, y1, on); - if (m & 0x04) /* C */ - rtwo_fill_rect(fb, x0 + RTWO_DIGIT_W - t, yh - t / 2, x0 + RTWO_DIGIT_W, y1, on); -} - -void rtwo_debug_blink_zone(unsigned int zone) -{ - volatile unsigned int *fb = (volatile unsigned int *)RTWO_FB_BASE; - const unsigned long total_words = RTWO_FB_SIZE / 4; - const unsigned long total_rows = total_words / RTWO_FB_STRIDE_WORDS; - const unsigned long margin_left = (RTWO_FB_STRIDE_WORDS - (2 * RTWO_DIGIT_W + RTWO_DIGIT_GAP)) / 2; unsigned long addr; - - rtwo_fill_rect(fb, 0, 0, RTWO_FB_STRIDE_WORDS, total_rows, 0u); /* fondo negro */ - - rtwo_draw_digit(fb, margin_left, zone / 10U); - rtwo_draw_digit(fb, margin_left + RTWO_DIGIT_W + RTWO_DIGIT_GAP, zone % 10U); + unsigned long start = RTWO_FB_BASE + RTWO_BAR_Y0 * RTWO_FB_STRIDE_WORDS * 4; + unsigned long end = RTWO_FB_BASE + RTWO_BAR_Y1 * RTWO_FB_STRIDE_WORDS * 4; asm volatile("dsb sy" ::: "memory"); - for (addr = RTWO_FB_BASE; addr < RTWO_FB_BASE + RTWO_FB_SIZE; addr += 64) + for (addr = start & ~63UL; addr < end; addr += 64) asm volatile("dc civac, %0" :: "r"(addr) : "memory"); asm volatile("dsb sy" ::: "memory"); asm volatile("isb" ::: "memory"); } -void rtwo_debug_blink(void) +static void rtwo_draw_progress_bar(unsigned int percent) { - rtwo_debug_blink_zone((gd->flags & GD_FLG_RELOC) ? 2U : 1U); + volatile unsigned int *fb = (volatile unsigned int *)RTWO_FB_BASE; + unsigned long fill_x1; + + if (percent > 100U) + percent = 100U; + + /* borde blanco */ + rtwo_fill_rect(fb, RTWO_BAR_X0, RTWO_BAR_Y0, RTWO_BAR_X1, RTWO_BAR_Y1, 0xFFFFFFFFu); + /* fondo negro, dentro del borde */ + rtwo_fill_rect(fb, RTWO_BAR_X0 + RTWO_BAR_BORDER, RTWO_BAR_Y0 + RTWO_BAR_BORDER, + RTWO_BAR_X1 - RTWO_BAR_BORDER, RTWO_BAR_Y1 - RTWO_BAR_BORDER, 0u); + + fill_x1 = RTWO_BAR_X0 + RTWO_BAR_BORDER + + (RTWO_BAR_X1 - RTWO_BAR_X0 - 2 * RTWO_BAR_BORDER) * percent / 100U; + if (fill_x1 > RTWO_BAR_X0 + RTWO_BAR_BORDER) + rtwo_fill_rect(fb, RTWO_BAR_X0 + RTWO_BAR_BORDER, RTWO_BAR_Y0 + RTWO_BAR_BORDER, + fill_x1, RTWO_BAR_Y1 - RTWO_BAR_BORDER, 0xFFFFFFFFu); + + rtwo_flush_bar_cache(); +} + +void rtwo_boot_progress_step(void) +{ + static unsigned int steps; + unsigned int percent; + + steps++; + percent = steps * RTWO_BOOT_PROGRESS_CAP / RTWO_BOOT_STEPS_ESTIMATE; + if (percent > RTWO_BOOT_PROGRESS_CAP) + percent = RTWO_BOOT_PROGRESS_CAP; + + rtwo_draw_progress_bar(percent); +} + +void rtwo_boot_progress_done(void) +{ + rtwo_draw_progress_bar(100U); } diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index e67b48d2..c33f4159 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -657,21 +657,15 @@ int clk_set_parent(struct clk *clk, struct clk *parent) return 0; } -void rtwo_debug_blink_zone(unsigned int zone); - int clk_enable(struct clk *clk) { const struct clk_ops *ops; struct clk *clkp = NULL; int ret; - rtwo_debug_blink_zone(23); /* CLKEN-1: entrada a clk_enable */ debug("%s(clk=%p name=%s)\n", __func__, clk, clk ? clk->dev->name : "NULL"); - if (!clk_valid(clk)) { - rtwo_debug_blink_zone(24); /* CLKEN-2a: clk invalido/NULL, return temprano */ + if (!clk_valid(clk)) return 0; - } - rtwo_debug_blink_zone(25); /* CLKEN-2b: clk valido, seguimos */ ops = clk_dev_ops(clk->dev); if (CONFIG_IS_ENABLED(CLK_CCF)) { @@ -705,10 +699,7 @@ int clk_enable(struct clk *clk) } else { if (!ops->enable) return -ENOSYS; - rtwo_debug_blink_zone(26); /* CLKEN-3: justo antes de ops->enable(clk) */ - ret = ops->enable(clk); - rtwo_debug_blink_zone(27); /* CLKEN-4: ops->enable(clk) retorno */ - return ret; + return ops->enable(clk); } return 0; diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c index 9bce5abd..6b46d9db 100644 --- a/drivers/clk/qcom/clock-qcom.c +++ b/drivers/clk/qcom/clock-qcom.c @@ -28,8 +28,6 @@ #include "clock-qcom.h" -void rtwo_debug_blink_zone(unsigned int zone); - /* CBCR register fields */ #define CBCR_BRANCH_ENABLE_BIT BIT(0) #define CBCR_BRANCH_OFF_BIT BIT(31) @@ -78,21 +76,17 @@ void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk) int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id) { - rtwo_debug_blink_zone(28); /* GATE-1: entrada a qcom_gate_clk_en */ if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) { log_err("gcc@%#08llx: unknown clock ID %lu!\n", priv->base, id); return -ENOENT; } - rtwo_debug_blink_zone(29); /* GATE-2: id valido, antes de setbits_le32 */ setbits_le32(priv->base + priv->data->clks[id].reg, priv->data->clks[id].en_val); - rtwo_debug_blink_zone(30); /* GATE-3: post setbits_le32 (el registro ya se escribio) */ if (priv->data->clks[id].cbcr_reg) { unsigned int count; u32 val; - rtwo_debug_blink_zone(31); /* GATE-4: hay cbcr_reg, entrando al poll acotado */ for (count = 0; count < 200; count++) { val = readl(priv->base + priv->data->clks[id].cbcr_reg); val &= BRANCH_CHECK_MASK; @@ -100,14 +94,10 @@ int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id) break; udelay(1); } - rtwo_debug_blink_zone(33); /* GATE-5: poll terminado (por bit ok o por timeout) */ if (WARN(count == 200, "WARNING: Clock @ %#lx [%#010x] stuck at off\n", priv->data->clks[id].cbcr_reg, val)) return -EBUSY; - } else { - rtwo_debug_blink_zone(32); /* GATE-4b: no hay cbcr_reg, no se espera nada */ } - rtwo_debug_blink_zone(34); /* GATE-6: fin de qcom_gate_clk_en, return 0 */ return 0; } @@ -266,14 +256,8 @@ static int msm_clk_enable(struct clk *clk) { struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(clk->dev); - rtwo_debug_blink_zone(35); /* MSMCLK-1: entrada a msm_clk_enable */ - if (data->enable) { - int ret; - rtwo_debug_blink_zone(36); /* MSMCLK-2: antes de data->enable(clk) */ - ret = data->enable(clk); - rtwo_debug_blink_zone(37); /* MSMCLK-3: data->enable(clk) retorno */ - return ret; - } + if (data->enable) + return data->enable(clk); return 0; } diff --git a/drivers/clk/qcom/clock-sm8550.c b/drivers/clk/qcom/clock-sm8550.c index a340b675..dc6e2b2c 100644 --- a/drivers/clk/qcom/clock-sm8550.c +++ b/drivers/clk/qcom/clock-sm8550.c @@ -198,14 +198,10 @@ static const struct gate_clk sm8550_clks[] = { GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x39068, BIT(0)), }; -void rtwo_debug_blink_zone(unsigned int zone); - static int sm8550_enable(struct clk *clk) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); - rtwo_debug_blink_zone(38); /* SM8550EN-1: entrada a sm8550_enable, id=%clk->id (sin printf aqui) */ - switch (clk->id) { case GCC_AGGRE_USB3_PRIM_AXI_CLK: qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); @@ -224,7 +220,6 @@ static int sm8550_enable(struct clk *clk) break; } - rtwo_debug_blink_zone(39); /* SM8550EN-2: post switch, antes de qcom_gate_clk_en final */ return qcom_gate_clk_en(priv, clk->id); } diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c index a2a9a5ce..87c9deab 100644 --- a/drivers/serial/serial_msm_geni.c +++ b/drivers/serial/serial_msm_geni.c @@ -19,8 +19,6 @@ #include #include -void rtwo_debug_blink_zone(unsigned int zone); - #define UART_OVERSAMPLING 32 #define STALE_TIMEOUT 160 @@ -211,15 +209,12 @@ static int msm_serial_setbrg(struct udevice *dev, int baud) pr_err("%s: Couldn't get clock division rate\n", __func__); return -EINVAL; } - rtwo_debug_blink_zone(10); /* SETBRG-1: pre clk_set_rate */ ret = clk_set_rate(priv->se, clk_rate); - rtwo_debug_blink_zone(11); /* SETBRG-2: post clk_set_rate */ if (ret < 0) { pr_err("%s: Couldn't set clock rate: %d\n", __func__, ret); return 0; } geni_serial_baud(priv->base, clk_div, baud); - rtwo_debug_blink_zone(12); /* SETBRG-3: post geni_serial_baud */ return 0; } @@ -522,8 +517,6 @@ static int msm_serial_probe(struct udevice *dev) u32 proto; struct clk *clk; - rtwo_debug_blink_zone(13); /* PROBE-1: entrada */ - clk = devm_clk_get_optional(dev, NULL); if (IS_ERR(clk)) { /* @@ -539,13 +532,9 @@ static int msm_serial_probe(struct udevice *dev) priv->se = clk; } - rtwo_debug_blink_zone(14); /* PROBE-2: post devm_clk_get_optional */ - /* Try enable clock */ clk_enable(clk); - rtwo_debug_blink_zone(15); /* PROBE-3: post clk_enable */ - /* Check if firmware loading is needed (BT UART) */ proto = readl(priv->base + GENI_FW_REVISION_RO); proto &= FW_REV_PROTOCOL_MSK; @@ -558,8 +547,6 @@ static int msm_serial_probe(struct udevice *dev) proto >>= FW_REV_PROTOCOL_SHFT; } - rtwo_debug_blink_zone(16); /* PROBE-4: post firmware check/load */ - if (proto != GENI_SE_UART) { dev_err(dev, "Invalid proto %d\n", proto); clk_disable(clk); @@ -570,26 +557,18 @@ static int msm_serial_probe(struct udevice *dev) if (ofnode_device_is_compatible(dev_ofnode(dev), "qcom,geni-uart")) return -ENOENT; - rtwo_debug_blink_zone(17); /* PROBE-5: es geni-debug-uart, seguimos */ - ret = geni_set_oversampling(dev); if (ret < 0) return ret; - rtwo_debug_blink_zone(18); /* PROBE-6: post geni_set_oversampling */ - /* No need to reinitialize the UART after relocation */ if (gd->flags & GD_FLG_RELOC) return 0; geni_serial_init(dev); - rtwo_debug_blink_zone(19); /* PROBE-7: post geni_serial_init */ msm_geni_serial_setup_rx(dev); - rtwo_debug_blink_zone(20); /* PROBE-8: post msm_geni_serial_setup_rx */ qcom_geni_serial_start_rx(dev); - rtwo_debug_blink_zone(21); /* PROBE-9: post qcom_geni_serial_start_rx */ qcom_geni_serial_start_tx(priv->base); - rtwo_debug_blink_zone(22); /* PROBE-10: post qcom_geni_serial_start_tx, fin de probe */ return 0; } diff --git a/include/initcall.h b/include/initcall.h index 1f179e34..f9a82cad 100644 --- a/include/initcall.h +++ b/include/initcall.h @@ -13,15 +13,15 @@ _Static_assert(EVT_COUNT < 256, "Can only support 256 event types with 8 bits"); #ifdef CONFIG_ARCH_SNAPDRAGON -void rtwo_debug_blink(void); -#define RTWO_DEBUG_BLINK() rtwo_debug_blink() +void rtwo_boot_progress_step(void); +#define RTWO_BOOT_PROGRESS() rtwo_boot_progress_step() #else -#define RTWO_DEBUG_BLINK() +#define RTWO_BOOT_PROGRESS() #endif #define INITCALL(_call) \ do { \ - RTWO_DEBUG_BLINK(); \ + RTWO_BOOT_PROGRESS(); \ if (_call()) { \ printf("%s(): initcall %s() failed\n", __func__, \ #_call); \