162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * polling mode stateless debugging stuff, originally for NS16550 Serial Ports
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * c 2001 PPC 64 Team, IBM Corp
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/stdarg.h>
962306a36Sopenharmony_ci#include <linux/types.h>
1062306a36Sopenharmony_ci#include <linux/sched.h>
1162306a36Sopenharmony_ci#include <linux/console.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <asm/processor.h>
1462306a36Sopenharmony_ci#include <asm/udbg.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_civoid (*udbg_putc)(char c);
1762306a36Sopenharmony_civoid (*udbg_flush)(void);
1862306a36Sopenharmony_ciint (*udbg_getc)(void);
1962306a36Sopenharmony_ciint (*udbg_getc_poll)(void);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * Early debugging facilities. You can enable _one_ of these via .config,
2362306a36Sopenharmony_ci * if you do so your kernel _will not boot_ on anything else. Be careful.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_civoid __init udbg_early_init(void)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci#if defined(CONFIG_PPC_EARLY_DEBUG_LPAR)
2862306a36Sopenharmony_ci	/* For LPAR machines that have an HVC console on vterm 0 */
2962306a36Sopenharmony_ci	udbg_init_debug_lpar();
3062306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_LPAR_HVSI)
3162306a36Sopenharmony_ci	/* For LPAR machines that have an HVSI console on vterm 0 */
3262306a36Sopenharmony_ci	udbg_init_debug_lpar_hvsi();
3362306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_G5)
3462306a36Sopenharmony_ci	/* For use on Apple G5 machines */
3562306a36Sopenharmony_ci	udbg_init_pmac_realmode();
3662306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL)
3762306a36Sopenharmony_ci	/* RTAS panel debug */
3862306a36Sopenharmony_ci	udbg_init_rtas_panel();
3962306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE)
4062306a36Sopenharmony_ci	/* RTAS console debug */
4162306a36Sopenharmony_ci	udbg_init_rtas_console();
4262306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
4362306a36Sopenharmony_ci	/* Maple real mode debug */
4462306a36Sopenharmony_ci	udbg_init_maple_realmode();
4562306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
4662306a36Sopenharmony_ci	udbg_init_pas_realmode();
4762306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_BOOTX)
4862306a36Sopenharmony_ci	udbg_init_btext();
4962306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_44x)
5062306a36Sopenharmony_ci	/* PPC44x debug */
5162306a36Sopenharmony_ci	udbg_init_44x_as1();
5262306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_40x)
5362306a36Sopenharmony_ci	/* PPC40x debug */
5462306a36Sopenharmony_ci	udbg_init_40x_realmode();
5562306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_CPM)
5662306a36Sopenharmony_ci	udbg_init_cpm();
5762306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_USBGECKO)
5862306a36Sopenharmony_ci	udbg_init_usbgecko();
5962306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_MEMCONS)
6062306a36Sopenharmony_ci	/* In memory console */
6162306a36Sopenharmony_ci	udbg_init_memcons();
6262306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_EHV_BC)
6362306a36Sopenharmony_ci	udbg_init_ehv_bc();
6462306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC)
6562306a36Sopenharmony_ci	udbg_init_ps3gelic();
6662306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_RAW)
6762306a36Sopenharmony_ci	udbg_init_debug_opal_raw();
6862306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI)
6962306a36Sopenharmony_ci	udbg_init_debug_opal_hvsi();
7062306a36Sopenharmony_ci#elif defined(CONFIG_PPC_EARLY_DEBUG_16550)
7162306a36Sopenharmony_ci	udbg_init_debug_16550();
7262306a36Sopenharmony_ci#endif
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#ifdef CONFIG_PPC_EARLY_DEBUG
7562306a36Sopenharmony_ci	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	register_early_udbg_console();
7862306a36Sopenharmony_ci#endif
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* udbg library, used by xmon et al */
8262306a36Sopenharmony_civoid udbg_puts(const char *s)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	if (udbg_putc) {
8562306a36Sopenharmony_ci		char c;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		if (s && *s != '\0') {
8862306a36Sopenharmony_ci			while ((c = *s++) != '\0')
8962306a36Sopenharmony_ci				udbg_putc(c);
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		if (udbg_flush)
9362306a36Sopenharmony_ci			udbg_flush();
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci#if 0
9662306a36Sopenharmony_ci	else {
9762306a36Sopenharmony_ci		printk("%s", s);
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci#endif
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciint udbg_write(const char *s, int n)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	int remain = n;
10562306a36Sopenharmony_ci	char c;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (!udbg_putc)
10862306a36Sopenharmony_ci		return 0;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (s && *s != '\0') {
11162306a36Sopenharmony_ci		while (((c = *s++) != '\0') && (remain-- > 0)) {
11262306a36Sopenharmony_ci			udbg_putc(c);
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (udbg_flush)
11762306a36Sopenharmony_ci		udbg_flush();
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return n - remain;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define UDBG_BUFSIZE 256
12362306a36Sopenharmony_civoid udbg_printf(const char *fmt, ...)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	if (udbg_putc) {
12662306a36Sopenharmony_ci		char buf[UDBG_BUFSIZE];
12762306a36Sopenharmony_ci		va_list args;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		va_start(args, fmt);
13062306a36Sopenharmony_ci		vsnprintf(buf, UDBG_BUFSIZE, fmt, args);
13162306a36Sopenharmony_ci		udbg_puts(buf);
13262306a36Sopenharmony_ci		va_end(args);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_civoid __init udbg_progress(char *s, unsigned short hex)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	udbg_puts(s);
13962306a36Sopenharmony_ci	udbg_puts("\n");
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/*
14362306a36Sopenharmony_ci * Early boot console based on udbg
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_cistatic void udbg_console_write(struct console *con, const char *s,
14662306a36Sopenharmony_ci		unsigned int n)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	udbg_write(s, n);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic struct console udbg_console = {
15262306a36Sopenharmony_ci	.name	= "udbg",
15362306a36Sopenharmony_ci	.write	= udbg_console_write,
15462306a36Sopenharmony_ci	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
15562306a36Sopenharmony_ci	.index	= 0,
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/*
15962306a36Sopenharmony_ci * Called by setup_system after ppc_md->probe and ppc_md->early_init.
16062306a36Sopenharmony_ci * Call it again after setting udbg_putc in ppc_md->setup_arch.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_civoid __init register_early_udbg_console(void)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	if (early_console)
16562306a36Sopenharmony_ci		return;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (!udbg_putc)
16862306a36Sopenharmony_ci		return;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (strstr(boot_command_line, "udbg-immortal")) {
17162306a36Sopenharmony_ci		printk(KERN_INFO "early console immortal !\n");
17262306a36Sopenharmony_ci		udbg_console.flags &= ~CON_BOOT;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	early_console = &udbg_console;
17562306a36Sopenharmony_ci	register_console(&udbg_console);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#if 0   /* if you want to use this as a regular output console */
17962306a36Sopenharmony_ciconsole_initcall(register_udbg_console);
18062306a36Sopenharmony_ci#endif
181