linux/drivers/tty/serial/earlycon.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2014 Linaro Ltd.
   4 * Author: Rob Herring <robh@kernel.org>
   5 *
   6 * Based on 8250 earlycon:
   7 * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
   8 *      Bjorn Helgaas <bjorn.helgaas@hp.com>
   9 */
  10
  11#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
  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#include <linux/sizes.h>
  19#include <linux/of.h>
  20#include <linux/of_fdt.h>
  21#include <linux/acpi.h>
  22
  23#ifdef CONFIG_FIX_EARLYCON_MEM
  24#include <asm/fixmap.h>
  25#endif
  26
  27#include <asm/serial.h>
  28
  29static struct console early_con = {
  30        .name =         "uart",         /* fixed up at earlycon registration */
  31        .flags =        CON_PRINTBUFFER | CON_BOOT,
  32        .index =        0,
  33};
  34
  35static struct earlycon_device early_console_dev = {
  36        .con = &early_con,
  37};
  38
  39static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size)
  40{
  41        void __iomem *base;
  42#ifdef CONFIG_FIX_EARLYCON_MEM
  43        set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
  44        base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
  45        base += paddr & ~PAGE_MASK;
  46#else
  47        base = ioremap(paddr, size);
  48#endif
  49        if (!base)
  50                pr_err("%s: Couldn't map %pa\n", __func__, &paddr);
  51
  52        return base;
  53}
  54
  55static void __init earlycon_init(struct earlycon_device *device,
  56                                 const char *name)
  57{
  58        struct console *earlycon = device->con;
  59        struct uart_port *port = &device->port;
  60        const char *s;
  61        size_t len;
  62
  63        /* scan backwards from end of string for first non-numeral */
  64        for (s = name + strlen(name);
  65             s > name && s[-1] >= '0' && s[-1] <= '9';
  66             s--)
  67                ;
  68        if (*s)
  69                earlycon->index = simple_strtoul(s, NULL, 10);
  70        len = s - name;
  71        strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
  72        earlycon->data = &early_console_dev;
  73
  74        if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
  75            port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
  76                pr_info("%s%d at MMIO%s %pa (options '%s')\n",
  77                        earlycon->name, earlycon->index,
  78                        (port->iotype == UPIO_MEM) ? "" :
  79                        (port->iotype == UPIO_MEM16) ? "16" :
  80                        (port->iotype == UPIO_MEM32) ? "32" : "32be",
  81                        &port->mapbase, device->options);
  82        else
  83                pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
  84                        earlycon->name, earlycon->index,
  85                        port->iobase, device->options);
  86}
  87
  88static int __init parse_options(struct earlycon_device *device, char *options)
  89{
  90        struct uart_port *port = &device->port;
  91        int length;
  92        resource_size_t addr;
  93
  94        if (uart_parse_earlycon(options, &port->iotype, &addr, &options))
  95                return -EINVAL;
  96
  97        switch (port->iotype) {
  98        case UPIO_MEM:
  99                port->mapbase = addr;
 100                break;
 101        case UPIO_MEM16:
 102                port->regshift = 1;
 103                port->mapbase = addr;
 104                break;
 105        case UPIO_MEM32:
 106        case UPIO_MEM32BE:
 107                port->regshift = 2;
 108                port->mapbase = addr;
 109                break;
 110        case UPIO_PORT:
 111                port->iobase = addr;
 112                break;
 113        default:
 114                return -EINVAL;
 115        }
 116
 117        if (options) {
 118                device->baud = simple_strtoul(options, NULL, 0);
 119                length = min(strcspn(options, " ") + 1,
 120                             (size_t)(sizeof(device->options)));
 121                strlcpy(device->options, options, length);
 122        }
 123
 124        return 0;
 125}
 126
 127static int __init register_earlycon(char *buf, const struct earlycon_id *match)
 128{
 129        int err;
 130        struct uart_port *port = &early_console_dev.port;
 131
 132        /* On parsing error, pass the options buf to the setup function */
 133        if (buf && !parse_options(&early_console_dev, buf))
 134                buf = NULL;
 135
 136        spin_lock_init(&port->lock);
 137        port->uartclk = BASE_BAUD * 16;
 138        if (port->mapbase)
 139                port->membase = earlycon_map(port->mapbase, 64);
 140
 141        earlycon_init(&early_console_dev, match->name);
 142        err = match->setup(&early_console_dev, buf);
 143        if (err < 0)
 144                return err;
 145        if (!early_console_dev.con->write)
 146                return -ENODEV;
 147
 148        register_console(early_console_dev.con);
 149        return 0;
 150}
 151
 152/**
 153 *      setup_earlycon - match and register earlycon console
 154 *      @buf:   earlycon param string
 155 *
 156 *      Registers the earlycon console matching the earlycon specified
 157 *      in the param string @buf. Acceptable param strings are of the form
 158 *         <name>,io|mmio|mmio32|mmio32be,<addr>,<options>
 159 *         <name>,0x<addr>,<options>
 160 *         <name>,<options>
 161 *         <name>
 162 *
 163 *      Only for the third form does the earlycon setup() method receive the
 164 *      <options> string in the 'options' parameter; all other forms set
 165 *      the parameter to NULL.
 166 *
 167 *      Returns 0 if an attempt to register the earlycon was made,
 168 *      otherwise negative error code
 169 */
 170int __init setup_earlycon(char *buf)
 171{
 172        const struct earlycon_id **p_match;
 173        bool empty_compatible = true;
 174
 175        if (!buf || !buf[0])
 176                return -EINVAL;
 177
 178        if (early_con.flags & CON_ENABLED)
 179                return -EALREADY;
 180
 181again:
 182        for (p_match = __earlycon_table; p_match < __earlycon_table_end;
 183             p_match++) {
 184                const struct earlycon_id *match = *p_match;
 185                size_t len = strlen(match->name);
 186
 187                if (strncmp(buf, match->name, len))
 188                        continue;
 189
 190                /* prefer entries with empty compatible */
 191                if (empty_compatible && *match->compatible)
 192                        continue;
 193
 194                if (buf[len]) {
 195                        if (buf[len] != ',')
 196                                continue;
 197                        buf += len + 1;
 198                } else
 199                        buf = NULL;
 200
 201                return register_earlycon(buf, match);
 202        }
 203
 204        if (empty_compatible) {
 205                empty_compatible = false;
 206                goto again;
 207        }
 208
 209        return -ENOENT;
 210}
 211
 212/*
 213 * This defers the initialization of the early console until after ACPI has
 214 * been initialized.
 215 */
 216bool earlycon_acpi_spcr_enable __initdata;
 217
 218/* early_param wrapper for setup_earlycon() */
 219static int __init param_setup_earlycon(char *buf)
 220{
 221        int err;
 222
 223        /* Just 'earlycon' is a valid param for devicetree and ACPI SPCR. */
 224        if (!buf || !buf[0]) {
 225                if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
 226                        earlycon_acpi_spcr_enable = true;
 227                        return 0;
 228                } else if (!buf) {
 229                        return early_init_dt_scan_chosen_stdout();
 230                }
 231        }
 232
 233        err = setup_earlycon(buf);
 234        if (err == -ENOENT || err == -EALREADY)
 235                return 0;
 236        return err;
 237}
 238early_param("earlycon", param_setup_earlycon);
 239
 240#ifdef CONFIG_OF_EARLY_FLATTREE
 241
 242int __init of_setup_earlycon(const struct earlycon_id *match,
 243                             unsigned long node,
 244                             const char *options)
 245{
 246        int err;
 247        struct uart_port *port = &early_console_dev.port;
 248        const __be32 *val;
 249        bool big_endian;
 250        u64 addr;
 251
 252        spin_lock_init(&port->lock);
 253        port->iotype = UPIO_MEM;
 254        addr = of_flat_dt_translate_address(node);
 255        if (addr == OF_BAD_ADDR) {
 256                pr_warn("[%s] bad address\n", match->name);
 257                return -ENXIO;
 258        }
 259        port->mapbase = addr;
 260
 261        val = of_get_flat_dt_prop(node, "reg-offset", NULL);
 262        if (val)
 263                port->mapbase += be32_to_cpu(*val);
 264        port->membase = earlycon_map(port->mapbase, SZ_4K);
 265
 266        val = of_get_flat_dt_prop(node, "reg-shift", NULL);
 267        if (val)
 268                port->regshift = be32_to_cpu(*val);
 269        big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
 270                (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
 271                 of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
 272        val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
 273        if (val) {
 274                switch (be32_to_cpu(*val)) {
 275                case 1:
 276                        port->iotype = UPIO_MEM;
 277                        break;
 278                case 2:
 279                        port->iotype = UPIO_MEM16;
 280                        break;
 281                case 4:
 282                        port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
 283                        break;
 284                default:
 285                        pr_warn("[%s] unsupported reg-io-width\n", match->name);
 286                        return -EINVAL;
 287                }
 288        }
 289
 290        val = of_get_flat_dt_prop(node, "current-speed", NULL);
 291        if (val)
 292                early_console_dev.baud = be32_to_cpu(*val);
 293
 294        val = of_get_flat_dt_prop(node, "clock-frequency", NULL);
 295        if (val)
 296                port->uartclk = be32_to_cpu(*val);
 297
 298        if (options) {
 299                early_console_dev.baud = simple_strtoul(options, NULL, 0);
 300                strlcpy(early_console_dev.options, options,
 301                        sizeof(early_console_dev.options));
 302        }
 303        earlycon_init(&early_console_dev, match->name);
 304        err = match->setup(&early_console_dev, options);
 305        if (err < 0)
 306                return err;
 307        if (!early_console_dev.con->write)
 308                return -ENODEV;
 309
 310
 311        register_console(early_console_dev.con);
 312        return 0;
 313}
 314
 315#endif /* CONFIG_OF_EARLY_FLATTREE */
 316