aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/8250_early.c
diff options
context:
space:
mode:
authorYinghai Lu <Yinghai.Lu@Sun.COM>2007-07-16 02:37:59 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:35 -0400
commit18a8bd949d6adb311ea816125ff65050df1f3f6e (patch)
tree4365db908430747a5c08cacdb4354577b7bfead7 /drivers/serial/8250_early.c
parentb1c931e39327ef121797927d4b3198d370e75b9b (diff)
serial: convert early_uart to earlycon for 8250
Beacuse SERIAL_PORT_DFNS is removed from include/asm-i386/serial.h and include/asm-x86_64/serial.h. the serial8250_ports need to be probed late in serial initializing stage. the console_init=>serial8250_console_init=> register_console=>serial8250_console_setup will return -ENDEV, and console ttyS0 can not be enabled at that time. need to wait till uart_add_one_port in drivers/serial/serial_core.c to call register_console to get console ttyS0. that is too late. Make early_uart to use early_param, so uart console can be used earlier. Make it to be bootconsole with CON_BOOT flag, so can use console handover feature. and it will switch to corresponding normal serial console automatically. new command line will be: console=uart8250,io,0x3f8,9600n8 console=uart8250,mmio,0xff5e0000,115200n8 or earlycon=uart8250,io,0x3f8,9600n8 earlycon=uart8250,mmio,0xff5e0000,115200n8 it will print in very early stage: Early serial console at I/O port 0x3f8 (options '9600n8') console [uart0] enabled later for console it will print: console handover: boot [uart0] -> real [ttyS0] Signed-off-by: <yinghai.lu@sun.com> Cc: Andi Kleen <ak@suse.de> Cc: Bjorn Helgaas <bjorn.helgaas@hp.com> Cc: Russell King <rmk@arm.linux.org.uk> Cc: Gerd Hoffmann <kraxel@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/serial/8250_early.c')
-rw-r--r--drivers/serial/8250_early.c117
1 files changed, 59 insertions, 58 deletions
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 7e511199b4c..947c20507e1 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -17,13 +17,11 @@
17 * we locate the device directly by its MMIO or I/O port address. 17 * we locate the device directly by its MMIO or I/O port address.
18 * 18 *
19 * The user can specify the device directly, e.g., 19 * The user can specify the device directly, e.g.,
20 * console=uart,io,0x3f8,9600n8 20 * earlycon=uart8250,io,0x3f8,9600n8
21 * console=uart,mmio,0xff5e0000,115200n8 21 * earlycon=uart8250,mmio,0xff5e0000,115200n8
22 * or platform code can call early_uart_console_init() to set 22 * or
23 * the early UART device. 23 * console=uart8250,io,0x3f8,9600n8
24 * 24 * console=uart8250,mmio,0xff5e0000,115200n8
25 * After the normal serial driver starts, we try to locate the
26 * matching ttyS device and start a console there.
27 */ 25 */
28 26
29#include <linux/tty.h> 27#include <linux/tty.h>
@@ -32,17 +30,21 @@
32#include <linux/serial_core.h> 30#include <linux/serial_core.h>
33#include <linux/serial_reg.h> 31#include <linux/serial_reg.h>
34#include <linux/serial.h> 32#include <linux/serial.h>
33#include <linux/serial_8250.h>
35#include <asm/io.h> 34#include <asm/io.h>
36#include <asm/serial.h> 35#include <asm/serial.h>
36#ifdef CONFIG_FIX_EARLYCON_MEM
37#include <asm/pgtable.h>
38#include <asm/fixmap.h>
39#endif
37 40
38struct early_uart_device { 41struct early_serial8250_device {
39 struct uart_port port; 42 struct uart_port port;
40 char options[16]; /* e.g., 115200n8 */ 43 char options[16]; /* e.g., 115200n8 */
41 unsigned int baud; 44 unsigned int baud;
42}; 45};
43 46
44static struct early_uart_device early_device __initdata; 47static struct early_serial8250_device early_device;
45static int early_uart_registered __initdata;
46 48
47static unsigned int __init serial_in(struct uart_port *port, int offset) 49static unsigned int __init serial_in(struct uart_port *port, int offset)
48{ 50{
@@ -80,7 +82,7 @@ static void __init putc(struct uart_port *port, int c)
80 serial_out(port, UART_TX, c); 82 serial_out(port, UART_TX, c);
81} 83}
82 84
83static void __init early_uart_write(struct console *console, const char *s, unsigned int count) 85static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count)
84{ 86{
85 struct uart_port *port = &early_device.port; 87 struct uart_port *port = &early_device.port;
86 unsigned int ier; 88 unsigned int ier;
@@ -111,7 +113,7 @@ static unsigned int __init probe_baud(struct uart_port *port)
111 return (port->uartclk / 16) / quot; 113 return (port->uartclk / 16) / quot;
112} 114}
113 115
114static void __init init_port(struct early_uart_device *device) 116static void __init init_port(struct early_serial8250_device *device)
115{ 117{
116 struct uart_port *port = &device->port; 118 struct uart_port *port = &device->port;
117 unsigned int divisor; 119 unsigned int divisor;
@@ -130,10 +132,9 @@ static void __init init_port(struct early_uart_device *device)
130 serial_out(port, UART_LCR, c & ~UART_LCR_DLAB); 132 serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
131} 133}
132 134
133static int __init parse_options(struct early_uart_device *device, char *options) 135static int __init parse_options(struct early_serial8250_device *device, char *options)
134{ 136{
135 struct uart_port *port = &device->port; 137 struct uart_port *port = &device->port;
136 int mapsize = 64;
137 int mmio, length; 138 int mmio, length;
138 139
139 if (!options) 140 if (!options)
@@ -143,12 +144,18 @@ static int __init parse_options(struct early_uart_device *device, char *options)
143 if (!strncmp(options, "mmio,", 5)) { 144 if (!strncmp(options, "mmio,", 5)) {
144 port->iotype = UPIO_MEM; 145 port->iotype = UPIO_MEM;
145 port->mapbase = simple_strtoul(options + 5, &options, 0); 146 port->mapbase = simple_strtoul(options + 5, &options, 0);
146 port->membase = ioremap(port->mapbase, mapsize); 147#ifdef CONFIG_FIX_EARLYCON_MEM
148 set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, port->mapbase & PAGE_MASK);
149 port->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
150 port->membase += port->mapbase & ~PAGE_MASK;
151#else
152 port->membase = ioremap(port->mapbase, 64);
147 if (!port->membase) { 153 if (!port->membase) {
148 printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n", 154 printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
149 __FUNCTION__, port->mapbase); 155 __FUNCTION__, port->mapbase);
150 return -ENOMEM; 156 return -ENOMEM;
151 } 157 }
158#endif
152 mmio = 1; 159 mmio = 1;
153 } else if (!strncmp(options, "io,", 3)) { 160 } else if (!strncmp(options, "io,", 3)) {
154 port->iotype = UPIO_PORT; 161 port->iotype = UPIO_PORT;
@@ -175,9 +182,16 @@ static int __init parse_options(struct early_uart_device *device, char *options)
175 return 0; 182 return 0;
176} 183}
177 184
178static int __init early_uart_setup(struct console *console, char *options) 185static struct console early_serial8250_console __initdata = {
186 .name = "uart",
187 .write = early_serial8250_write,
188 .flags = CON_PRINTBUFFER | CON_BOOT,
189 .index = -1,
190};
191
192static int __init early_serial8250_setup(char *options)
179{ 193{
180 struct early_uart_device *device = &early_device; 194 struct early_serial8250_device *device = &early_device;
181 int err; 195 int err;
182 196
183 if (device->port.membase || device->port.iobase) 197 if (device->port.membase || device->port.iobase)
@@ -190,61 +204,48 @@ static int __init early_uart_setup(struct console *console, char *options)
190 return 0; 204 return 0;
191} 205}
192 206
193static struct console early_uart_console __initdata = { 207int __init setup_early_serial8250_console(char *cmdline)
194 .name = "uart",
195 .write = early_uart_write,
196 .setup = early_uart_setup,
197 .flags = CON_PRINTBUFFER,
198 .index = -1,
199};
200
201static int __init early_uart_console_init(void)
202{
203 if (!early_uart_registered) {
204 register_console(&early_uart_console);
205 early_uart_registered = 1;
206 }
207 return 0;
208}
209console_initcall(early_uart_console_init);
210
211int __init early_serial_console_init(char *cmdline)
212{ 208{
213 char *options; 209 char *options;
214 int err; 210 int err;
215 211
216 options = strstr(cmdline, "console=uart,"); 212 options = strstr(cmdline, "uart8250,");
217 if (!options) 213 if (!options) {
218 return -ENODEV; 214 options = strstr(cmdline, "uart,");
215 if (!options)
216 return 0;
217 }
219 218
220 options = strchr(cmdline, ',') + 1; 219 options = strchr(cmdline, ',') + 1;
221 if ((err = early_uart_setup(NULL, options)) < 0) 220 if ((err = early_serial8250_setup(options)) < 0)
222 return err; 221 return err;
223 return early_uart_console_init(); 222
223 register_console(&early_serial8250_console);
224
225 return 0;
224} 226}
225 227
226static int __init early_uart_console_switch(void) 228int __init serial8250_find_port_for_earlycon(void)
227{ 229{
228 struct early_uart_device *device = &early_device; 230 struct early_serial8250_device *device = &early_device;
229 struct uart_port *port = &device->port; 231 struct uart_port *port = &device->port;
230 int mmio, line; 232 int line;
233 int ret;
231 234
232 if (!(early_uart_console.flags & CON_ENABLED)) 235 if (!device->port.membase && !device->port.iobase)
233 return 0; 236 return -ENODEV;
234 237
235 /* Try to start the normal driver on a matching line. */ 238 line = serial8250_find_port(port);
236 mmio = (port->iotype == UPIO_MEM);
237 line = serial8250_start_console(port, device->options);
238 if (line < 0) 239 if (line < 0)
239 printk("No ttyS device at %s 0x%lx for console\n", 240 return -ENODEV;
240 mmio ? "MMIO" : "I/O port",
241 mmio ? port->mapbase :
242 (unsigned long) port->iobase);
243 241
244 unregister_console(&early_uart_console); 242 ret = update_console_cmdline("uart", 8250,
245 if (mmio) 243 "ttyS", line, device->options);
246 iounmap(port->membase); 244 if (ret < 0)
245 ret = update_console_cmdline("uart", 0,
246 "ttyS", line, device->options);
247 247
248 return 0; 248 return ret;
249} 249}
250late_initcall(early_uart_console_switch); 250
251early_param("earlycon", setup_early_serial8250_console);