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 #ifdef CONFIG_HAS_IOPORT 50 case UPIO_PORT: 51 return inb(port->iobase + offset); 52 #endif 53 default: 54 return 0; 55 } 56 } 57 58 static void serial8250_early_out(struct uart_port *port, int offset, int value) 59 { 60 offset <<= port->regshift; 61 62 switch (port->iotype) { 63 case UPIO_MEM: 64 writeb(value, port->membase + offset); 65 break; 66 case UPIO_MEM16: 67 writew(value, port->membase + offset); 68 break; 69 case UPIO_MEM32: 70 writel(value, port->membase + offset); 71 break; 72 case UPIO_MEM32BE: 73 iowrite32be(value, port->membase + offset); 74 break; 75 #ifdef CONFIG_HAS_IOPORT 76 case UPIO_PORT: 77 outb(value, port->iobase + offset); 78 break; 79 #endif 80 default: 81 break; 82 } 83 } 84 85 static void serial_putc(struct uart_port *port, unsigned char c) 86 { 87 unsigned int status; 88 89 serial8250_early_out(port, UART_TX, c); 90 91 for (;;) { 92 status = serial8250_early_in(port, UART_LSR); 93 if (uart_lsr_tx_empty(status)) 94 break; 95 cpu_relax(); 96 } 97 } 98 99 static void early_serial8250_write(struct console *console, 100 const char *s, unsigned int count) 101 { 102 struct earlycon_device *device = console->data; 103 struct uart_port *port = &device->port; 104 105 uart_console_write(port, s, count, serial_putc); 106 } 107 108 #ifdef CONFIG_CONSOLE_POLL 109 static int early_serial8250_read(struct console *console, 110 char *s, unsigned int count) 111 { 112 struct earlycon_device *device = console->data; 113 struct uart_port *port = &device->port; 114 unsigned int status; 115 int num_read = 0; 116 117 while (num_read < count) { 118 status = serial8250_early_in(port, UART_LSR); 119 if (!(status & UART_LSR_DR)) 120 break; 121 s[num_read++] = serial8250_early_in(port, UART_RX); 122 } 123 124 return num_read; 125 } 126 #else 127 #define early_serial8250_read NULL 128 #endif 129 130 static void __init init_port(struct earlycon_device *device) 131 { 132 struct uart_port *port = &device->port; 133 unsigned int divisor; 134 unsigned char c; 135 unsigned int ier; 136 137 serial8250_early_out(port, UART_LCR, UART_LCR_WLEN8); /* 8n1 */ 138 ier = serial8250_early_in(port, UART_IER); 139 serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */ 140 serial8250_early_out(port, UART_FCR, 0); /* no fifo */ 141 serial8250_early_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); 142 143 if (port->uartclk) { 144 divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); 145 c = serial8250_early_in(port, UART_LCR); 146 serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); 147 serial8250_early_out(port, UART_DLL, divisor & 0xff); 148 serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff); 149 serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); 150 } 151 } 152 153 int __init early_serial8250_setup(struct earlycon_device *device, 154 const char *options) 155 { 156 if (!(device->port.membase || device->port.iobase)) 157 return -ENODEV; 158 159 if (!device->baud) { 160 struct uart_port *port = &device->port; 161 unsigned int ier; 162 163 /* assume the device was initialized, only mask interrupts */ 164 ier = serial8250_early_in(port, UART_IER); 165 serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); 166 } else 167 init_port(device); 168 169 device->con->write = early_serial8250_write; 170 device->con->read = early_serial8250_read; 171 return 0; 172 } 173 EARLYCON_DECLARE(uart8250, early_serial8250_setup); 174 EARLYCON_DECLARE(uart, early_serial8250_setup); 175 OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup); 176 OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); 177 OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); 178 OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup); 179 180 static int __init early_serial8250_rs2_setup(struct earlycon_device *device, 181 const char *options) 182 { 183 device->port.regshift = 2; 184 185 return early_serial8250_setup(device, options); 186 } 187 OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup); 188 OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup); 189 OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup); 190 191 #ifdef CONFIG_SERIAL_8250_OMAP 192 193 static int __init early_omap8250_setup(struct earlycon_device *device, 194 const char *options) 195 { 196 struct uart_port *port = &device->port; 197 198 if (!(device->port.membase || device->port.iobase)) 199 return -ENODEV; 200 201 port->regshift = 2; 202 device->con->write = early_serial8250_write; 203 return 0; 204 } 205 206 OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup); 207 OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup); 208 OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup); 209 OF_EARLYCON_DECLARE(omap8250, "ti,am654-uart", early_omap8250_setup); 210 211 #endif 212