aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial
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
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')
-rw-r--r--drivers/serial/8250.c28
-rw-r--r--drivers/serial/8250_early.c117
-rw-r--r--drivers/serial/Kconfig14
3 files changed, 80 insertions, 79 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c84dab083a85..0b3ec38ae614 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2514,12 +2514,18 @@ static int __init serial8250_console_setup(struct console *co, char *options)
2514 return uart_set_options(port, co, baud, parity, bits, flow); 2514 return uart_set_options(port, co, baud, parity, bits, flow);
2515} 2515}
2516 2516
2517static int __init serial8250_console_early_setup(void)
2518{
2519 return serial8250_find_port_for_earlycon();
2520}
2521
2517static struct uart_driver serial8250_reg; 2522static struct uart_driver serial8250_reg;
2518static struct console serial8250_console = { 2523static struct console serial8250_console = {
2519 .name = "ttyS", 2524 .name = "ttyS",
2520 .write = serial8250_console_write, 2525 .write = serial8250_console_write,
2521 .device = uart_console_device, 2526 .device = uart_console_device,
2522 .setup = serial8250_console_setup, 2527 .setup = serial8250_console_setup,
2528 .early_setup = serial8250_console_early_setup,
2523 .flags = CON_PRINTBUFFER, 2529 .flags = CON_PRINTBUFFER,
2524 .index = -1, 2530 .index = -1,
2525 .data = &serial8250_reg, 2531 .data = &serial8250_reg,
@@ -2533,7 +2539,7 @@ static int __init serial8250_console_init(void)
2533} 2539}
2534console_initcall(serial8250_console_init); 2540console_initcall(serial8250_console_init);
2535 2541
2536static int __init find_port(struct uart_port *p) 2542int serial8250_find_port(struct uart_port *p)
2537{ 2543{
2538 int line; 2544 int line;
2539 struct uart_port *port; 2545 struct uart_port *port;
@@ -2546,26 +2552,6 @@ static int __init find_port(struct uart_port *p)
2546 return -ENODEV; 2552 return -ENODEV;
2547} 2553}
2548 2554
2549int __init serial8250_start_console(struct uart_port *port, char *options)
2550{
2551 int line;
2552
2553 line = find_port(port);
2554 if (line < 0)
2555 return -ENODEV;
2556
2557 add_preferred_console("ttyS", line, options);
2558 printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
2559 line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
2560 port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
2561 (unsigned long) port->iobase, options);
2562 if (!(serial8250_console.flags & CON_ENABLED)) {
2563 serial8250_console.flags &= ~CON_PRINTBUFFER;
2564 register_console(&serial8250_console);
2565 }
2566 return line;
2567}
2568
2569#define SERIAL8250_CONSOLE &serial8250_console 2555#define SERIAL8250_CONSOLE &serial8250_console
2570#else 2556#else
2571#define SERIAL8250_CONSOLE NULL 2557#define SERIAL8250_CONSOLE NULL
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 7e511199b4c5..947c20507e1f 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);
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 2adbed4e10f3..cab42cbd920d 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -62,8 +62,22 @@ config SERIAL_8250_CONSOLE
62 kernel will automatically use the first serial line, /dev/ttyS0, as 62 kernel will automatically use the first serial line, /dev/ttyS0, as
63 system console. 63 system console.
64 64
65 you can set that using a kernel command line option such as
66 "console=uart8250,io,0x3f8,9600n8"
67 "console=uart8250,mmio,0xff5e0000,115200n8".
68 and it will switch to normal serial console when correponding port is
69 ready.
70 "earlycon=uart8250,io,0x3f8,9600n8"
71 "earlycon=uart8250,mmio,0xff5e0000,115200n8".
72 it will not only setup early console.
73
65 If unsure, say N. 74 If unsure, say N.
66 75
76config FIX_EARLYCON_MEM
77 bool
78 depends on X86
79 default y
80
67config SERIAL_8250_GSC 81config SERIAL_8250_GSC
68 tristate 82 tristate
69 depends on SERIAL_8250 && GSC 83 depends on SERIAL_8250 && GSC