dt-bindings: pinctrl: k3: Synchronize with v5.14 kernel
[platform/kernel/u-boot.git] / drivers / serial / serial_pl01x.c
index 552c945..67caa06 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2000
  * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
@@ -5,30 +6,32 @@
  * (C) Copyright 2004
  * ARM Ltd.
  * Philippe Robin, <philippe.robin@arm.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 /* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */
 
 #include <common.h>
+#include <asm/global_data.h>
+/* For get_bus_freq() */
+#include <clock_legacy.h>
 #include <dm.h>
+#include <clk.h>
 #include <errno.h>
 #include <watchdog.h>
 #include <asm/io.h>
 #include <serial.h>
+#include <dm/device_compat.h>
 #include <dm/platform_data/serial_pl01x.h>
 #include <linux/compiler.h>
 #include "serial_pl01x_internal.h"
-#include <fdtdec.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifndef CONFIG_DM_SERIAL
 
 static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS;
-static enum pl01x_type pl01x_type __attribute__ ((section(".data")));
-static struct pl01x_regs *base_regs __attribute__ ((section(".data")));
+static enum pl01x_type pl01x_type __section(".data");
+static struct pl01x_regs *base_regs __section(".data");
 #define NUM_PORTS (sizeof(port)/sizeof(port[0]))
 
 #endif
@@ -117,7 +120,7 @@ static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type,
                        divisor = UART_PL010_BAUD_9600;
                        break;
                case 19200:
-                       divisor = UART_PL010_BAUD_9600;
+                       divisor = UART_PL010_BAUD_19200;
                        break;
                case 38400:
                        divisor = UART_PL010_BAUD_38400;
@@ -151,21 +154,24 @@ static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type,
                unsigned int remainder;
                unsigned int fraction;
 
-               /*
-               * Set baud rate
-               *
-               * IBRD = UART_CLK / (16 * BAUD_RATE)
-               * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE)))
-               *               / (16 * BAUD_RATE))
-               */
-               temp = 16 * baudrate;
-               divider = clock / temp;
-               remainder = clock % temp;
-               temp = (8 * remainder) / baudrate;
-               fraction = (temp >> 1) + (temp & 1);
-
-               writel(divider, &regs->pl011_ibrd);
-               writel(fraction, &regs->pl011_fbrd);
+               /* Without a valid clock rate we cannot set up the baudrate. */
+               if (clock) {
+                       /*
+                        * Set baud rate
+                        *
+                        * IBRD = UART_CLK / (16 * BAUD_RATE)
+                        * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE)))
+                        *              / (16 * BAUD_RATE))
+                        */
+                       temp = 16 * baudrate;
+                       divider = clock / temp;
+                       remainder = clock % temp;
+                       temp = (8 * remainder) / baudrate;
+                       fraction = (temp >> 1) + (temp & 1);
+
+                       writel(divider, &regs->pl011_ibrd);
+                       writel(fraction, &regs->pl011_fbrd);
+               }
 
                pl011_set_line_control(regs);
                /* Finally, enable the UART */
