11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 3027c3d34SHelge Deller * PDC early console support - use PDC firmware to dump text via boot console 41da177e4SLinus Torvalds * 5027c3d34SHelge 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> 10027c3d34SHelge Deller #include <linux/serial_core.h> 11027c3d34SHelge 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 151da177e4SLinus Torvalds static void pdc_console_write(struct console *co, const char *s, unsigned count) 161da177e4SLinus Torvalds { 17ef1afd4dSKyle McMartin int i = 0; 18ef1afd4dSKyle McMartin 19ef1afd4dSKyle McMartin do { 20ef1afd4dSKyle McMartin i += pdc_iodc_print(s + i, count - i); 21ef1afd4dSKyle McMartin } while (i < count); 221da177e4SLinus Torvalds } 231da177e4SLinus Torvalds 24027c3d34SHelge Deller #ifdef CONFIG_KGDB 25027c3d34SHelge Deller static int kgdb_pdc_read_char(void) 261da177e4SLinus Torvalds { 27*7dc4dbfeSHelge Deller int c = pdc_iodc_getc(); 28ef1afd4dSKyle McMartin 29027c3d34SHelge Deller return (c <= 0) ? NO_POLL_CHAR : c; 301da177e4SLinus Torvalds } 311da177e4SLinus Torvalds 32027c3d34SHelge Deller static void kgdb_pdc_write_char(u8 chr) 331da177e4SLinus Torvalds { 34*7dc4dbfeSHelge Deller /* no need to print char as it's shown on standard console */ 35*7dc4dbfeSHelge Deller /* pdc_iodc_print(&chr, 1); */ 361da177e4SLinus Torvalds } 371da177e4SLinus Torvalds 38027c3d34SHelge Deller static struct kgdb_io kgdb_pdc_io_ops = { 39027c3d34SHelge Deller .name = "kgdb_pdc", 40027c3d34SHelge Deller .read_char = kgdb_pdc_read_char, 41027c3d34SHelge Deller .write_char = kgdb_pdc_write_char, 42650a35f8SGuy Martin }; 431da177e4SLinus Torvalds #endif 441da177e4SLinus Torvalds 45027c3d34SHelge Deller static int __init pdc_earlycon_setup(struct earlycon_device *device, 46027c3d34SHelge Deller const char *opt) 471da177e4SLinus Torvalds { 48027c3d34SHelge Deller struct console *earlycon_console; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* If the console is duplex then copy the COUT parameters to CIN. */ 511da177e4SLinus Torvalds if (PAGE0->mem_cons.cl_class == CL_DUPLEX) 521da177e4SLinus Torvalds memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons)); 531da177e4SLinus Torvalds 54027c3d34SHelge Deller earlycon_console = device->con; 55027c3d34SHelge Deller earlycon_console->write = pdc_console_write; 56027c3d34SHelge Deller device->port.iotype = UPIO_MEM32BE; 571da177e4SLinus Torvalds 58027c3d34SHelge Deller #ifdef CONFIG_KGDB 59027c3d34SHelge Deller kgdb_register_io_module(&kgdb_pdc_io_ops); 601da177e4SLinus Torvalds #endif 61027c3d34SHelge Deller 62027c3d34SHelge Deller return 0; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 65027c3d34SHelge Deller EARLYCON_DECLARE(pdc, pdc_earlycon_setup); 66