xref: /openbmc/linux/arch/powerpc/kernel/udbg.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
235cd8785SDavid Gibson /*
335cd8785SDavid Gibson  * polling mode stateless debugging stuff, originally for NS16550 Serial Ports
435cd8785SDavid Gibson  *
535cd8785SDavid Gibson  * c 2001 PPC 64 Team, IBM Corp
635cd8785SDavid Gibson  */
735cd8785SDavid Gibson 
8c0891ac1SAlexey Dobriyan #include <linux/stdarg.h>
935cd8785SDavid Gibson #include <linux/types.h>
1035cd8785SDavid Gibson #include <linux/sched.h>
1135cd8785SDavid Gibson #include <linux/console.h>
123b5e905eSBenjamin Herrenschmidt #include <linux/init.h>
1335cd8785SDavid Gibson #include <asm/processor.h>
14296167aeSMichael Ellerman #include <asm/udbg.h>
1535cd8785SDavid Gibson 
1651d3082fSBenjamin Herrenschmidt void (*udbg_putc)(char c);
17af9c7249SAndrew Klossner void (*udbg_flush)(void);
18bb6b9b28SBenjamin Herrenschmidt int (*udbg_getc)(void);
1935cd8785SDavid Gibson int (*udbg_getc_poll)(void);
2035cd8785SDavid Gibson 
21296167aeSMichael Ellerman /*
22296167aeSMichael Ellerman  * Early debugging facilities. You can enable _one_ of these via .config,
23296167aeSMichael Ellerman  * if you do so your kernel _will not boot_ on anything else. Be careful.
24296167aeSMichael Ellerman  */
udbg_early_init(void)25296167aeSMichael Ellerman void __init udbg_early_init(void)
26296167aeSMichael Ellerman {
27296167aeSMichael Ellerman #if defined(CONFIG_PPC_EARLY_DEBUG_LPAR)
28296167aeSMichael Ellerman 	/* For LPAR machines that have an HVC console on vterm 0 */
29296167aeSMichael Ellerman 	udbg_init_debug_lpar();
304d2bb3f5SBenjamin Herrenschmidt #elif defined(CONFIG_PPC_EARLY_DEBUG_LPAR_HVSI)
314d2bb3f5SBenjamin Herrenschmidt 	/* For LPAR machines that have an HVSI console on vterm 0 */
324d2bb3f5SBenjamin Herrenschmidt 	udbg_init_debug_lpar_hvsi();
33296167aeSMichael Ellerman #elif defined(CONFIG_PPC_EARLY_DEBUG_G5)
34296167aeSMichael Ellerman 	/* For use on Apple G5 machines */
35296167aeSMichael Ellerman 	udbg_init_pmac_realmode();
36cc46bb98SMichael Ellerman #elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL)
37296167aeSMichael Ellerman 	/* RTAS panel debug */
38cc46bb98SMichael Ellerman 	udbg_init_rtas_panel();
39cc46bb98SMichael Ellerman #elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE)
40cc46bb98SMichael Ellerman 	/* RTAS console debug */
41cc46bb98SMichael Ellerman 	udbg_init_rtas_console();
42296167aeSMichael Ellerman #elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
43296167aeSMichael Ellerman 	/* Maple real mode debug */
44296167aeSMichael Ellerman 	udbg_init_maple_realmode();
4539c870d5SOlof Johansson #elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
4639c870d5SOlof Johansson 	udbg_init_pas_realmode();
47071df942SAlistair Popple #elif defined(CONFIG_PPC_EARLY_DEBUG_BOOTX)
48719c91ccSDavid Gibson 	udbg_init_btext();
49d9b55a03SDavid Gibson #elif defined(CONFIG_PPC_EARLY_DEBUG_44x)
50d9b55a03SDavid Gibson 	/* PPC44x debug */
51d9b55a03SDavid Gibson 	udbg_init_44x_as1();
529dae8afdSBenjamin Herrenschmidt #elif defined(CONFIG_PPC_EARLY_DEBUG_40x)
539dae8afdSBenjamin Herrenschmidt 	/* PPC40x debug */
549dae8afdSBenjamin Herrenschmidt 	udbg_init_40x_realmode();
55c374e00eSScott Wood #elif defined(CONFIG_PPC_EARLY_DEBUG_CPM)
56c374e00eSScott Wood 	udbg_init_cpm();
57d1d56f8cSAlbert Herranz #elif defined(CONFIG_PPC_EARLY_DEBUG_USBGECKO)
58d1d56f8cSAlbert Herranz 	udbg_init_usbgecko();
5930650239SAlistair Popple #elif defined(CONFIG_PPC_EARLY_DEBUG_MEMCONS)
6030650239SAlistair Popple 	/* In memory console */
6130650239SAlistair Popple 	udbg_init_memcons();
62dcd83aafSTimur Tabi #elif defined(CONFIG_PPC_EARLY_DEBUG_EHV_BC)
63dcd83aafSTimur Tabi 	udbg_init_ehv_bc();
64c26afe9eSHector Martin #elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC)
65c26afe9eSHector Martin 	udbg_init_ps3gelic();
66daea1175SBenjamin Herrenschmidt #elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_RAW)
67daea1175SBenjamin Herrenschmidt 	udbg_init_debug_opal_raw();
68daea1175SBenjamin Herrenschmidt #elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI)
69daea1175SBenjamin Herrenschmidt 	udbg_init_debug_opal_hvsi();
70*b19448feSPali Rohár #elif defined(CONFIG_PPC_EARLY_DEBUG_16550)
71*b19448feSPali Rohár 	udbg_init_debug_16550();
72296167aeSMichael Ellerman #endif
737ee17466SBenjamin Herrenschmidt 
747ee17466SBenjamin Herrenschmidt #ifdef CONFIG_PPC_EARLY_DEBUG
75fae1383bSSergey Senozhatsky 	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
76dd2e356aSBenjamin Herrenschmidt 
77dd2e356aSBenjamin Herrenschmidt 	register_early_udbg_console();
787ee17466SBenjamin Herrenschmidt #endif
79296167aeSMichael Ellerman }
80296167aeSMichael Ellerman 
8135cd8785SDavid Gibson /* udbg library, used by xmon et al */
udbg_puts(const char * s)8235cd8785SDavid Gibson void udbg_puts(const char *s)
8335cd8785SDavid Gibson {
8435cd8785SDavid Gibson 	if (udbg_putc) {
8535cd8785SDavid Gibson 		char c;
8635cd8785SDavid Gibson 
8735cd8785SDavid Gibson 		if (s && *s != '\0') {
8835cd8785SDavid Gibson 			while ((c = *s++) != '\0')
8935cd8785SDavid Gibson 				udbg_putc(c);
9035cd8785SDavid Gibson 		}
91af9c7249SAndrew Klossner 
92af9c7249SAndrew Klossner 		if (udbg_flush)
93af9c7249SAndrew Klossner 			udbg_flush();
9435cd8785SDavid Gibson 	}
9535cd8785SDavid Gibson #if 0
9635cd8785SDavid Gibson 	else {
9735cd8785SDavid Gibson 		printk("%s", s);
9835cd8785SDavid Gibson 	}
9935cd8785SDavid Gibson #endif
10035cd8785SDavid Gibson }
10135cd8785SDavid Gibson 
udbg_write(const char * s,int n)10235cd8785SDavid Gibson int udbg_write(const char *s, int n)
10335cd8785SDavid Gibson {
10435cd8785SDavid Gibson 	int remain = n;
10535cd8785SDavid Gibson 	char c;
10635cd8785SDavid Gibson 
10735cd8785SDavid Gibson 	if (!udbg_putc)
10835cd8785SDavid Gibson 		return 0;
10935cd8785SDavid Gibson 
11035cd8785SDavid Gibson 	if (s && *s != '\0') {
11135cd8785SDavid Gibson 		while (((c = *s++) != '\0') && (remain-- > 0)) {
11235cd8785SDavid Gibson 			udbg_putc(c);
11335cd8785SDavid Gibson 		}
11435cd8785SDavid Gibson 	}
11535cd8785SDavid Gibson 
116af9c7249SAndrew Klossner 	if (udbg_flush)
117af9c7249SAndrew Klossner 		udbg_flush();
118af9c7249SAndrew Klossner 
11935cd8785SDavid Gibson 	return n - remain;
12035cd8785SDavid Gibson }
12135cd8785SDavid Gibson 
12235cd8785SDavid Gibson #define UDBG_BUFSIZE 256
udbg_printf(const char * fmt,...)12335cd8785SDavid Gibson void udbg_printf(const char *fmt, ...)
12435cd8785SDavid Gibson {
125f7a678a8SMichael Ellerman 	if (udbg_putc) {
12651d3082fSBenjamin Herrenschmidt 		char buf[UDBG_BUFSIZE];
12735cd8785SDavid Gibson 		va_list args;
12835cd8785SDavid Gibson 
12935cd8785SDavid Gibson 		va_start(args, fmt);
13035cd8785SDavid Gibson 		vsnprintf(buf, UDBG_BUFSIZE, fmt, args);
13135cd8785SDavid Gibson 		udbg_puts(buf);
13235cd8785SDavid Gibson 		va_end(args);
13335cd8785SDavid Gibson 	}
134f7a678a8SMichael Ellerman }
13535cd8785SDavid Gibson 
udbg_progress(char * s,unsigned short hex)136be6b8439SKumar Gala void __init udbg_progress(char *s, unsigned short hex)
137be6b8439SKumar Gala {
138be6b8439SKumar Gala 	udbg_puts(s);
139be6b8439SKumar Gala 	udbg_puts("\n");
140be6b8439SKumar Gala }
141be6b8439SKumar Gala 
14235cd8785SDavid Gibson /*
14335cd8785SDavid Gibson  * Early boot console based on udbg
14435cd8785SDavid Gibson  */
udbg_console_write(struct console * con,const char * s,unsigned int n)14535cd8785SDavid Gibson static void udbg_console_write(struct console *con, const char *s,
14635cd8785SDavid Gibson 		unsigned int n)
14735cd8785SDavid Gibson {
14835cd8785SDavid Gibson 	udbg_write(s, n);
14935cd8785SDavid Gibson }
15035cd8785SDavid Gibson 
15135cd8785SDavid Gibson static struct console udbg_console = {
15235cd8785SDavid Gibson 	.name	= "udbg",
15335cd8785SDavid Gibson 	.write	= udbg_console_write,
154f336632fSMichael Ellerman 	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
155c7afb4e2SMichael Ellerman 	.index	= 0,
15635cd8785SDavid Gibson };
15735cd8785SDavid Gibson 
158220ddc08SMilton Miller /*
159220ddc08SMilton Miller  * Called by setup_system after ppc_md->probe and ppc_md->early_init.
160220ddc08SMilton Miller  * Call it again after setting udbg_putc in ppc_md->setup_arch.
161220ddc08SMilton Miller  */
register_early_udbg_console(void)162282045b4SKumar Gala void __init register_early_udbg_console(void)
16335cd8785SDavid Gibson {
164d0380e6cSThomas Gleixner 	if (early_console)
16551d3082fSBenjamin Herrenschmidt 		return;
16669331af7SGerd Hoffmann 
167220ddc08SMilton Miller 	if (!udbg_putc)
168220ddc08SMilton Miller 		return;
169220ddc08SMilton Miller 
17069331af7SGerd Hoffmann 	if (strstr(boot_command_line, "udbg-immortal")) {
17169331af7SGerd Hoffmann 		printk(KERN_INFO "early console immortal !\n");
17269331af7SGerd Hoffmann 		udbg_console.flags &= ~CON_BOOT;
17369331af7SGerd Hoffmann 	}
174d0380e6cSThomas Gleixner 	early_console = &udbg_console;
17535cd8785SDavid Gibson 	register_console(&udbg_console);
17635cd8785SDavid Gibson }
17735cd8785SDavid Gibson 
17835cd8785SDavid Gibson #if 0   /* if you want to use this as a regular output console */
17935cd8785SDavid Gibson console_initcall(register_udbg_console);
18035cd8785SDavid Gibson #endif
181