]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
serial: serial_meson: add minimal non-DM driver
authorFerass El Hafidi <funderscore@postmarketos.org>
Wed, 26 Nov 2025 12:17:05 +0000 (12:17 +0000)
committerNeil Armstrong <neil.armstrong@linaro.org>
Thu, 11 Dec 2025 10:44:41 +0000 (11:44 +0100)
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 <neil.armstrong@linaro.org>
Signed-off-by: Ferass El Hafidi <funderscore@postmarketos.org>
Link: https://patch.msgid.link/20251126-spl-gx-v5-3-6cbffb2451ca@postmarketos.org
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
drivers/serial/serial.c
drivers/serial/serial_meson.c

index e10ca6eef768502ea32bf39a41ae2e3ccd168c66..c0b1eb3056181b95e1861f1ce08fcd82ff81eb71 100644 (file)
@@ -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);
 
index bb79b9729579a661084425d6b3c5357da31dc3c0..cc71381f87e1e2d192e5f4450f881c2a69511ca3 100644 (file)
@@ -3,9 +3,11 @@
  * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
  */
 
+#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>