1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Early serial console for 8250/16550 devices 4 * 5 * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. 6 * Bjorn Helgaas <bjorn.helgaas@hp.com> 7 * 8 * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King, 9 * and on early_printk.c by Andi Kleen. 10 * 11 * This is for use before the serial driver has initialized, in 12 * particular, before the UARTs have been discovered and named. 13 * Instead of specifying the console device as, e.g., "ttyS0", 14 * we locate the device directly by its MMIO or I/O port address. 15 * 16 * The user can specify the device directly, e.g., 17 * earlycon=uart8250,io,0x3f8,9600n8 18 * earlycon=uart8250,mmio,0xff5e0000,115200n8 19 * earlycon=uart8250,mmio32,0xff5e0000,115200n8 20 * or 21 * console=uart8250,io,0x3f8,9600n8 22 * console=uart8250,mmio,0xff5e0000,115200n8 23 * console=uart8250,mmio32,0xff5e0000,115200n8 24 */ 25 26 #include <linux/tty.h> 27 #include <linux/init.h> 28 #include <linux/console.h> 29 #include <linux/of.h> 30 #include <linux/serial_reg.h> 31 #include <linux/serial.h> 32 #include <linux/serial_8250.h> 33 #include <asm/io.h> 34 #include <asm/serial.h> 35 36 static unsigned int serial8250_early_in(struct uart_port *port, int offset) 37 { 38 offset <<= port->regshift; 39 40 switch (port->iotype) { 41 case UPIO_MEM: 42 return readb(port->membase + offset); 43 case UPIO_MEM16: 44 return readw(port->membase + offset); 45 case UPIO_MEM32: 46 return readl(port->membase + offset); 47 case UPIO_MEM32BE: 48 return ioread32be(port->membase + offset); 49 case UPIO_PORT: 50 return inb(port->iobase + offset); 51 default: 52 return 0; 53 } 54 } 55 56 static void serial8250_early_out(struct uart_port *port, int offset, int value) 57 { 58 offset <<= port->regshift; 59 60 switch (port->iotype) { 61 case UPIO_MEM: 62 writeb(value, port->membase + offset); 63 break; 64 case UPIO_MEM16: 65 writew(value, port->membase + offset); 66 break; 67 case UPIO_MEM32: 68 writel(value, port->membase + offset); 69 break; 70 case UPIO_MEM32BE: 71 iowrite32be(value, port->membase + offset); 72 break; 73 case UPIO_PORT: 74 outb(value, port->iobase + offset); 75 break; 76 } 77 } 78 79 static void serial_putc(struct uart_port *port, unsigned char c) 80 { 81 unsigned int status; 82 83 serial8250_early_out(port, UART_TX, c); 84 85 for (;;) { 86 status = serial8250_early_in(port, UART_LSR); 87 if (uart_lsr_tx_empty(status)) 88 break; 89 cpu_relax(); 90 } 91 } 92 93 static void early_serial8250_write(struct console *console, 94 const char *s, unsigned int count) 95 { 96 struct earlycon_device *device = console->data; 97 struct uart_port *port = &device->port; 98 99 uart_console_write(port, s, count, serial_putc); 100 } 101 102 #ifdef CONFIG_CONSOLE_POLL 103 static int early_serial8250_read(struct console *console, 104 char *s, unsigned int count) 105 { 106 struct earlycon_device *device = console->data; 107 struct uart_port *port = &device->port; 108 unsigned int status; 109 int num_read = 0; 110 111 while (num_read < count) { 112 status = serial8250_early_in(port, UART_LSR); 113 if (!(status & UART_LSR_DR)) 114 break; 115 s[num_read++] = serial8250_early_in(port, UART_RX); 116 } 117 118 return num_read; 119 } 120 #else 121 #define early_serial8250_read NULL 122 #endif 123 124 static void __init init_port(struct earlycon_device *device) 125 { 126 struct uart_port *port = &device->port; 127 unsigned int divisor; 128 unsigned char c; 129 unsigned int ier; 130 131 serial8250_early_out(port, UART_LCR, UART_LCR_WLEN8); /* 8n1 */ 132 ier = serial8250_early_in(port, UART_IER); 133 serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */ 134 serial8250_early_out(port, UART_FCR, 0); /* no fifo */ 135 serial8250_early_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); 136 137 if (port->uartclk) { 138 divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); 139 c = serial8250_early_in(port, UART_LCR); 140 serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); 141 serial8250_early_out(port, UART_DLL, divisor & 0xff); 142 serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff); 143 serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); 144 } 145 } 146 147 int __init early_serial8250_setup(struct earlycon_device *device, 148 const char *options) 149 { 150 if (!(device->port.membase || device->port.iobase)) 151 return -ENODEV; 152 153 if (!device->baud) { 154 struct uart_port *port = &device->port; 155 unsigned int ier; 156 157 /* assume the device was initialized, only mask interrupts */ 158 ier = serial8250_early_in(port, UART_IER); 159 serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); 160 } else 161 init_port(device); 162 163 device->con->write = early_serial8250_write; 164 device->con->read = early_serial8250_read; 165 return 0; 166 } 167 EARLYCON_DECLARE(uart8250, early_serial8250_setup); 168 EARLYCON_DECLARE(uart, early_serial8250_setup); 169 OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup); 170 OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); 171 OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); 172 OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup); 173 174 static int __init early_serial8250_rs2_setup(struct earlycon_device *device, 175 const char *options) 176 { 177 device->port.regshift = 2; 178 179 return early_serial8250_setup(device, options); 180 } 181 OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup); 182 OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup); 183 OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup); 184 185 #ifdef CONFIG_SERIAL_8250_OMAP 186 187 static int __init early_omap8250_setup(struct earlycon_device *device, 188 const char *options) 189 { 190 struct uart_port *port = &device->port; 191 192 if (!(device->port.membase || device->port.iobase)) 193 return -ENODEV; 194 195 port->regshift = 2; 196 device->con->write = early_serial8250_write; 197 return 0; 198 } 199 200 OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup); 201 OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup); 202 OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup); 203 OF_EARLYCON_DECLARE(omap8250, "ti,am654-uart", early_omap8250_setup); 204 205 #endif 206