1/*
2 * Early serial console for 8250/16550 devices
3 *
4 * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
5 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
12 * and on early_printk.c by Andi Kleen.
13 *
14 * This is for use before the serial driver has initialized, in
15 * particular, before the UARTs have been discovered and named.
16 * Instead of specifying the console device as, e.g., "ttyS0",
17 * we locate the device directly by its MMIO or I/O port address.
18 *
19 * The user can specify the device directly, e.g.,
20 *	earlycon=uart8250,io,0x3f8,9600n8
21 *	earlycon=uart8250,mmio,0xff5e0000,115200n8
22 *	earlycon=uart8250,mmio32,0xff5e0000,115200n8
23 * or
24 *	console=uart8250,io,0x3f8,9600n8
25 *	console=uart8250,mmio,0xff5e0000,115200n8
26 *	console=uart8250,mmio32,0xff5e0000,115200n8
27 */
28
29#include <linux/tty.h>
30#include <linux/init.h>
31#include <linux/console.h>
32#include <linux/serial_core.h>
33#include <linux/serial_reg.h>
34#include <linux/serial.h>
35#include <linux/serial_8250.h>
36#include <asm/io.h>
37#include <asm/serial.h>
38#ifdef CONFIG_FIX_EARLYCON_MEM
39#include <asm/pgtable.h>
40#include <asm/fixmap.h>
41#endif
42
43struct early_serial8250_device {
44	struct uart_port port;
45	char options[16];		/* e.g., 115200n8 */
46	unsigned int baud;
47};
48
49static struct early_serial8250_device early_device;
50
51static unsigned int __init serial_in(struct uart_port *port, int offset)
52{
53	switch (port->iotype) {
54	case UPIO_MEM:
55		return readb(port->membase + offset);
56	case UPIO_MEM32:
57		return readl(port->membase + (offset << 2));
58	case UPIO_PORT:
59		return inb(port->iobase + offset);
60	default:
61		return 0;
62	}
63}
64
65static void __init serial_out(struct uart_port *port, int offset, int value)
66{
67	switch (port->iotype) {
68	case UPIO_MEM:
69		writeb(value, port->membase + offset);
70		break;
71	case UPIO_MEM32:
72		writel(value, port->membase + (offset << 2));
73		break;
74	case UPIO_PORT:
75		outb(value, port->iobase + offset);
76		break;
77	}
78}
79
80#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
81
82static void __init wait_for_xmitr(struct uart_port *port)
83{
84	unsigned int status;
85
86	for (;;) {
87		status = serial_in(port, UART_LSR);
88		if ((status & BOTH_EMPTY) == BOTH_EMPTY)
89			return;
90		cpu_relax();
91	}
92}
93
94static void __init serial_putc(struct uart_port *port, int c)
95{
96	wait_for_xmitr(port);
97	serial_out(port, UART_TX, c);
98}
99
100static void __init early_serial8250_write(struct console *console,
101					const char *s, unsigned int count)
102{
103	struct uart_port *port = &early_device.port;
104	unsigned int ier;
105
106	/* Save the IER and disable interrupts */
107	ier = serial_in(port, UART_IER);
108	serial_out(port, UART_IER, 0);
109
110	uart_console_write(port, s, count, serial_putc);
111
112	/* Wait for transmitter to become empty and restore the IER */
113	wait_for_xmitr(port);
114	serial_out(port, UART_IER, ier);
115}
116
117static unsigned int __init probe_baud(struct uart_port *port)
118{
119	unsigned char lcr, dll, dlm;
120	unsigned int quot;
121
122	lcr = serial_in(port, UART_LCR);
123	serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
124	dll = serial_in(port, UART_DLL);
125	dlm = serial_in(port, UART_DLM);
126	serial_out(port, UART_LCR, lcr);
127
128	quot = (dlm << 8) | dll;
129	return (port->uartclk / 16) / quot;
130}
131
132static void __init init_port(struct early_serial8250_device *device)
133{
134	struct uart_port *port = &device->port;
135	unsigned int divisor;
136	unsigned char c;
137
138	serial_out(port, UART_LCR, 0x3);	/* 8n1 */
139	serial_out(port, UART_IER, 0);		/* no interrupt */
140	serial_out(port, UART_FCR, 0);		/* no fifo */
141	serial_out(port, UART_MCR, 0x3);	/* DTR + RTS */
142
143	divisor = port->uartclk / (16 * device->baud);
144	c = serial_in(port, UART_LCR);
145	serial_out(port, UART_LCR, c | UART_LCR_DLAB);
146	serial_out(port, UART_DLL, divisor & 0xff);
147	serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
148	serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
149}
150
151static int __init parse_options(struct early_serial8250_device *device,
152								char *options)
153{
154	struct uart_port *port = &device->port;
155	int mmio, mmio32, length;
156
157	if (!options)
158		return -ENODEV;
159
160	port->uartclk = BASE_BAUD * 16;
161
162	mmio = !strncmp(options, "mmio,", 5);
163	mmio32 = !strncmp(options, "mmio32,", 7);
164	if (mmio || mmio32) {
165		port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
166		port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
167					       &options, 0);
168		if (mmio32)
169			port->regshift = 2;
170#ifdef CONFIG_FIX_EARLYCON_MEM
171		set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
172					port->mapbase & PAGE_MASK);
173		port->membase =
174			(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
175		port->membase += port->mapbase & ~PAGE_MASK;
176#else
177		port->membase = ioremap_nocache(port->mapbase, 64);
178		if (!port->membase) {
179			printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
180				__func__,
181			       (unsigned long long) port->mapbase);
182			return -ENOMEM;
183		}
184#endif
185	} else if (!strncmp(options, "io,", 3)) {
186		port->iotype = UPIO_PORT;
187		port->iobase = simple_strtoul(options + 3, &options, 0);
188		mmio = 0;
189	} else
190		return -EINVAL;
191
192	options = strchr(options, ',');
193	if (options) {
194		options++;
195		device->baud = simple_strtoul(options, NULL, 0);
196		length = min(strcspn(options, " "), sizeof(device->options));
197		strncpy(device->options, options, length);
198	} else {
199		device->baud = probe_baud(port);
200		snprintf(device->options, sizeof(device->options), "%u",
201			device->baud);
202	}
203
204	if (mmio || mmio32)
205		printk(KERN_INFO
206		       "Early serial console at MMIO%s 0x%llx (options '%s')\n",
207			mmio32 ? "32" : "",
208			(unsigned long long)port->mapbase,
209			device->options);
210	else
211		printk(KERN_INFO
212		      "Early serial console at I/O port 0x%lx (options '%s')\n",
213			port->iobase,
214			device->options);
215
216	return 0;
217}
218
219static struct console early_serial8250_console __initdata = {
220	.name	= "uart",
221	.write	= early_serial8250_write,
222	.flags	= CON_PRINTBUFFER | CON_BOOT,
223	.index	= -1,
224};
225
226static int __init early_serial8250_setup(char *options)
227{
228	struct early_serial8250_device *device = &early_device;
229	int err;
230
231	if (device->port.membase || device->port.iobase)
232		return 0;
233
234	err = parse_options(device, options);
235	if (err < 0)
236		return err;
237
238	init_port(device);
239	return 0;
240}
241
242int __init setup_early_serial8250_console(char *cmdline)
243{
244	char *options;
245	int err;
246
247	options = strstr(cmdline, "uart8250,");
248	if (!options) {
249		options = strstr(cmdline, "uart,");
250		if (!options)
251			return 0;
252	}
253
254	options = strchr(cmdline, ',') + 1;
255	err = early_serial8250_setup(options);
256	if (err < 0)
257		return err;
258
259	register_console(&early_serial8250_console);
260
261	return 0;
262}
263
264int serial8250_find_port_for_earlycon(void)
265{
266	struct early_serial8250_device *device = &early_device;
267	struct uart_port *port = &device->port;
268	int line;
269	int ret;
270
271	if (!device->port.membase && !device->port.iobase)
272		return -ENODEV;
273
274	line = serial8250_find_port(port);
275	if (line < 0)
276		return -ENODEV;
277
278	ret = update_console_cmdline("uart", 8250,
279			     "ttyS", line, device->options);
280	if (ret < 0)
281		ret = update_console_cmdline("uart", 0,
282				     "ttyS", line, device->options);
283
284	return ret;
285}
286
287early_param("earlycon", setup_early_serial8250_console);
288