|
@@ -2,14 +2,14 @@
|
|
|
* Copyright (C) 2012-2014 Panasonic Corporation
|
|
|
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
|
|
|
*
|
|
|
- * Based on serial_ns16550.c
|
|
|
- * (C) Copyright 2000
|
|
|
- * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
|
|
|
- *
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
*/
|
|
|
|
|
|
#include <common.h>
|
|
|
+#include <asm/io.h>
|
|
|
+#include <asm/errno.h>
|
|
|
+#include <dm/device.h>
|
|
|
+#include <dm/platform_data/serial-uniphier.h>
|
|
|
#include <serial.h>
|
|
|
|
|
|
#define UART_REG(x) \
|
|
@@ -48,157 +48,104 @@ struct uniphier_serial {
|
|
|
#define UART_LSR_DR 0x01 /* Data ready */
|
|
|
#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
|
|
|
|
|
|
-DECLARE_GLOBAL_DATA_PTR;
|
|
|
+struct uniphier_serial_private_data {
|
|
|
+ struct uniphier_serial __iomem *membase;
|
|
|
+};
|
|
|
+
|
|
|
+#define uniphier_serial_port(dev) \
|
|
|
+ ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase
|
|
|
|
|
|
-static void uniphier_serial_init(struct uniphier_serial *port)
|
|
|
+int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
|
|
|
{
|
|
|
+ struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
|
|
|
+ struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
|
|
|
const unsigned int mode_x_div = 16;
|
|
|
unsigned int divisor;
|
|
|
|
|
|
writeb(UART_LCR_WLS_8, &port->lcr);
|
|
|
|
|
|
- divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK,
|
|
|
- mode_x_div * gd->baudrate);
|
|
|
+ divisor = DIV_ROUND_CLOSEST(plat->uartclk, mode_x_div * baudrate);
|
|
|
|
|
|
writew(divisor, &port->dlr);
|
|
|
-}
|
|
|
|
|
|
-static void uniphier_serial_setbrg(struct uniphier_serial *port)
|
|
|
-{
|
|
|
- uniphier_serial_init(port);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static int uniphier_serial_tstc(struct uniphier_serial *port)
|
|
|
+static int uniphier_serial_getc(struct udevice *dev)
|
|
|
{
|
|
|
- return (readb(&port->lsr) & UART_LSR_DR) != 0;
|
|
|
-}
|
|
|
+ struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
|
|
|
|
|
|
-static int uniphier_serial_getc(struct uniphier_serial *port)
|
|
|
-{
|
|
|
- while (!uniphier_serial_tstc(port))
|
|
|
- ;
|
|
|
+ if (!(readb(&port->lsr) & UART_LSR_DR))
|
|
|
+ return -EAGAIN;
|
|
|
|
|
|
return readb(&port->rbr);
|
|
|
}
|
|
|
|
|
|
-static void uniphier_serial_putc(struct uniphier_serial *port, const char c)
|
|
|
+static int uniphier_serial_putc(struct udevice *dev, const char c)
|
|
|
{
|
|
|
- if (c == '\n')
|
|
|
- uniphier_serial_putc(port, '\r');
|
|
|
+ struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
|
|
|
|
|
|
- while (!(readb(&port->lsr) & UART_LSR_THRE))
|
|
|
- ;
|
|
|
+ if (!(readb(&port->lsr) & UART_LSR_THRE))
|
|
|
+ return -EAGAIN;
|
|
|
|
|
|
writeb(c, &port->thr);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static struct uniphier_serial *serial_ports[4] = {
|
|
|
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0
|
|
|
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0,
|
|
|
-#else
|
|
|
- NULL,
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1
|
|
|
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1,
|
|
|
-#else
|
|
|
- NULL,
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2
|
|
|
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2,
|
|
|
-#else
|
|
|
- NULL,
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3
|
|
|
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3,
|
|
|
-#else
|
|
|
- NULL,
|
|
|
-#endif
|
|
|
-};
|
|
|
+int uniphier_serial_probe(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct uniphier_serial_private_data *priv = dev_get_priv(dev);
|
|
|
+ struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
|
|
|
|
|
|
-/* Multi serial device functions */
|
|
|
-#define DECLARE_ESERIAL_FUNCTIONS(port) \
|
|
|
- static int eserial##port##_init(void) \
|
|
|
- { \
|
|
|
- uniphier_serial_init(serial_ports[port]); \
|
|
|
- return 0 ; \
|
|
|
- } \
|
|
|
- static void eserial##port##_setbrg(void) \
|
|
|
- { \
|
|
|
- uniphier_serial_setbrg(serial_ports[port]); \
|
|
|
- } \
|
|
|
- static int eserial##port##_getc(void) \
|
|
|
- { \
|
|
|
- return uniphier_serial_getc(serial_ports[port]); \
|
|
|
- } \
|
|
|
- static int eserial##port##_tstc(void) \
|
|
|
- { \
|
|
|
- return uniphier_serial_tstc(serial_ports[port]); \
|
|
|
- } \
|
|
|
- static void eserial##port##_putc(const char c) \
|
|
|
- { \
|
|
|
- uniphier_serial_putc(serial_ports[port], c); \
|
|
|
- }
|
|
|
-
|
|
|
-/* Serial device descriptor */
|
|
|
-#define INIT_ESERIAL_STRUCTURE(port, __name) { \
|
|
|
- .name = __name, \
|
|
|
- .start = eserial##port##_init, \
|
|
|
- .stop = NULL, \
|
|
|
- .setbrg = eserial##port##_setbrg, \
|
|
|
- .getc = eserial##port##_getc, \
|
|
|
- .tstc = eserial##port##_tstc, \
|
|
|
- .putc = eserial##port##_putc, \
|
|
|
- .puts = default_serial_puts, \
|
|
|
-}
|
|
|
+ priv->membase = map_sysmem(plat->base, sizeof(struct uniphier_serial));
|
|
|
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
|
|
|
-DECLARE_ESERIAL_FUNCTIONS(0);
|
|
|
-struct serial_device uniphier_serial0_device =
|
|
|
- INIT_ESERIAL_STRUCTURE(0, "ttyS0");
|
|
|
-#endif
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
|
|
|
-DECLARE_ESERIAL_FUNCTIONS(1);
|
|
|
-struct serial_device uniphier_serial1_device =
|
|
|
- INIT_ESERIAL_STRUCTURE(1, "ttyS1");
|
|
|
-#endif
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
|
|
|
-DECLARE_ESERIAL_FUNCTIONS(2);
|
|
|
-struct serial_device uniphier_serial2_device =
|
|
|
- INIT_ESERIAL_STRUCTURE(2, "ttyS2");
|
|
|
-#endif
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
|
|
|
-DECLARE_ESERIAL_FUNCTIONS(3);
|
|
|
-struct serial_device uniphier_serial3_device =
|
|
|
- INIT_ESERIAL_STRUCTURE(3, "ttyS3");
|
|
|
-#endif
|
|
|
+ if (!priv->membase)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
-__weak struct serial_device *default_serial_console(void)
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int uniphier_serial_remove(struct udevice *dev)
|
|
|
{
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
|
|
|
- return &uniphier_serial0_device;
|
|
|
-#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
|
|
|
- return &uniphier_serial1_device;
|
|
|
-#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
|
|
|
- return &uniphier_serial2_device;
|
|
|
-#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
|
|
|
- return &uniphier_serial3_device;
|
|
|
-#else
|
|
|
-#error "No uniphier serial ports configured."
|
|
|
-#endif
|
|
|
+ unmap_sysmem(uniphier_serial_port(dev));
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void uniphier_serial_initialize(void)
|
|
|
+#ifdef CONFIG_OF_CONTROL
|
|
|
+static const struct udevice_id uniphier_uart_of_match = {
|
|
|
+ { .compatible = "panasonic,uniphier-uart"},
|
|
|
+ {},
|
|
|
+};
|
|
|
+
|
|
|
+static int uniphier_serial_ofdata_to_platdata(struct udevice *dev)
|
|
|
{
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
|
|
|
- serial_register(&uniphier_serial0_device);
|
|
|
-#endif
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
|
|
|
- serial_register(&uniphier_serial1_device);
|
|
|
-#endif
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
|
|
|
- serial_register(&uniphier_serial2_device);
|
|
|
-#endif
|
|
|
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
|
|
|
- serial_register(&uniphier_serial3_device);
|
|
|
-#endif
|
|
|
+ /*
|
|
|
+ * TODO: Masahiro Yamada (yamada.m@jp.panasonic.com)
|
|
|
+ *
|
|
|
+ * Implement conversion code from DTB to platform data
|
|
|
+ * when supporting CONFIG_OF_CONTROL on UniPhir platform.
|
|
|
+ */
|
|
|
}
|
|
|
+#endif
|
|
|
+
|
|
|
+static const struct dm_serial_ops uniphier_serial_ops = {
|
|
|
+ .setbrg = uniphier_serial_setbrg,
|
|
|
+ .getc = uniphier_serial_getc,
|
|
|
+ .putc = uniphier_serial_putc,
|
|
|
+};
|
|
|
+
|
|
|
+U_BOOT_DRIVER(uniphier_serial) = {
|
|
|
+ .name = DRIVER_NAME,
|
|
|
+ .id = UCLASS_SERIAL,
|
|
|
+ .of_match = of_match_ptr(uniphier_uart_of_match),
|
|
|
+ .ofdata_to_platdata = of_match_ptr(uniphier_serial_ofdata_to_platdata),
|
|
|
+ .probe = uniphier_serial_probe,
|
|
|
+ .remove = uniphier_serial_remove,
|
|
|
+ .priv_auto_alloc_size = sizeof(struct uniphier_serial_private_data),
|
|
|
+ .platdata_auto_alloc_size =
|
|
|
+ sizeof(struct uniphier_serial_platform_data),
|
|
|
+ .ops = &uniphier_serial_ops,
|
|
|
+ .flags = DM_FLAG_PRE_RELOC,
|
|
|
+};
|