xref: /openbmc/linux/arch/parisc/kernel/pdc_cons.c (revision 027c3d34)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3*027c3d34SHelge Deller  *    PDC early console support - use PDC firmware to dump text via boot console
41da177e4SLinus Torvalds  *
5*027c3d34SHelge Deller  *    Copyright (C) 2001-2022 Helge Deller <deller@gmx.de>
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/console.h>
91da177e4SLinus Torvalds #include <linux/init.h>
10*027c3d34SHelge Deller #include <linux/serial_core.h>
11*027c3d34SHelge Deller #include <linux/kgdb.h>
124a8a0788SRolf Eike Beer #include <asm/page.h>		/* for PAGE0 */
131da177e4SLinus Torvalds #include <asm/pdc.h>		/* for iodc_call() proto and friends */
141da177e4SLinus Torvalds 
15aefa8b6bSJulia Lawall static DEFINE_SPINLOCK(pdc_console_lock);
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds static void pdc_console_write(struct console *co, const char *s, unsigned count)
181da177e4SLinus Torvalds {
19ef1afd4dSKyle McMartin 	int i = 0;
20ef1afd4dSKyle McMartin 	unsigned long flags;
21ef1afd4dSKyle McMartin 
22ef1afd4dSKyle McMartin 	spin_lock_irqsave(&pdc_console_lock, flags);
23ef1afd4dSKyle McMartin 	do {
24ef1afd4dSKyle McMartin 		i += pdc_iodc_print(s + i, count - i);
25ef1afd4dSKyle McMartin 	} while (i < count);
26ef1afd4dSKyle McMartin 	spin_unlock_irqrestore(&pdc_console_lock, flags);
271da177e4SLinus Torvalds }
281da177e4SLinus Torvalds 
29*027c3d34SHelge Deller #ifdef CONFIG_KGDB
30*027c3d34SHelge Deller static int kgdb_pdc_read_char(void)
311da177e4SLinus Torvalds {
32ef1afd4dSKyle McMartin 	int c;
33ef1afd4dSKyle McMartin 	unsigned long flags;
34ef1afd4dSKyle McMartin 
35ef1afd4dSKyle McMartin 	spin_lock_irqsave(&pdc_console_lock, flags);
36ef1afd4dSKyle McMartin 	c = pdc_iodc_getc();
37ef1afd4dSKyle McMartin 	spin_unlock_irqrestore(&pdc_console_lock, flags);
38ef1afd4dSKyle McMartin 
39*027c3d34SHelge Deller 	return (c <= 0) ? NO_POLL_CHAR : c;
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds 
42*027c3d34SHelge Deller static void kgdb_pdc_write_char(u8 chr)
431da177e4SLinus Torvalds {
44*027c3d34SHelge Deller 	if (PAGE0->mem_cons.cl_class != CL_DUPLEX)
45*027c3d34SHelge Deller 		pdc_console_write(NULL, &chr, 1);
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds 
48*027c3d34SHelge Deller static struct kgdb_io kgdb_pdc_io_ops = {
49*027c3d34SHelge Deller 	.name = "kgdb_pdc",
50*027c3d34SHelge Deller 	.read_char = kgdb_pdc_read_char,
51*027c3d34SHelge Deller 	.write_char = kgdb_pdc_write_char,
52650a35f8SGuy Martin };
531da177e4SLinus Torvalds #endif
541da177e4SLinus Torvalds 
55*027c3d34SHelge Deller static int __init pdc_earlycon_setup(struct earlycon_device *device,
56*027c3d34SHelge Deller 				     const char *opt)
571da177e4SLinus Torvalds {
58*027c3d34SHelge Deller 	struct console *earlycon_console;
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	/* If the console is duplex then copy the COUT parameters to CIN. */
611da177e4SLinus Torvalds 	if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
621da177e4SLinus Torvalds 		memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
631da177e4SLinus Torvalds 
64*027c3d34SHelge Deller 	earlycon_console = device->con;
65*027c3d34SHelge Deller 	earlycon_console->write = pdc_console_write;
66*027c3d34SHelge Deller 	device->port.iotype = UPIO_MEM32BE;
671da177e4SLinus Torvalds 
68*027c3d34SHelge Deller #ifdef CONFIG_KGDB
69*027c3d34SHelge Deller 	kgdb_register_io_module(&kgdb_pdc_io_ops);
701da177e4SLinus Torvalds #endif
71*027c3d34SHelge Deller 
72*027c3d34SHelge Deller 	return 0;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
75*027c3d34SHelge Deller EARLYCON_DECLARE(pdc, pdc_earlycon_setup);
76