It is very limited and minimal, only implements putc/puts.
This minimal driver is intended to be used in SPL, and other
size-constrained situations.

Reviewed-by: Neil Armstrong <[email protected]>
Signed-off-by: Ferass El Hafidi <[email protected]>
---
 drivers/serial/serial.c       |   2 +
 drivers/serial/serial_meson.c | 119 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index e10ca6eef76..c0b1eb30561 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -129,6 +129,7 @@ serial_initfunc(pxa_serial_initialize);
 serial_initfunc(smh_serial_initialize);
 serial_initfunc(sh_serial_initialize);
 serial_initfunc(mtk_serial_initialize);
+serial_initfunc(meson_serial_initialize);
 
 /**
  * serial_register() - Register serial driver with serial driver core
@@ -167,6 +168,7 @@ int serial_initialize(void)
        smh_serial_initialize();
        sh_serial_initialize();
        mtk_serial_initialize();
+       meson_serial_initialize();
 
        serial_assign(default_serial_console()->name);
 
diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c
index bb79b972957..cc71381f87e 100644
--- a/drivers/serial/serial_meson.c
+++ b/drivers/serial/serial_meson.c
@@ -3,9 +3,11 @@
  * (C) Copyright 2016 Beniamino Galvani <[email protected]>
  */
 
+#if CONFIG_IS_ENABLED(DM_SERIAL)
 #include <dm.h>
-#include <errno.h>
 #include <fdtdec.h>
+#endif
+#include <errno.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/compiler.h>
@@ -25,6 +27,15 @@ struct meson_serial_plat {
        struct meson_uart *reg;
 };
 
+#if !CONFIG_IS_ENABLED(DM_SERIAL)
+/* UART base address */
+#if defined(CONFIG_MESON_GX)
+#define AML_UART_BASE  0xc81004c0
+#else /* G12A, AXG, ... */
+#define AML_UART_BASE  0xff803000
+#endif
+#endif
+
 /* AML_UART_STATUS bits */
 #define AML_UART_PARITY_ERR            BIT(16)
 #define AML_UART_FRAME_ERR             BIT(17)
@@ -51,6 +62,7 @@ struct meson_serial_plat {
 #define AML_UART_REG5_USE_NEW_BAUD     BIT(23) /* default 1 (use new baud rate 
register) */
 #define AML_UART_REG5_BAUD_MASK                0x7fffff
 
+#if CONFIG_IS_ENABLED(DM_SERIAL)
 static u32 meson_calc_baud_divisor(ulong src_rate, u32 baud)
 {
        /*
@@ -245,6 +257,111 @@ U_BOOT_DRIVER(serial_meson) = {
        .plat_auto      = sizeof(struct meson_serial_plat),
 };
 
+#else
+
+static int meson_serial_init(void)
+{
+       struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE;
+       u32 val;
+
+       val = readl(&uart->control);
+       val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
+       writel(val, &uart->control);
+       val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
+       writel(val, &uart->control);
+       val |= (AML_UART_RX_EN | AML_UART_TX_EN);
+       writel(val, &uart->control);
+
+       return 0;
+}
+
+static int meson_serial_stop(void)
+{
+       return 0;
+}
+
+static void meson_serial_setbrg(void)
+{
+}
+
+static void meson_serial_putc(const char ch)
+{
+       struct meson_uart *uart = (struct meson_uart *)AML_UART_BASE;
+
+       /* On '\n' also do '\r' */
+       if (ch == '\n')
+               meson_serial_putc('\r');
+
+       while (readl(&uart->status) & AML_UART_TX_FULL)
+               ;
+
+       writel(ch, &uart->wfifo);
+}
+
+static void meson_serial_puts(const char *s)
+{
+       while (*s)
+               meson_serial_putc(*s++);
+}
+
+static int meson_serial_getc(void)
+{
+       struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE;
+       uint32_t status = readl(&uart->status);
+
+       if (status & AML_UART_RX_EMPTY)
+               return -EAGAIN;
+
+       if (status & AML_UART_ERR) {
+               u32 val = readl(&uart->control);
+
+               /* Clear error */
+               val |= AML_UART_CLR_ERR;
+               writel(val, &uart->control);
+               val &= ~AML_UART_CLR_ERR;
+               writel(val, &uart->control);
+
+               /* Remove spurious byte from fifo */
+               readl(&uart->rfifo);
+               return -EIO;
+       }
+
+       return readl(&uart->rfifo) & 0xff;
+}
+
+static int meson_serial_tstc(void)
+{
+       struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE;
+       uint32_t status = readl(&uart->status);
+
+       if (status & AML_UART_RX_EMPTY)
+               return 0;
+       return 1;
+}
+
+struct serial_device meson_serial_device = {
+       .name   = "meson_serial",
+       .start  = meson_serial_init,
+       .stop   = meson_serial_stop,
+       .setbrg = meson_serial_setbrg,
+       .getc   = meson_serial_getc,
+       .tstc   = meson_serial_tstc,
+       .putc   = meson_serial_putc,
+       .puts   = meson_serial_puts,
+};
+
+void meson_serial_initialize(void)
+{
+       serial_register(&meson_serial_device);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+       return &meson_serial_device;
+}
+
+#endif
+
 #ifdef CONFIG_DEBUG_UART_MESON
 
 #include <debug_uart.h>

-- 
2.51.2

Reply via email to