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 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 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> 21#include <linux/sizes.h> 22#include <linux/mod_devicetable.h> 23 24#ifdef CONFIG_FIX_EARLYCON_MEM 25#include <asm/fixmap.h> 26#endif 27 28#include <asm/serial.h> 29 30static struct console early_con = { 31 .name = "uart", /* 8250 console switch requires this name */ 32 .flags = CON_PRINTBUFFER | CON_BOOT, 33 .index = -1, 34}; 35 36static struct earlycon_device early_console_dev = { 37 .con = &early_con, 38}; 39 40extern struct earlycon_id __earlycon_table[]; 41static const struct earlycon_id __earlycon_table_sentinel 42 __used __section(__earlycon_table_end); 43 44static const struct of_device_id __earlycon_of_table_sentinel 45 __used __section(__earlycon_of_table_end); 46 47static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) 48{ 49 void __iomem *base; 50#ifdef CONFIG_FIX_EARLYCON_MEM 51 set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK); 52 base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); 53 base += paddr & ~PAGE_MASK; 54#else 55 base = ioremap(paddr, size); 56#endif 57 if (!base) 58 pr_err("%s: Couldn't map 0x%llx\n", __func__, 59 (unsigned long long)paddr); 60 61 return base; 62} 63 64static int __init parse_options(struct earlycon_device *device, char *options) 65{ 66 struct uart_port *port = &device->port; 67 int length; 68 unsigned long addr; 69 70 if (uart_parse_earlycon(options, &port->iotype, &addr, &options)) 71 return -EINVAL; 72 73 switch (port->iotype) { 74 case UPIO_MEM32: 75 port->regshift = 2; /* fall-through */ 76 case UPIO_MEM: 77 port->mapbase = addr; 78 break; 79 case UPIO_PORT: 80 port->iobase = addr; 81 break; 82 default: 83 return -EINVAL; 84 } 85 86 if (options) { 87 device->baud = simple_strtoul(options, NULL, 0); 88 length = min(strcspn(options, " ") + 1, 89 (size_t)(sizeof(device->options))); 90 strlcpy(device->options, options, length); 91 } 92 93 if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32) 94 pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", 95 (port->iotype == UPIO_MEM32) ? "32" : "", 96 (unsigned long long)port->mapbase, 97 device->options); 98 else 99 pr_info("Early serial console at I/O port 0x%lx (options '%s')\n", 100 port->iobase, 101 device->options); 102 103 return 0; 104} 105 106static int __init register_earlycon(char *buf, const struct earlycon_id *match) 107{ 108 int err; 109 struct uart_port *port = &early_console_dev.port; 110 111 /* On parsing error, pass the options buf to the setup function */ 112 if (buf && !parse_options(&early_console_dev, buf)) 113 buf = NULL; 114 115 port->uartclk = BASE_BAUD * 16; 116 if (port->mapbase) 117 port->membase = earlycon_map(port->mapbase, 64); 118 119 early_console_dev.con->data = &early_console_dev; 120 err = match->setup(&early_console_dev, buf); 121 if (err < 0) 122 return err; 123 if (!early_console_dev.con->write) 124 return -ENODEV; 125 126 register_console(early_console_dev.con); 127 return 0; 128} 129 130/** 131 * setup_earlycon - match and register earlycon console 132 * @buf: earlycon param string 133 * 134 * Registers the earlycon console matching the earlycon specified 135 * in the param string @buf. Acceptable param strings are of the form 136 * <name>,io|mmio|mmio32,<addr>,<options> 137 * <name>,0x<addr>,<options> 138 * <name>,<options> 139 * <name> 140 * 141 * Only for the third form does the earlycon setup() method receive the 142 * <options> string in the 'options' parameter; all other forms set 143 * the parameter to NULL. 144 * 145 * Returns 0 if an attempt to register the earlycon was made, 146 * otherwise negative error code 147 */ 148int __init setup_earlycon(char *buf) 149{ 150 const struct earlycon_id *match; 151 152 if (!buf || !buf[0]) 153 return -EINVAL; 154 155 if (early_con.flags & CON_ENABLED) 156 return -EALREADY; 157 158 for (match = __earlycon_table; match->name[0]; match++) { 159 size_t len = strlen(match->name); 160 161 if (strncmp(buf, match->name, len)) 162 continue; 163 164 if (buf[len]) { 165 if (buf[len] != ',') 166 continue; 167 buf += len + 1; 168 } else 169 buf = NULL; 170 171 return register_earlycon(buf, match); 172 } 173 174 return -ENOENT; 175} 176 177/* early_param wrapper for setup_earlycon() */ 178static int __init param_setup_earlycon(char *buf) 179{ 180 int err; 181 182 /* 183 * Just 'earlycon' is a valid param for devicetree earlycons; 184 * don't generate a warning from parse_early_params() in that case 185 */ 186 if (!buf || !buf[0]) 187 return 0; 188 189 err = setup_earlycon(buf); 190 if (err == -ENOENT || err == -EALREADY) 191 return 0; 192 return err; 193} 194early_param("earlycon", param_setup_earlycon); 195 196int __init of_setup_earlycon(unsigned long addr, 197 int (*setup)(struct earlycon_device *, const char *)) 198{ 199 int err; 200 struct uart_port *port = &early_console_dev.port; 201 202 port->iotype = UPIO_MEM; 203 port->mapbase = addr; 204 port->uartclk = BASE_BAUD * 16; 205 port->membase = earlycon_map(addr, SZ_4K); 206 207 early_console_dev.con->data = &early_console_dev; 208 err = setup(&early_console_dev, NULL); 209 if (err < 0) 210 return err; 211 if (!early_console_dev.con->write) 212 return -ENODEV; 213 214 215 register_console(early_console_dev.con); 216 return 0; 217} 218