• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Linaro Ltd.
3  * Author: Rob Herring <robh@kernel.org>
4  *
5  * Based on 8250 earlycon:
6  * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
7  *	Bjorn Helgaas <bjorn.helgaas@hp.com>
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 #include <linux/console.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/io.h>
17 #include <linux/serial_core.h>
18 
19 #ifdef CONFIG_FIX_EARLYCON_MEM
20 #include <asm/fixmap.h>
21 #endif
22 
23 #include <asm/serial.h>
24 
25 static struct console early_con = {
26 	.name =		"earlycon",
27 	.flags =	CON_PRINTBUFFER | CON_BOOT,
28 	.index =	-1,
29 };
30 
31 static struct earlycon_device early_console_dev = {
32 	.con = &early_con,
33 };
34 
earlycon_map(unsigned long paddr,size_t size)35 static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
36 {
37 	void __iomem *base;
38 #ifdef CONFIG_FIX_EARLYCON_MEM
39 	set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
40 	base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
41 	base += paddr & ~PAGE_MASK;
42 #else
43 	base = ioremap(paddr, size);
44 #endif
45 	if (!base)
46 		pr_err("%s: Couldn't map 0x%llx\n", __func__,
47 		       (unsigned long long)paddr);
48 
49 	return base;
50 }
51 
parse_options(struct earlycon_device * device,char * options)52 static int __init parse_options(struct earlycon_device *device,
53 				char *options)
54 {
55 	struct uart_port *port = &device->port;
56 	int mmio, mmio32, length, ret;
57 	unsigned long addr;
58 
59 	if (!options)
60 		return -ENODEV;
61 
62 	mmio = !strncmp(options, "mmio,", 5);
63 	mmio32 = !strncmp(options, "mmio32,", 7);
64 	if (mmio || mmio32) {
65 		port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
66 		options += mmio ? 5 : 7;
67 		ret = kstrtoul(options, 0, &addr);
68 		if (ret)
69 			return ret;
70 		port->mapbase = addr;
71 		if (mmio32)
72 			port->regshift = 2;
73 	} else if (!strncmp(options, "io,", 3)) {
74 		port->iotype = UPIO_PORT;
75 		options += 3;
76 		ret = kstrtoul(options, 0, &addr);
77 		if (ret)
78 			return ret;
79 		port->iobase = addr;
80 		mmio = 0;
81 	} else if (!strncmp(options, "0x", 2)) {
82 		port->iotype = UPIO_MEM;
83 		ret = kstrtoul(options, 0, &addr);
84 		if (ret)
85 			return ret;
86 		port->mapbase = addr;
87 	} else {
88 		return -EINVAL;
89 	}
90 
91 	port->uartclk = BASE_BAUD * 16;
92 
93 	options = strchr(options, ',');
94 	if (options) {
95 		options++;
96 		ret = kstrtouint(options, 0, &device->baud);
97 		if (ret)
98 			return ret;
99 		length = min(strcspn(options, " ") + 1,
100 			     (size_t)(sizeof(device->options)));
101 		strlcpy(device->options, options, length);
102 	}
103 
104 	if (mmio || mmio32)
105 		pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
106 			mmio32 ? "32" : "",
107 			(unsigned long long)port->mapbase,
108 			device->options);
109 	else
110 		pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
111 			port->iobase,
112 			device->options);
113 
114 	return 0;
115 }
116 
setup_earlycon(char * buf,const char * match,int (* setup)(struct earlycon_device *,const char *))117 int __init setup_earlycon(char *buf, const char *match,
118 			  int (*setup)(struct earlycon_device *, const char *))
119 {
120 	int err;
121 	size_t len;
122 	struct uart_port *port = &early_console_dev.port;
123 
124 	if (!buf || !match || !setup)
125 		return 0;
126 
127 	len = strlen(match);
128 	if (strncmp(buf, match, len))
129 		return 0;
130 	if (buf[len] && (buf[len] != ','))
131 		return 0;
132 
133 	buf += len + 1;
134 
135 	err = parse_options(&early_console_dev, buf);
136 	/* On parsing error, pass the options buf to the setup function */
137 	if (!err)
138 		buf = NULL;
139 
140 	if (port->mapbase)
141 		port->membase = earlycon_map(port->mapbase, 64);
142 
143 	early_console_dev.con->data = &early_console_dev;
144 	err = setup(&early_console_dev, buf);
145 	if (err < 0)
146 		return err;
147 	if (!early_console_dev.con->write)
148 		return -ENODEV;
149 
150 	register_console(early_console_dev.con);
151 	return 0;
152 }
153