LCOV - code coverage report
Current view: top level - drivers/tty/serial - earlycon.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 16 82 19.5 %
Date: 2022-04-01 14:58:12 Functions: 2 5 40.0 %
Branches: 9 61 14.8 %

           Branch data     Line data    Source code
       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                 :            : 
      29                 :            : static struct console early_con = {
      30                 :            :         .name =         "uart",               /* fixed up at earlycon registration */
      31                 :            :         .flags =        CON_PRINTBUFFER | CON_BOOT,
      32                 :            :         .index =        0,
      33                 :            : };
      34                 :            : 
      35                 :            : static struct earlycon_device early_console_dev = {
      36                 :            :         .con = &early_con,
      37                 :            : };
      38                 :            : 
      39                 :            : static 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                 :            : 
      55                 :          0 : static void __init earlycon_init(struct earlycon_device *device,
      56                 :            :                                  const char *name)
      57                 :            : {
      58                 :          0 :         struct console *earlycon = device->con;
      59                 :          0 :         struct uart_port *port = &device->port;
      60                 :          0 :         const char *s;
      61                 :          0 :         size_t len;
      62                 :            : 
      63                 :            :         /* scan backwards from end of string for first non-numeral */
      64                 :          0 :         for (s = name + strlen(name);
      65   [ #  #  #  #  :          0 :              s > name && s[-1] >= '0' && s[-1] <= '9';
                   #  # ]
      66                 :          0 :              s--)
      67                 :          0 :                 ;
      68         [ #  # ]:          0 :         if (*s)
      69                 :          0 :                 earlycon->index = simple_strtoul(s, NULL, 10);
      70                 :          0 :         len = s - name;
      71                 :          0 :         strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
      72                 :          0 :         earlycon->data = &early_console_dev;
      73                 :            : 
      74   [ #  #  #  # ]:          0 :         if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
      75         [ #  # ]:          0 :             port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
      76   [ #  #  #  #  :          0 :                 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                 :          0 :                 pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
      84                 :            :                         earlycon->name, earlycon->index,
      85                 :            :                         port->iobase, device->options);
      86                 :          0 : }
      87                 :            : 
      88                 :          0 : static int __init parse_options(struct earlycon_device *device, char *options)
      89                 :            : {
      90                 :          0 :         struct uart_port *port = &device->port;
      91                 :          0 :         int length;
      92                 :          0 :         resource_size_t addr;
      93                 :            : 
      94         [ #  # ]:          0 :         if (uart_parse_earlycon(options, &port->iotype, &addr, &options))
      95                 :            :                 return -EINVAL;
      96                 :            : 
      97   [ #  #  #  #  :          0 :         switch (port->iotype) {
                      # ]
      98                 :          0 :         case UPIO_MEM:
      99                 :          0 :                 port->mapbase = addr;
     100                 :          0 :                 break;
     101                 :          0 :         case UPIO_MEM16:
     102                 :          0 :                 port->regshift = 1;
     103                 :          0 :                 port->mapbase = addr;
     104                 :          0 :                 break;
     105                 :          0 :         case UPIO_MEM32:
     106                 :            :         case UPIO_MEM32BE:
     107                 :          0 :                 port->regshift = 2;
     108                 :          0 :                 port->mapbase = addr;
     109                 :          0 :                 break;
     110                 :          0 :         case UPIO_PORT:
     111                 :          0 :                 port->iobase = addr;
     112                 :          0 :                 break;
     113                 :            :         default:
     114                 :            :                 return -EINVAL;
     115                 :            :         }
     116                 :            : 
     117         [ #  # ]:          0 :         if (options) {
     118                 :          0 :                 device->baud = simple_strtoul(options, NULL, 0);
     119                 :          0 :                 length = min(strcspn(options, " ") + 1,
     120                 :            :                              (size_t)(sizeof(device->options)));
     121                 :          0 :                 strlcpy(device->options, options, length);
     122                 :            :         }
     123                 :            : 
     124                 :            :         return 0;
     125                 :            : }
     126                 :            : 
     127                 :          0 : static int __init register_earlycon(char *buf, const struct earlycon_id *match)
     128                 :            : {
     129                 :          0 :         int err;
     130                 :          0 :         struct uart_port *port = &early_console_dev.port;
     131                 :            : 
     132                 :            :         /* On parsing error, pass the options buf to the setup function */
     133   [ #  #  #  # ]:          0 :         if (buf && !parse_options(&early_console_dev, buf))
     134                 :          0 :                 buf = NULL;
     135                 :            : 
     136         [ #  # ]:          0 :         spin_lock_init(&port->lock);
     137                 :          0 :         port->uartclk = BASE_BAUD * 16;
     138         [ #  # ]:          0 :         if (port->mapbase)
     139                 :          0 :                 port->membase = earlycon_map(port->mapbase, 64);
     140                 :            : 
     141                 :          0 :         earlycon_init(&early_console_dev, match->name);
     142                 :          0 :         err = match->setup(&early_console_dev, buf);
     143         [ #  # ]:          0 :         if (err < 0)
     144                 :            :                 return err;
     145         [ #  # ]:          0 :         if (!early_console_dev.con->write)
     146                 :            :                 return -ENODEV;
     147                 :            : 
     148                 :          0 :         register_console(early_console_dev.con);
     149                 :          0 :         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                 :            :  */
     170                 :          3 : int __init setup_earlycon(char *buf)
     171                 :            : {
     172                 :          3 :         const struct earlycon_id **p_match;
     173                 :            : 
     174   [ +  -  +  - ]:          3 :         if (!buf || !buf[0])
     175                 :            :                 return -EINVAL;
     176                 :            : 
     177         [ +  - ]:          3 :         if (early_con.flags & CON_ENABLED)
     178                 :            :                 return -EALREADY;
     179                 :            : 
     180         [ +  + ]:         24 :         for (p_match = __earlycon_table; p_match < __earlycon_table_end;
     181                 :         21 :              p_match++) {
     182                 :         21 :                 const struct earlycon_id *match = *p_match;
     183                 :         21 :                 size_t len = strlen(match->name);
     184                 :            : 
     185         [ +  - ]:         21 :                 if (strncmp(buf, match->name, len))
     186                 :         21 :                         continue;
     187                 :            : 
     188         [ #  # ]:          0 :                 if (buf[len]) {
     189         [ #  # ]:          0 :                         if (buf[len] != ',')
     190                 :          0 :                                 continue;
     191                 :          0 :                         buf += len + 1;
     192                 :            :                 } else
     193                 :            :                         buf = NULL;
     194                 :            : 
     195                 :          0 :                 return register_earlycon(buf, match);
     196                 :            :         }
     197                 :            : 
     198                 :            :         return -ENOENT;
     199                 :            : }
     200                 :            : 
     201                 :            : /*
     202                 :            :  * This defers the initialization of the early console until after ACPI has
     203                 :            :  * been initialized.
     204                 :            :  */
     205                 :            : bool earlycon_acpi_spcr_enable __initdata;
     206                 :            : 
     207                 :            : /* early_param wrapper for setup_earlycon() */
     208                 :          3 : static int __init param_setup_earlycon(char *buf)
     209                 :            : {
     210                 :          3 :         int err;
     211                 :            : 
     212                 :            :         /* Just 'earlycon' is a valid param for devicetree and ACPI SPCR. */
     213   [ +  -  -  + ]:          3 :         if (!buf || !buf[0]) {
     214                 :          0 :                 if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
     215                 :          0 :                         earlycon_acpi_spcr_enable = true;
     216                 :          0 :                         return 0;
     217                 :            :                 } else if (!buf) {
     218                 :            :                         return early_init_dt_scan_chosen_stdout();
     219                 :            :                 }
     220                 :            :         }
     221                 :            : 
     222                 :          3 :         err = setup_earlycon(buf);
     223         [ +  - ]:          3 :         if (err == -ENOENT || err == -EALREADY)
     224                 :          3 :                 return 0;
     225                 :            :         return err;
     226                 :            : }
     227                 :            : early_param("earlycon", param_setup_earlycon);
     228                 :            : 
     229                 :            : #ifdef CONFIG_OF_EARLY_FLATTREE
     230                 :            : 
     231                 :            : int __init of_setup_earlycon(const struct earlycon_id *match,
     232                 :            :                              unsigned long node,
     233                 :            :                              const char *options)
     234                 :            : {
     235                 :            :         int err;
     236                 :            :         struct uart_port *port = &early_console_dev.port;
     237                 :            :         const __be32 *val;
     238                 :            :         bool big_endian;
     239                 :            :         u64 addr;
     240                 :            : 
     241                 :            :         spin_lock_init(&port->lock);
     242                 :            :         port->iotype = UPIO_MEM;
     243                 :            :         addr = of_flat_dt_translate_address(node);
     244                 :            :         if (addr == OF_BAD_ADDR) {
     245                 :            :                 pr_warn("[%s] bad address\n", match->name);
     246                 :            :                 return -ENXIO;
     247                 :            :         }
     248                 :            :         port->mapbase = addr;
     249                 :            : 
     250                 :            :         val = of_get_flat_dt_prop(node, "reg-offset", NULL);
     251                 :            :         if (val)
     252                 :            :                 port->mapbase += be32_to_cpu(*val);
     253                 :            :         port->membase = earlycon_map(port->mapbase, SZ_4K);
     254                 :            : 
     255                 :            :         val = of_get_flat_dt_prop(node, "reg-shift", NULL);
     256                 :            :         if (val)
     257                 :            :                 port->regshift = be32_to_cpu(*val);
     258                 :            :         big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
     259                 :            :                 (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
     260                 :            :                  of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
     261                 :            :         val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
     262                 :            :         if (val) {
     263                 :            :                 switch (be32_to_cpu(*val)) {
     264                 :            :                 case 1:
     265                 :            :                         port->iotype = UPIO_MEM;
     266                 :            :                         break;
     267                 :            :                 case 2:
     268                 :            :                         port->iotype = UPIO_MEM16;
     269                 :            :                         break;
     270                 :            :                 case 4:
     271                 :            :                         port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
     272                 :            :                         break;
     273                 :            :                 default:
     274                 :            :                         pr_warn("[%s] unsupported reg-io-width\n", match->name);
     275                 :            :                         return -EINVAL;
     276                 :            :                 }
     277                 :            :         }
     278                 :            : 
     279                 :            :         val = of_get_flat_dt_prop(node, "current-speed", NULL);
     280                 :            :         if (val)
     281                 :            :                 early_console_dev.baud = be32_to_cpu(*val);
     282                 :            : 
     283                 :            :         val = of_get_flat_dt_prop(node, "clock-frequency", NULL);
     284                 :            :         if (val)
     285                 :            :                 port->uartclk = be32_to_cpu(*val);
     286                 :            : 
     287                 :            :         if (options) {
     288                 :            :                 early_console_dev.baud = simple_strtoul(options, NULL, 0);
     289                 :            :                 strlcpy(early_console_dev.options, options,
     290                 :            :                         sizeof(early_console_dev.options));
     291                 :            :         }
     292                 :            :         earlycon_init(&early_console_dev, match->name);
     293                 :            :         err = match->setup(&early_console_dev, options);
     294                 :            :         if (err < 0)
     295                 :            :                 return err;
     296                 :            :         if (!early_console_dev.con->write)
     297                 :            :                 return -ENODEV;
     298                 :            : 
     299                 :            : 
     300                 :            :         register_console(early_console_dev.con);
     301                 :            :         return 0;
     302                 :            : }
     303                 :            : 
     304                 :            : #endif /* CONFIG_OF_EARLY_FLATTREE */

Generated by: LCOV version 1.14