@@ -185,9 +191,7 @@ static void pl01x_serial_init_baud(int baudrate)
 {
        int clock = 0;
 
-#if defined(CONFIG_PL010_SERIAL)
-       pl01x_type = TYPE_PL010;
-#elif defined(CONFIG_PL011_SERIAL)
+#if defined(CONFIG_PL011_SERIAL)
        pl01x_type = TYPE_PL011;
        clock = CONFIG_PL011_CLOCK;
 #endif
@@ -274,46 +278,47 @@ __weak struct serial_device *default_serial_console(void)
 
 #ifdef CONFIG_DM_SERIAL
 
-struct pl01x_priv {
-       struct pl01x_regs *regs;
-       enum pl01x_type type;
-};
-
-static int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
+int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
 {
-       struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
+       struct pl01x_serial_plat *plat = dev_get_plat(dev);
        struct pl01x_priv *priv = dev_get_priv(dev);
 
-       pl01x_generic_setbrg(priv->regs, priv->type, plat->clock, baudrate);
+       if (!plat->skip_init) {
+               pl01x_generic_setbrg(priv->regs, priv->type, plat->clock,
+                                    baudrate);
+       }
 
        return 0;
 }
 
-static int pl01x_serial_probe(struct udevice *dev)
+int pl01x_serial_probe(struct udevice *dev)
 {
-       struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
+       struct pl01x_serial_plat *plat = dev_get_plat(dev);
        struct pl01x_priv *priv = dev_get_priv(dev);
 
        priv->regs = (struct pl01x_regs *)plat->base;
        priv->type = plat->type;
-       return pl01x_generic_serial_init(priv->regs, priv->type);
+       if (!plat->skip_init)
+               return pl01x_generic_serial_init(priv->regs, priv->type);
+       else
+               return 0;
 }
 
-static int pl01x_serial_getc(struct udevice *dev)
+int pl01x_serial_getc(struct udevice *dev)
 {
        struct pl01x_priv *priv = dev_get_priv(dev);
 
        return pl01x_getc(priv->regs);
 }
 
-static int pl01x_serial_putc(struct udevice *dev, const char ch)
+int pl01x_serial_putc(struct udevice *dev, const char ch)
 {
        struct pl01x_priv *priv = dev_get_priv(dev);
 
        return pl01x_putc(priv->regs, ch);
 }
 
-static int pl01x_serial_pending(struct udevice *dev, bool input)
+int pl01x_serial_pending(struct udevice *dev, bool input)
 {
        struct pl01x_priv *priv = dev_get_priv(dev);
        unsigned int fr = readl(&priv->regs->fr);
@@ -338,18 +343,41 @@ static const struct udevice_id pl01x_serial_id[] ={
        {}
 };
 
-static int pl01x_serial_ofdata_to_platdata(struct udevice *dev)
+#ifndef CONFIG_PL011_CLOCK
+#define CONFIG_PL011_CLOCK 0
+#endif
+
+int pl01x_serial_of_to_plat(struct udevice *dev)
 {
-       struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
+       struct pl01x_serial_plat *plat = dev_get_plat(dev);
+       struct clk clk;
        fdt_addr_t addr;
+       int ret;
 
-       addr = dev_get_addr(dev);
+       addr = dev_read_addr(dev);
        if (addr == FDT_ADDR_T_NONE)
                return -EINVAL;
 
        plat->base = addr;
-       plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "clock", 1);
+       plat->clock = dev_read_u32_default(dev, "clock", CONFIG_PL011_CLOCK);
+       ret = clk_get_by_index(dev, 0, &clk);
+       if (!ret) {
+               ret = clk_enable(&clk);
+               if (ret && ret != -ENOSYS) {
+                       dev_err(dev, "failed to enable clock\n");
+                       return ret;
+               }
+
+               plat->clock = clk_get_rate(&clk);
+               if (IS_ERR_VALUE(plat->clock)) {
+                       dev_err(dev, "failed to get rate\n");
+                       return plat->clock;
+               }
+               debug("%s: CLK %d\n", __func__, plat->clock);
+       }
        plat->type = dev_get_driver_data(dev);
+       plat->skip_init = dev_read_bool(dev, "skip-init");
+
        return 0;
 }
 #endif
@@ -358,12 +386,12 @@ U_BOOT_DRIVER(serial_pl01x) = {
        .name   = "serial_pl01x",
        .id     = UCLASS_SERIAL,
        .of_match = of_match_ptr(pl01x_serial_id),
-       .ofdata_to_platdata = of_match_ptr(pl01x_serial_ofdata_to_platdata),
-       .platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
+       .of_to_plat = of_match_ptr(pl01x_serial_of_to_plat),
+       .plat_auto      = sizeof(struct pl01x_serial_plat),
        .probe = pl01x_serial_probe,
        .ops    = &pl01x_serial_ops,
        .flags = DM_FLAG_PRE_RELOC,
-       .priv_auto_alloc_size = sizeof(struct pl01x_priv),
+       .priv_auto      = sizeof(struct pl01x_priv),
 };
 
 #endif
@@ -376,8 +404,12 @@ static void _debug_uart_init(void)
 {
 #ifndef CONFIG_DEBUG_UART_SKIP_INIT
        struct pl01x_regs *regs = (struct pl01x_regs *)CONFIG_DEBUG_UART_BASE;
-       enum pl01x_type type = CONFIG_IS_ENABLED(DEBUG_UART_PL011) ?
-                               TYPE_PL011 : TYPE_PL010;
+       enum pl01x_type type;
+
+       if (IS_ENABLED(CONFIG_DEBUG_UART_PL011))
+               type = TYPE_PL011;
+       else
+               type = TYPE_PL010;
 
        pl01x_generic_serial_init(regs, type);
        pl01x_generic_setbrg(regs, type,
@@ -389,7 +421,8 @@ static inline void _debug_uart_putc(int ch)
 {
        struct pl01x_regs *regs = (struct pl01x_regs *)CONFIG_DEBUG_UART_BASE;
 
-       pl01x_putc(regs, ch);
+       while (pl01x_putc(regs, ch) == -EAGAIN)
+               ;
 }
 
 DEBUG_UART_FUNCS