serial: earlycon: Enable earlycon without command line param
[cascardo/linux.git] / drivers / tty / serial / earlycon.c
index 9fb76b6..5fdc9f3 100644 (file)
@@ -10,6 +10,9 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/console.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -34,6 +37,10 @@ static struct earlycon_device early_console_dev = {
        .con = &early_con,
 };
 
+extern struct earlycon_id __earlycon_table[];
+static const struct earlycon_id __earlycon_table_sentinel
+       __used __section(__earlycon_table_end);
+
 static const struct of_device_id __earlycon_of_table_sentinel
        __used __section(__earlycon_of_table_end);
 
@@ -96,9 +103,7 @@ static int __init parse_options(struct earlycon_device *device, char *options)
        return 0;
 }
 
-
-static int __init
-register_earlycon(char *buf, int (*setup)(struct earlycon_device *, const char *))
+static int __init register_earlycon(char *buf, const struct earlycon_id *match)
 {
        int err;
        struct uart_port *port = &early_console_dev.port;
@@ -112,7 +117,7 @@ register_earlycon(char *buf, int (*setup)(struct earlycon_device *, const char *
                port->membase = earlycon_map(port->mapbase, 64);
 
        early_console_dev.con->data = &early_console_dev;
-       err = setup(&early_console_dev, buf);
+       err = match->setup(&early_console_dev, buf);
        if (err < 0)
                return err;
        if (!early_console_dev.con->write)
@@ -122,27 +127,76 @@ register_earlycon(char *buf, int (*setup)(struct earlycon_device *, const char *
        return 0;
 }
 
-int __init setup_earlycon(char *buf, const char *match,
-                         int (*setup)(struct earlycon_device *, const char *))
+/**
+ *     setup_earlycon - match and register earlycon console
+ *     @buf:   earlycon param string
+ *
+ *     Registers the earlycon console matching the earlycon specified
+ *     in the param string @buf. Acceptable param strings are of the form
+ *        <name>,io|mmio|mmio32,<addr>,<options>
+ *        <name>,0x<addr>,<options>
+ *        <name>,<options>
+ *        <name>
+ *
+ *     Only for the third form does the earlycon setup() method receive the
+ *     <options> string in the 'options' parameter; all other forms set
+ *     the parameter to NULL.
+ *
+ *     Returns 0 if an attempt to register the earlycon was made,
+ *     otherwise negative error code
+ */
+int __init setup_earlycon(char *buf)
 {
-       size_t len;
+       const struct earlycon_id *match;
 
-       if (!buf || !match || !setup)
-               return 0;
+       if (!buf || !buf[0])
+               return -EINVAL;
 
-       len = strlen(match);
-       if (strncmp(buf, match, len))
-               return 0;
+       if (early_con.flags & CON_ENABLED)
+               return -EALREADY;
 
-       if (buf[len]) {
-               if (buf[len] != ',')
-                       return 0;
-               buf += len + 1;
-       } else
-               buf = NULL;
+       for (match = __earlycon_table; match->name[0]; match++) {
+               size_t len = strlen(match->name);
 
-       return register_earlycon(buf, setup);
+               if (strncmp(buf, match->name, len))
+                       continue;
+
+               if (buf[len]) {
+                       if (buf[len] != ',')
+                               continue;
+                       buf += len + 1;
+               } else
+                       buf = NULL;
+
+               return register_earlycon(buf, match);
+       }
+
+       return -ENOENT;
+}
+
+/* early_param wrapper for setup_earlycon() */
+static int __init param_setup_earlycon(char *buf)
+{
+       int err;
+
+       /*
+        * Just 'earlycon' is a valid param for devicetree earlycons;
+        * don't generate a warning from parse_early_params() in that case
+        */
+       if (!buf || !buf[0])
+               return 0;
+
+       err = setup_earlycon(buf);
+       if (err == -ENOENT) {
+               pr_warn("no match for %s\n", buf);
+               err = 0;
+       } else if (err == -EALREADY) {
+               pr_warn("already registered\n");
+               err = 0;
+       }
+       return err;
 }
+early_param("earlycon", param_setup_earlycon);
 
 int __init of_setup_earlycon(unsigned long addr,
                             int (*setup)(struct earlycon_device *, const char *))