Board entry points usually set up the console UART first thing and print a '>' with putc_ll() to show that they have been reached.
Let's make the console part of the board info instead and have the stage dispatch print the stage number followed by '>', e.g. "2>", once it's up. As the UART may need clocks enabled by SoC init or a description only filled in by board init, the console is tried before SoC init and again after each of the two. Without PBL console support or a console description, the stage number goes to DEBUG_LL. With DEBUG, each callback run is reported as well. Assisted-by: Claude:opus-5 Signed-off-by: Ahmad Fatoum <[email protected]> --- Documentation/devel/troubleshooting.rst | 6 +++ include/pbl.h | 6 +++ include/pbl/entry.h | 19 ++++++- pbl/entry.c | 67 ++++++++++++++++++++++++- 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/Documentation/devel/troubleshooting.rst b/Documentation/devel/troubleshooting.rst index 2aef57c3c1e2..39cc88a9a7dd 100644 --- a/Documentation/devel/troubleshooting.rst +++ b/Documentation/devel/troubleshooting.rst @@ -62,6 +62,12 @@ options: the serial console needs to be done in software in some situations before the UART is accessible from the outside. + Boards using the board info entry point (``ENTRY_POINT()``) will + also indicate the boot stage before the ``>`` character, e.g. ``1>2>`` + means the prebootloader entered its 1st stage followed by entering the + 2nd stage. ``CONFIG_DEBUG_PBL`` would provide more information on what + callback is being executed. + .. note:: Make sure the correct UART index or address is selected under **Kernel low-level debugging port** in ``menuconfig``. diff --git a/include/pbl.h b/include/pbl.h index 45640c26e32e..9efc520d6a69 100644 --- a/include/pbl.h +++ b/include/pbl.h @@ -57,4 +57,10 @@ void __noreturn barebox_pbl_entry(ulong, ulong, void *); #define pbl_puts puts_ll #endif +#ifdef DEBUG +#define pbl_debug pbl_puts +#else +#define pbl_debug (void) +#endif + #endif /* __PBL_H__ */ diff --git a/include/pbl/entry.h b/include/pbl/entry.h index 17056a3ab1ca..acf0ea1e1824 100644 --- a/include/pbl/entry.h +++ b/include/pbl/entry.h @@ -26,12 +26,27 @@ enum pbl_stage_idx { typedef void (*pbl_board_fn_t)(void); typedef enum pbl_stage_idx (*pbl_locate_pc_fn_t)(void); +struct pbl_console_driver { + void (*putc)(void *arg, int c); /* as accepted by pbl_set_putc() */ +}; + +/* + * arg is usually the UART base address. A console without setup callback + * is registered before soc_init, else after. Without a console, the PBL + * prints through DEBUG_LL. + */ +struct pbl_console { + void (*setup)(void *arg); + void *arg; + const struct pbl_console_driver *driver; +}; + /* * Only the callbacks of the stage the PBL was entered in are run. * * prereloc_cpu_init runs on the stage's stack, but unrelocated and before * BSS is cleared, so it must be __prereloc and may not use globals. - * The other callbacks run relocated with BSS cleared. + * The console setup and the other callbacks run relocated with BSS cleared. */ struct pbl_stage { unsigned long stacktop; /* stack top or PBL_STACKTOP_* */ @@ -60,6 +75,8 @@ struct pbl_board_info { /* Called without a stack, so it must not spill */ pbl_locate_pc_fn_t assembly_locate_pc; + struct pbl_console console; + struct pbl_stage rom_stage; /* PBL_STAGE_ROM */ struct pbl_stage first_stage; /* PBL_STAGE_OCRAM */ struct pbl_stage second_stage; /* PBL_STAGE_DRAM */ diff --git a/pbl/entry.c b/pbl/entry.c index 1349e7c56a93..827af905964b 100644 --- a/pbl/entry.c +++ b/pbl/entry.c @@ -11,7 +11,11 @@ #include <asm/reloc.h> #include <asm/sections.h> #include <asm-generic/registers.h> +#include <console.h> +#include <debug_ll.h> +#include <stdio.h> #include <barebox.h> +#include <pbl.h> #include <pbl/entry.h> #include <pbl/soc-type.h> #include <pbl/handoff-data.h> @@ -136,6 +140,44 @@ pbl_head_reloc_v1(ulong stage_ul, ulong entry_data) pbl_head_entry_v1(entry_data); } +static void pbl_console_report_stage(int stage_idx) +{ + static bool stage_reported; + char stage_str[2] = "0"; + + if (stage_reported) + return; + + stage_str[0] += stage_idx; + + pbl_puts(stage_str); + pbl_puts(">"); + + stage_reported = true; +} + +/* Called until there is a console, board_init may still describe it */ +static void pbl_console_init(const struct pbl_console *console, + int stage_idx) +{ + static bool console_initialized; + + if (console_initialized) + return; + + if (console->setup) + console->setup(console->arg); + + if (console->driver && console->driver->putc) { + pbl_set_putc(console->driver->putc, console->arg); + console_initialized = true; + } + + /* Without PBL_CONSOLE, pbl_puts() is DEBUG_LL's puts_ll() */ + if (console_initialized || !IS_ENABLED(CONFIG_PBL_CONSOLE)) + pbl_console_report_stage(stage_idx); +} + /* noinline, so &__pbl_board_info isn't computed before relocation */ static void noinline pbl_head_entry_v1(ulong entry_data) { @@ -154,12 +196,35 @@ static void noinline pbl_head_entry_v1(ulong entry_data) current_stage = stage; + /* A console needing no setup is readily usable in soc_init */ + if (!pbi->console.setup) + pbl_console_init(&pbi->console, stage_idx); + if (stage->soc_init) stage->soc_init(); + + /* Initialize console if possible */ + pbl_console_init(&pbi->console, stage_idx); + + if (stage->soc_init) + pbl_debug("soc_init done\n"); + if (stage->board_init) stage->board_init(entry_data); - if (stage->soc_chainload) + + /* Initialize console if possible */ + pbl_console_init(&pbi->console, stage_idx); + + /* Without a console, the stage goes to the DEBUG_LL fallback */ + pbl_console_report_stage(stage_idx); + + if (stage->board_init) + pbl_debug("board_init done\n"); + + if (stage->soc_chainload) { + pbl_debug("Chainloading..\n"); stage->soc_chainload(stage->board_data); + } hang(); } -- 2.47.3
