]>
Commit | Line | Data |
---|---|---|
9aac5887 RH |
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 | */ | |
470ca0de PH |
13 | |
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
15 | ||
9aac5887 RH |
16 | #include <linux/console.h> |
17 | #include <linux/kernel.h> | |
18 | #include <linux/init.h> | |
19 | #include <linux/io.h> | |
20 | #include <linux/serial_core.h> | |
b0b6abd3 | 21 | #include <linux/sizes.h> |
c90fe9c0 | 22 | #include <linux/of.h> |
088da2a1 | 23 | #include <linux/of_fdt.h> |
ad1696f6 | 24 | #include <linux/acpi.h> |
9aac5887 RH |
25 | |
26 | #ifdef CONFIG_FIX_EARLYCON_MEM | |
27 | #include <asm/fixmap.h> | |
28 | #endif | |
29 | ||
30 | #include <asm/serial.h> | |
31 | ||
32 | static struct console early_con = { | |
cda64e68 | 33 | .name = "uart", /* fixed up at earlycon registration */ |
9aac5887 | 34 | .flags = CON_PRINTBUFFER | CON_BOOT, |
cda64e68 | 35 | .index = 0, |
9aac5887 RH |
36 | }; |
37 | ||
38 | static struct earlycon_device early_console_dev = { | |
39 | .con = &early_con, | |
40 | }; | |
41 | ||
46e36683 | 42 | static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size) |
9aac5887 RH |
43 | { |
44 | void __iomem *base; | |
45 | #ifdef CONFIG_FIX_EARLYCON_MEM | |
46 | set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK); | |
47 | base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); | |
48 | base += paddr & ~PAGE_MASK; | |
49 | #else | |
50 | base = ioremap(paddr, size); | |
51 | #endif | |
52 | if (!base) | |
46e36683 | 53 | pr_err("%s: Couldn't map %pa\n", __func__, &paddr); |
9aac5887 RH |
54 | |
55 | return base; | |
56 | } | |
57 | ||
cda64e68 PH |
58 | static void __init earlycon_init(struct earlycon_device *device, |
59 | const char *name) | |
60 | { | |
61 | struct console *earlycon = device->con; | |
8e773739 | 62 | struct uart_port *port = &device->port; |
cda64e68 PH |
63 | const char *s; |
64 | size_t len; | |
65 | ||
66 | /* scan backwards from end of string for first non-numeral */ | |
67 | for (s = name + strlen(name); | |
68 | s > name && s[-1] >= '0' && s[-1] <= '9'; | |
69 | s--) | |
70 | ; | |
71 | if (*s) | |
72 | earlycon->index = simple_strtoul(s, NULL, 10); | |
73 | len = s - name; | |
74 | strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name))); | |
75 | earlycon->data = &early_console_dev; | |
8e773739 PH |
76 | |
77 | if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 || | |
78 | port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE) | |
b9693984 PH |
79 | pr_info("%s%d at MMIO%s %pa (options '%s')\n", |
80 | earlycon->name, earlycon->index, | |
8e773739 PH |
81 | (port->iotype == UPIO_MEM) ? "" : |
82 | (port->iotype == UPIO_MEM16) ? "16" : | |
83 | (port->iotype == UPIO_MEM32) ? "32" : "32be", | |
b9693984 | 84 | &port->mapbase, device->options); |
8e773739 | 85 | else |
b9693984 PH |
86 | pr_info("%s%d at I/O port 0x%lx (options '%s')\n", |
87 | earlycon->name, earlycon->index, | |
88 | port->iobase, device->options); | |
cda64e68 PH |
89 | } |
90 | ||
73abaf87 | 91 | static int __init parse_options(struct earlycon_device *device, char *options) |
9aac5887 RH |
92 | { |
93 | struct uart_port *port = &device->port; | |
73abaf87 | 94 | int length; |
46e36683 | 95 | resource_size_t addr; |
9aac5887 | 96 | |
73abaf87 PH |
97 | if (uart_parse_earlycon(options, &port->iotype, &addr, &options)) |
98 | return -EINVAL; | |
9aac5887 | 99 | |
73abaf87 | 100 | switch (port->iotype) { |
bd94c407 MY |
101 | case UPIO_MEM: |
102 | port->mapbase = addr; | |
103 | break; | |
104 | case UPIO_MEM16: | |
105 | port->regshift = 1; | |
106 | port->mapbase = addr; | |
107 | break; | |
73abaf87 | 108 | case UPIO_MEM32: |
6e63be3f | 109 | case UPIO_MEM32BE: |
bd94c407 | 110 | port->regshift = 2; |
9aac5887 | 111 | port->mapbase = addr; |
73abaf87 PH |
112 | break; |
113 | case UPIO_PORT: | |
9aac5887 | 114 | port->iobase = addr; |
73abaf87 PH |
115 | break; |
116 | default: | |
9aac5887 RH |
117 | return -EINVAL; |
118 | } | |
119 | ||
9aac5887 | 120 | if (options) { |
e26f1db9 | 121 | device->baud = simple_strtoul(options, NULL, 0); |
9aac5887 RH |
122 | length = min(strcspn(options, " ") + 1, |
123 | (size_t)(sizeof(device->options))); | |
124 | strlcpy(device->options, options, length); | |
125 | } | |
126 | ||
9aac5887 RH |
127 | return 0; |
128 | } | |
129 | ||
470ca0de | 130 | static int __init register_earlycon(char *buf, const struct earlycon_id *match) |
9aac5887 RH |
131 | { |
132 | int err; | |
9aac5887 RH |
133 | struct uart_port *port = &early_console_dev.port; |
134 | ||
9aac5887 | 135 | /* On parsing error, pass the options buf to the setup function */ |
60846880 | 136 | if (buf && !parse_options(&early_console_dev, buf)) |
9aac5887 RH |
137 | buf = NULL; |
138 | ||
e1dd3bef | 139 | spin_lock_init(&port->lock); |
feed5bab | 140 | port->uartclk = BASE_BAUD * 16; |
9aac5887 RH |
141 | if (port->mapbase) |
142 | port->membase = earlycon_map(port->mapbase, 64); | |
143 | ||
cda64e68 | 144 | earlycon_init(&early_console_dev, match->name); |
470ca0de | 145 | err = match->setup(&early_console_dev, buf); |
9aac5887 RH |
146 | if (err < 0) |
147 | return err; | |
148 | if (!early_console_dev.con->write) | |
149 | return -ENODEV; | |
150 | ||
151 | register_console(early_console_dev.con); | |
152 | return 0; | |
153 | } | |
b0b6abd3 | 154 | |
470ca0de PH |
155 | /** |
156 | * setup_earlycon - match and register earlycon console | |
157 | * @buf: earlycon param string | |
158 | * | |
159 | * Registers the earlycon console matching the earlycon specified | |
160 | * in the param string @buf. Acceptable param strings are of the form | |
6e63be3f | 161 | * <name>,io|mmio|mmio32|mmio32be,<addr>,<options> |
470ca0de PH |
162 | * <name>,0x<addr>,<options> |
163 | * <name>,<options> | |
164 | * <name> | |
165 | * | |
166 | * Only for the third form does the earlycon setup() method receive the | |
167 | * <options> string in the 'options' parameter; all other forms set | |
168 | * the parameter to NULL. | |
169 | * | |
170 | * Returns 0 if an attempt to register the earlycon was made, | |
171 | * otherwise negative error code | |
172 | */ | |
173 | int __init setup_earlycon(char *buf) | |
7c53cb3d | 174 | { |
470ca0de | 175 | const struct earlycon_id *match; |
7c53cb3d | 176 | |
470ca0de PH |
177 | if (!buf || !buf[0]) |
178 | return -EINVAL; | |
7c53cb3d | 179 | |
470ca0de PH |
180 | if (early_con.flags & CON_ENABLED) |
181 | return -EALREADY; | |
7c53cb3d | 182 | |
2eaa7909 | 183 | for (match = __earlycon_table; match < __earlycon_table_end; match++) { |
470ca0de | 184 | size_t len = strlen(match->name); |
7c53cb3d | 185 | |
470ca0de PH |
186 | if (strncmp(buf, match->name, len)) |
187 | continue; | |
188 | ||
189 | if (buf[len]) { | |
190 | if (buf[len] != ',') | |
191 | continue; | |
192 | buf += len + 1; | |
193 | } else | |
194 | buf = NULL; | |
195 | ||
196 | return register_earlycon(buf, match); | |
197 | } | |
198 | ||
199 | return -ENOENT; | |
200 | } | |
201 | ||
ad1696f6 AM |
202 | /* |
203 | * When CONFIG_ACPI_SPCR_TABLE is defined, "earlycon" without parameters in | |
204 | * command line does not start DT earlycon immediately, instead it defers | |
205 | * starting it until DT/ACPI decision is made. At that time if ACPI is enabled | |
206 | * call parse_spcr(), else call early_init_dt_scan_chosen_stdout() | |
207 | */ | |
208 | bool earlycon_init_is_deferred __initdata; | |
209 | ||
470ca0de PH |
210 | /* early_param wrapper for setup_earlycon() */ |
211 | static int __init param_setup_earlycon(char *buf) | |
212 | { | |
213 | int err; | |
214 | ||
215 | /* | |
216 | * Just 'earlycon' is a valid param for devicetree earlycons; | |
217 | * don't generate a warning from parse_early_params() in that case | |
218 | */ | |
ad1696f6 AM |
219 | if (!buf || !buf[0]) { |
220 | if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) { | |
221 | earlycon_init_is_deferred = true; | |
222 | return 0; | |
223 | } else { | |
224 | return early_init_dt_scan_chosen_stdout(); | |
225 | } | |
226 | } | |
470ca0de PH |
227 | |
228 | err = setup_earlycon(buf); | |
66c53aaa PH |
229 | if (err == -ENOENT || err == -EALREADY) |
230 | return 0; | |
470ca0de | 231 | return err; |
7c53cb3d | 232 | } |
470ca0de | 233 | early_param("earlycon", param_setup_earlycon); |
7c53cb3d | 234 | |
8477614d PH |
235 | #ifdef CONFIG_OF_EARLY_FLATTREE |
236 | ||
c90fe9c0 | 237 | int __init of_setup_earlycon(const struct earlycon_id *match, |
088da2a1 | 238 | unsigned long node, |
4d118c9a | 239 | const char *options) |
b0b6abd3 RH |
240 | { |
241 | int err; | |
242 | struct uart_port *port = &early_console_dev.port; | |
088da2a1 PH |
243 | const __be32 *val; |
244 | bool big_endian; | |
c90fe9c0 | 245 | u64 addr; |
b0b6abd3 | 246 | |
e1dd3bef | 247 | spin_lock_init(&port->lock); |
b0b6abd3 | 248 | port->iotype = UPIO_MEM; |
c90fe9c0 PH |
249 | addr = of_flat_dt_translate_address(node); |
250 | if (addr == OF_BAD_ADDR) { | |
251 | pr_warn("[%s] bad address\n", match->name); | |
252 | return -ENXIO; | |
253 | } | |
b0b6abd3 RH |
254 | port->mapbase = addr; |
255 | port->uartclk = BASE_BAUD * 16; | |
c90fe9c0 | 256 | port->membase = earlycon_map(port->mapbase, SZ_4K); |
b0b6abd3 | 257 | |
088da2a1 PH |
258 | val = of_get_flat_dt_prop(node, "reg-offset", NULL); |
259 | if (val) | |
260 | port->mapbase += be32_to_cpu(*val); | |
261 | val = of_get_flat_dt_prop(node, "reg-shift", NULL); | |
262 | if (val) | |
263 | port->regshift = be32_to_cpu(*val); | |
264 | big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL || | |
265 | (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && | |
266 | of_get_flat_dt_prop(node, "native-endian", NULL) != NULL); | |
267 | val = of_get_flat_dt_prop(node, "reg-io-width", NULL); | |
268 | if (val) { | |
269 | switch (be32_to_cpu(*val)) { | |
270 | case 1: | |
271 | port->iotype = UPIO_MEM; | |
272 | break; | |
273 | case 2: | |
274 | port->iotype = UPIO_MEM16; | |
275 | break; | |
276 | case 4: | |
277 | port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32; | |
278 | break; | |
279 | default: | |
280 | pr_warn("[%s] unsupported reg-io-width\n", match->name); | |
281 | return -EINVAL; | |
282 | } | |
283 | } | |
284 | ||
4d118c9a PH |
285 | if (options) { |
286 | strlcpy(early_console_dev.options, options, | |
287 | sizeof(early_console_dev.options)); | |
288 | } | |
05d96132 | 289 | earlycon_init(&early_console_dev, match->name); |
4d118c9a | 290 | err = match->setup(&early_console_dev, options); |
b0b6abd3 RH |
291 | if (err < 0) |
292 | return err; | |
293 | if (!early_console_dev.con->write) | |
294 | return -ENODEV; | |
295 | ||
296 | ||
297 | register_console(early_console_dev.con); | |
298 | return 0; | |
299 | } | |
8477614d PH |
300 | |
301 | #endif /* CONFIG_OF_EARLY_FLATTREE */ |