Line data Source code
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 <[email protected]>
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 0 : static unsigned int serial8250_early_in(struct uart_port *port, int offset)
37 : {
38 0 : offset <<= port->regshift;
39 :
40 0 : switch (port->iotype) {
41 : case UPIO_MEM:
42 0 : return readb(port->membase + offset);
43 : case UPIO_MEM16:
44 0 : return readw(port->membase + offset);
45 : case UPIO_MEM32:
46 0 : return readl(port->membase + offset);
47 : case UPIO_MEM32BE:
48 0 : return ioread32be(port->membase + offset);
49 : #ifdef CONFIG_HAS_IOPORT
50 : case UPIO_PORT:
51 0 : return inb(port->iobase + offset);
52 : #endif
53 : default:
54 0 : return 0;
55 : }
56 0 : }
57 :
58 0 : static void serial8250_early_out(struct uart_port *port, int offset, int value)
59 : {
60 0 : offset <<= port->regshift;
61 :
62 0 : switch (port->iotype) {
63 : case UPIO_MEM:
64 0 : writeb(value, port->membase + offset);
65 0 : break;
66 : case UPIO_MEM16:
67 0 : writew(value, port->membase + offset);
68 0 : break;
69 : case UPIO_MEM32:
70 0 : writel(value, port->membase + offset);
71 0 : break;
72 : case UPIO_MEM32BE:
73 0 : iowrite32be(value, port->membase + offset);
74 0 : break;
75 : #ifdef CONFIG_HAS_IOPORT
76 : case UPIO_PORT:
77 0 : outb(value, port->iobase + offset);
78 0 : break;
79 : #endif
80 : default:
81 0 : break;
82 : }
83 0 : }
84 :
85 0 : static void serial_putc(struct uart_port *port, unsigned char c)
86 : {
87 0 : unsigned int status;
88 :
89 0 : serial8250_early_out(port, UART_TX, c);
90 :
91 0 : for (;;) {
92 0 : status = serial8250_early_in(port, UART_LSR);
93 0 : if (uart_lsr_tx_empty(status))
94 0 : break;
95 0 : cpu_relax();
96 : }
97 0 : }
98 :
99 0 : static void early_serial8250_write(struct console *console,
100 : const char *s, unsigned int count)
101 : {
102 0 : struct earlycon_device *device = console->data;
103 0 : struct uart_port *port = &device->port;
104 :
105 0 : uart_console_write(port, s, count, serial_putc);
106 0 : }
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 0 : static void __init init_port(struct earlycon_device *device)
131 : {
132 0 : struct uart_port *port = &device->port;
133 0 : unsigned int divisor;
134 0 : unsigned char c;
135 0 : unsigned int ier;
136 :
137 0 : serial8250_early_out(port, UART_LCR, UART_LCR_WLEN8); /* 8n1 */
138 0 : ier = serial8250_early_in(port, UART_IER);
139 0 : serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
140 0 : serial8250_early_out(port, UART_FCR, 0); /* no fifo */
141 0 : serial8250_early_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
142 :
143 0 : if (port->uartclk) {
144 0 : divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
145 0 : c = serial8250_early_in(port, UART_LCR);
146 0 : serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);
147 0 : serial8250_early_out(port, UART_DLL, divisor & 0xff);
148 0 : serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff);
149 0 : serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
150 0 : }
151 0 : }
152 :
153 0 : int __init early_serial8250_setup(struct earlycon_device *device,
154 : const char *options)
155 : {
156 0 : if (!(device->port.membase || device->port.iobase))
157 0 : return -ENODEV;
158 :
159 0 : if (!device->baud) {
160 0 : struct uart_port *port = &device->port;
161 0 : unsigned int ier;
162 :
163 : /* assume the device was initialized, only mask interrupts */
164 0 : ier = serial8250_early_in(port, UART_IER);
165 0 : serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
166 0 : } else
167 0 : init_port(device);
168 :
169 0 : device->con->write = early_serial8250_write;
170 0 : device->con->read = early_serial8250_read;
171 0 : return 0;
172 0 : }
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 0 : static int __init early_serial8250_rs2_setup(struct earlycon_device *device,
181 : const char *options)
182 : {
183 0 : device->port.regshift = 2;
184 :
185 0 : 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
|