+// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000
* Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
* (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
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;
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, ®s->pl011_ibrd);
- writel(fraction, ®s->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, ®s->pl011_ibrd);
+ writel(fraction, ®s->pl011_fbrd);
+ }
pl011_set_line_control(regs);
/* Finally, enable the UART */
{
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
#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);
{}
};
-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
.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
{
#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,
{
struct pl01x_regs *regs = (struct pl01x_regs *)CONFIG_DEBUG_UART_BASE;
- pl01x_putc(regs, ch);
+ while (pl01x_putc(regs, ch) == -EAGAIN)
+ ;
}
DEBUG_UART_FUNCS