Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2014 Linaro Ltd.
0004  * Author: Rob Herring <robh@kernel.org>
0005  *
0006  * Based on 8250 earlycon:
0007  * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
0008  *  Bjorn Helgaas <bjorn.helgaas@hp.com>
0009  */
0010 
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012 
0013 #include <linux/console.h>
0014 #include <linux/kernel.h>
0015 #include <linux/init.h>
0016 #include <linux/io.h>
0017 #include <linux/serial_core.h>
0018 #include <linux/sizes.h>
0019 #include <linux/of.h>
0020 #include <linux/of_fdt.h>
0021 #include <linux/acpi.h>
0022 
0023 #ifdef CONFIG_FIX_EARLYCON_MEM
0024 #include <asm/fixmap.h>
0025 #endif
0026 
0027 #include <asm/serial.h>
0028 
0029 static struct console early_con = {
0030     .name =     "uart",     /* fixed up at earlycon registration */
0031     .flags =    CON_PRINTBUFFER | CON_BOOT,
0032     .index =    0,
0033 };
0034 
0035 static struct earlycon_device early_console_dev = {
0036     .con = &early_con,
0037 };
0038 
0039 static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size)
0040 {
0041     void __iomem *base;
0042 #ifdef CONFIG_FIX_EARLYCON_MEM
0043     set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
0044     base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
0045     base += paddr & ~PAGE_MASK;
0046 #else
0047     base = ioremap(paddr, size);
0048 #endif
0049     if (!base)
0050         pr_err("%s: Couldn't map %pa\n", __func__, &paddr);
0051 
0052     return base;
0053 }
0054 
0055 static void __init earlycon_init(struct earlycon_device *device,
0056                  const char *name)
0057 {
0058     struct console *earlycon = device->con;
0059     const char *s;
0060     size_t len;
0061 
0062     /* scan backwards from end of string for first non-numeral */
0063     for (s = name + strlen(name);
0064          s > name && s[-1] >= '0' && s[-1] <= '9';
0065          s--)
0066         ;
0067     if (*s)
0068         earlycon->index = simple_strtoul(s, NULL, 10);
0069     len = s - name;
0070     strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
0071     earlycon->data = &early_console_dev;
0072 }
0073 
0074 static void __init earlycon_print_info(struct earlycon_device *device)
0075 {
0076     struct console *earlycon = device->con;
0077     struct uart_port *port = &device->port;
0078 
0079     if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
0080         port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
0081         pr_info("%s%d at MMIO%s %pa (options '%s')\n",
0082             earlycon->name, earlycon->index,
0083             (port->iotype == UPIO_MEM) ? "" :
0084             (port->iotype == UPIO_MEM16) ? "16" :
0085             (port->iotype == UPIO_MEM32) ? "32" : "32be",
0086             &port->mapbase, device->options);
0087     else
0088         pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
0089             earlycon->name, earlycon->index,
0090             port->iobase, device->options);
0091 }
0092 
0093 static int __init parse_options(struct earlycon_device *device, char *options)
0094 {
0095     struct uart_port *port = &device->port;
0096     int length;
0097     resource_size_t addr;
0098 
0099     if (uart_parse_earlycon(options, &port->iotype, &addr, &options))
0100         return -EINVAL;
0101 
0102     switch (port->iotype) {
0103     case UPIO_MEM:
0104         port->mapbase = addr;
0105         break;
0106     case UPIO_MEM16:
0107         port->regshift = 1;
0108         port->mapbase = addr;
0109         break;
0110     case UPIO_MEM32:
0111     case UPIO_MEM32BE:
0112         port->regshift = 2;
0113         port->mapbase = addr;
0114         break;
0115     case UPIO_PORT:
0116         port->iobase = addr;
0117         break;
0118     default:
0119         return -EINVAL;
0120     }
0121 
0122     if (options) {
0123         device->baud = simple_strtoul(options, NULL, 0);
0124         length = min(strcspn(options, " ") + 1,
0125                  (size_t)(sizeof(device->options)));
0126         strlcpy(device->options, options, length);
0127     }
0128 
0129     return 0;
0130 }
0131 
0132 static int __init register_earlycon(char *buf, const struct earlycon_id *match)
0133 {
0134     int err;
0135     struct uart_port *port = &early_console_dev.port;
0136 
0137     /* On parsing error, pass the options buf to the setup function */
0138     if (buf && !parse_options(&early_console_dev, buf))
0139         buf = NULL;
0140 
0141     spin_lock_init(&port->lock);
0142     port->uartclk = BASE_BAUD * 16;
0143     if (port->mapbase)
0144         port->membase = earlycon_map(port->mapbase, 64);
0145 
0146     earlycon_init(&early_console_dev, match->name);
0147     err = match->setup(&early_console_dev, buf);
0148     earlycon_print_info(&early_console_dev);
0149     if (err < 0)
0150         return err;
0151     if (!early_console_dev.con->write)
0152         return -ENODEV;
0153 
0154     register_console(early_console_dev.con);
0155     return 0;
0156 }
0157 
0158 /**
0159  *  setup_earlycon - match and register earlycon console
0160  *  @buf:   earlycon param string
0161  *
0162  *  Registers the earlycon console matching the earlycon specified
0163  *  in the param string @buf. Acceptable param strings are of the form
0164  *     <name>,io|mmio|mmio32|mmio32be,<addr>,<options>
0165  *     <name>,0x<addr>,<options>
0166  *     <name>,<options>
0167  *     <name>
0168  *
0169  *  Only for the third form does the earlycon setup() method receive the
0170  *  <options> string in the 'options' parameter; all other forms set
0171  *  the parameter to NULL.
0172  *
0173  *  Returns 0 if an attempt to register the earlycon was made,
0174  *  otherwise negative error code
0175  */
0176 int __init setup_earlycon(char *buf)
0177 {
0178     const struct earlycon_id *match;
0179     bool empty_compatible = true;
0180 
0181     if (!buf || !buf[0])
0182         return -EINVAL;
0183 
0184     if (early_con.flags & CON_ENABLED)
0185         return -EALREADY;
0186 
0187 again:
0188     for (match = __earlycon_table; match < __earlycon_table_end; match++) {
0189         size_t len = strlen(match->name);
0190 
0191         if (strncmp(buf, match->name, len))
0192             continue;
0193 
0194         /* prefer entries with empty compatible */
0195         if (empty_compatible && *match->compatible)
0196             continue;
0197 
0198         if (buf[len]) {
0199             if (buf[len] != ',')
0200                 continue;
0201             buf += len + 1;
0202         } else
0203             buf = NULL;
0204 
0205         return register_earlycon(buf, match);
0206     }
0207 
0208     if (empty_compatible) {
0209         empty_compatible = false;
0210         goto again;
0211     }
0212 
0213     return -ENOENT;
0214 }
0215 
0216 /*
0217  * This defers the initialization of the early console until after ACPI has
0218  * been initialized.
0219  */
0220 bool earlycon_acpi_spcr_enable __initdata;
0221 
0222 /* early_param wrapper for setup_earlycon() */
0223 static int __init param_setup_earlycon(char *buf)
0224 {
0225     int err;
0226 
0227     /* Just 'earlycon' is a valid param for devicetree and ACPI SPCR. */
0228     if (!buf || !buf[0]) {
0229         if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
0230             earlycon_acpi_spcr_enable = true;
0231             return 0;
0232         } else if (!buf) {
0233             return early_init_dt_scan_chosen_stdout();
0234         }
0235     }
0236 
0237     err = setup_earlycon(buf);
0238     if (err == -ENOENT || err == -EALREADY)
0239         return 0;
0240     return err;
0241 }
0242 early_param("earlycon", param_setup_earlycon);
0243 
0244 #ifdef CONFIG_OF_EARLY_FLATTREE
0245 
0246 int __init of_setup_earlycon(const struct earlycon_id *match,
0247                  unsigned long node,
0248                  const char *options)
0249 {
0250     int err;
0251     struct uart_port *port = &early_console_dev.port;
0252     const __be32 *val;
0253     bool big_endian;
0254     u64 addr;
0255 
0256     if (early_con.flags & CON_ENABLED)
0257         return -EALREADY;
0258 
0259     spin_lock_init(&port->lock);
0260     port->iotype = UPIO_MEM;
0261     addr = of_flat_dt_translate_address(node);
0262     if (addr == OF_BAD_ADDR) {
0263         pr_warn("[%s] bad address\n", match->name);
0264         return -ENXIO;
0265     }
0266     port->mapbase = addr;
0267 
0268     val = of_get_flat_dt_prop(node, "reg-offset", NULL);
0269     if (val)
0270         port->mapbase += be32_to_cpu(*val);
0271     port->membase = earlycon_map(port->mapbase, SZ_4K);
0272 
0273     val = of_get_flat_dt_prop(node, "reg-shift", NULL);
0274     if (val)
0275         port->regshift = be32_to_cpu(*val);
0276     big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
0277         (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
0278          of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
0279     val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
0280     if (val) {
0281         switch (be32_to_cpu(*val)) {
0282         case 1:
0283             port->iotype = UPIO_MEM;
0284             break;
0285         case 2:
0286             port->iotype = UPIO_MEM16;
0287             break;
0288         case 4:
0289             port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
0290             break;
0291         default:
0292             pr_warn("[%s] unsupported reg-io-width\n", match->name);
0293             return -EINVAL;
0294         }
0295     }
0296 
0297     val = of_get_flat_dt_prop(node, "current-speed", NULL);
0298     if (val)
0299         early_console_dev.baud = be32_to_cpu(*val);
0300 
0301     val = of_get_flat_dt_prop(node, "clock-frequency", NULL);
0302     if (val)
0303         port->uartclk = be32_to_cpu(*val);
0304 
0305     if (options) {
0306         early_console_dev.baud = simple_strtoul(options, NULL, 0);
0307         strlcpy(early_console_dev.options, options,
0308             sizeof(early_console_dev.options));
0309     }
0310     earlycon_init(&early_console_dev, match->name);
0311     err = match->setup(&early_console_dev, options);
0312     earlycon_print_info(&early_console_dev);
0313     if (err < 0)
0314         return err;
0315     if (!early_console_dev.con->write)
0316         return -ENODEV;
0317 
0318 
0319     register_console(early_console_dev.con);
0320     return 0;
0321 }
0322 
0323 #endif /* CONFIG_OF_EARLY_FLATTREE */