of: earlycon: Initialize port fields from DT properties
authorPeter Hurley <peter@hurleysoftware.com>
Sat, 16 Jan 2016 23:23:43 +0000 (15:23 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 7 Feb 2016 06:07:37 +0000 (22:07 -0800)
Read the optional "reg-offset", "reg-shift", "reg-io-width" and endianness
properties and initialize the respective struct uart_port field if found.

NB: These bindings are common to several drivers and the values merely
indicate the default value; the registering earlycon setup() method can
simply override the values if required.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/of/fdt.c
drivers/tty/serial/earlycon.c
include/linux/serial_core.h

index cfd3b35e8d81fe6ed5bd2839942ef72f6365b866..e8fd54a30802f5b0a810b4bf7fff010332e9a75e 100644 (file)
@@ -839,7 +839,7 @@ static int __init early_init_dt_scan_chosen_serial(void)
                if (addr == OF_BAD_ADDR)
                        return -ENXIO;
 
-               of_setup_earlycon(addr, match, options);
+               of_setup_earlycon(addr, match, offset, options);
                return 0;
        }
        return -ENODEV;
index 7509ee34de28d5c05ab383bd41d0cba57d37574d..7089667bde93c47fb39c07f07a95a38f8ed32aaf 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/serial_core.h>
 #include <linux/sizes.h>
+#include <linux/of_fdt.h>
 
 #ifdef CONFIG_FIX_EARLYCON_MEM
 #include <asm/fixmap.h>
@@ -219,10 +220,13 @@ early_param("earlycon", param_setup_earlycon);
 
 int __init of_setup_earlycon(unsigned long addr,
                             const struct earlycon_id *match,
+                            unsigned long node,
                             const char *options)
 {
        int err;
        struct uart_port *port = &early_console_dev.port;
+       const __be32 *val;
+       bool big_endian;
 
        spin_lock_init(&port->lock);
        port->iotype = UPIO_MEM;
@@ -230,6 +234,33 @@ int __init of_setup_earlycon(unsigned long addr,
        port->uartclk = BASE_BAUD * 16;
        port->membase = earlycon_map(addr, SZ_4K);
 
+       val = of_get_flat_dt_prop(node, "reg-offset", NULL);
+       if (val)
+               port->mapbase += be32_to_cpu(*val);
+       val = of_get_flat_dt_prop(node, "reg-shift", NULL);
+       if (val)
+               port->regshift = be32_to_cpu(*val);
+       big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
+               (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
+                of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
+       val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
+       if (val) {
+               switch (be32_to_cpu(*val)) {
+               case 1:
+                       port->iotype = UPIO_MEM;
+                       break;
+               case 2:
+                       port->iotype = UPIO_MEM16;
+                       break;
+               case 4:
+                       port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
+                       break;
+               default:
+                       pr_warn("[%s] unsupported reg-io-width\n", match->name);
+                       return -EINVAL;
+               }
+       }
+
        if (options) {
                strlcpy(early_console_dev.options, options,
                        sizeof(early_console_dev.options));
index 62a4df05eaca3550ef993071f9b9d982c6ca12fd..6d1bed821181e0bfc6d5c0fc3ed996669b398d95 100644 (file)
@@ -360,6 +360,7 @@ extern const struct earlycon_id __earlycon_table_end[];
 
 extern int setup_earlycon(char *buf);
 extern int of_setup_earlycon(unsigned long addr, const struct earlycon_id *match,
+                            unsigned long node,
                             const char *options);
 
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,