From: Kwanghoon Son <asdfkwang@gmail.com>
To: opensbi@lists.infradead.org
Cc: Anup Patel <anup@brainfault.org>, Kwanghoon Son <asdfkwang@gmail.com>
Subject: [PATCH] lib: utils/serial: Add Bouffalo Lab BL808 UART driver
Date: Wed, 21 Oct 2026 07:50:17 -0400 [thread overview]
Message-ID: <20261021115017.19344-1-asdfkwang@gmail.com> (raw)
Add a polling UART driver for the Bouffalo Lab BL808 SoC and its
FDT frontend, matching bflb,bl808-uart. Read the register base, input
clock and baud rate from the device tree and register the SBI console.
The preceding firmware must enable the UART input clock and configure
the pinmux before entering OpenSBI. The driver only configures the UART
peripheral; it does not change SoC clocks or board pin routing.
Signed-off-by: Kwanghoon Son <asdfkwang@gmail.com>
---
The BL808 is also used on the PINE64 Ox64 [1]. Zephyr already provides
a Bouffalo Lab UART driver using the "bflb,uart" compatible [2], and
supports the M1S Dock's E907 core [3].
This patch provides a polling UART console driver for OpenSBI.
Testing was performed on the Sipeed M1s Dock's C906 D0 core using
UART3 at 2 Mbaud, with the input clock and pinmux configured by
the preceding firmware.
The FDT frontend currently requires reg, clock-frequency and
current-speed. This patch does not add board initialization or
T-Head PMU support.
Validation:
- RV32 and RV64 cross-builds passed with the driver enabled.
- UART output through the OpenSBI banner and handoff to S-mode
U-Boot was verified on the UART-only implementation.
- The board-tested revision was 6b317b61. The submitted revision
differs only by leaving the driver disabled in generic defconfig;
the UART driver sources are unchanged.
- UART RX, operation on the Ox64, and repeated cold boots remain
untested.
[1] https://pine64.org/documentation/Ox64/
[2] https://docs.zephyrproject.org/latest/build/dts/api/bindings/serial/bflb,uart.html
[3] https://docs.zephyrproject.org/latest/boards/sipeed/m1s_dock/doc/index.html
include/sbi_utils/serial/bl808-uart.h | 11 +++
lib/utils/serial/Kconfig | 9 +++
lib/utils/serial/bl808-uart.c | 107 ++++++++++++++++++++++++++
lib/utils/serial/fdt_serial_bl808.c | 44 +++++++++++
lib/utils/serial/objects.mk | 4 +
5 files changed, 175 insertions(+)
create mode 100644 include/sbi_utils/serial/bl808-uart.h
create mode 100644 lib/utils/serial/bl808-uart.c
create mode 100644 lib/utils/serial/fdt_serial_bl808.c
diff --git a/include/sbi_utils/serial/bl808-uart.h b/include/sbi_utils/serial/bl808-uart.h
new file mode 100644
index 00000000..aa6281db
--- /dev/null
+++ b/include/sbi_utils/serial/bl808-uart.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+#ifndef __SERIAL_BL808_UART_H__
+#define __SERIAL_BL808_UART_H__
+
+#include <sbi/sbi_types.h>
+
+/* The caller must enable the input clock and configure the pinmux. */
+int bl808_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
+
+#endif
diff --git a/lib/utils/serial/Kconfig b/lib/utils/serial/Kconfig
index 21619d0d..15ede441 100644
--- a/lib/utils/serial/Kconfig
+++ b/lib/utils/serial/Kconfig
@@ -14,6 +14,11 @@ config FDT_SERIAL_ALTR_JUART
select SERIAL_ALTR_JUART
default n
+config FDT_SERIAL_BL808
+ bool "Bouffalo Lab BL808 UART FDT driver"
+ select SERIAL_BL808
+ default n
+
config FDT_SERIAL_CADENCE
bool "Cadence UART FDT driver"
select SERIAL_CADENCE
@@ -65,6 +70,10 @@ config SERIAL_ALTR_JUART
bool "Altera JTAG UART support"
default n
+config SERIAL_BL808
+ bool "Bouffalo Lab BL808 UART support"
+ default n
+
config SERIAL_CADENCE
bool "Cadence UART support"
default n
diff --git a/lib/utils/serial/bl808-uart.c b/lib/utils/serial/bl808-uart.c
new file mode 100644
index 00000000..e1f1ffbf
--- /dev/null
+++ b/lib/utils/serial/bl808-uart.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: BSD-2-Clause
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_error.h>
+#include <sbi_utils/serial/bl808-uart.h>
+
+#define UART_TX_CONFIG 0x00
+#define UART_RX_CONFIG 0x04
+#define UART_BIT_PERIOD 0x08
+#define UART_DATA_CONFIG 0x0c
+#define UART_SW_MODE 0x1c
+#define UART_INT_MASK 0x24
+#define UART_INT_CLEAR 0x28
+#define UART_INT_ENABLE 0x2c
+#define UART_FIFO_CONFIG0 0x80
+#define UART_FIFO_CONFIG1 0x84
+#define UART_FIFO_WDATA 0x88
+#define UART_FIFO_RDATA 0x8c
+
+#define UART_TX_ENABLE BIT(0)
+#define UART_RX_ENABLE BIT(0)
+#define UART_TX_FREE_RUN BIT(2)
+#define UART_TX_DATA_BITS (7 << 8)
+#define UART_TX_STOP_BITS BIT(11)
+#define UART_RX_DATA_BITS (7 << 8)
+#define UART_INT_MASK_ALL 0xfff
+#define UART_INT_CLEAR_ALL 0xf33
+#define UART_TX_FIFO_CLEAR BIT(2)
+#define UART_RX_FIFO_CLEAR BIT(3)
+#define UART_TX_FIFO_COUNT 0x3f
+#define UART_RX_FIFO_COUNT (0x3f << 8)
+
+static volatile void *uart_base;
+
+static void bl808_uart_putc(char ch)
+{
+ while (!(readl(uart_base + UART_FIFO_CONFIG1) & UART_TX_FIFO_COUNT))
+ ;
+
+ writeb(ch, uart_base + UART_FIFO_WDATA);
+}
+
+static int bl808_uart_getc(void)
+{
+ if (!(readl(uart_base + UART_FIFO_CONFIG1) & UART_RX_FIFO_COUNT))
+ return -1;
+
+ return readb(uart_base + UART_FIFO_RDATA);
+}
+
+static struct sbi_console_device bl808_console = {
+ .name = "bl808_uart",
+ .console_putc = bl808_uart_putc,
+ .console_getc = bl808_uart_getc,
+};
+
+int bl808_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
+{
+ u64 divisor;
+ u32 period;
+ int rc;
+
+ if (!base || (base & 3) || base > -1UL - PAGE_SIZE ||
+ !in_freq || !baudrate)
+ return SBI_EINVAL;
+
+ divisor = ((u64)in_freq + baudrate / 2) / baudrate;
+ if (!divisor || divisor > 0x10000)
+ return SBI_EINVAL;
+
+ rc = sbi_domain_root_add_memrange(base, PAGE_SIZE, PAGE_SIZE,
+ (SBI_DOMAIN_MEMREGION_MMIO |
+ SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW));
+ if (rc)
+ return rc;
+
+ uart_base = (void *)base;
+ writel(0, uart_base + UART_TX_CONFIG);
+ writel(0, uart_base + UART_RX_CONFIG);
+
+ /* The TX and RX period fields both encode divisor minus one. */
+ period = divisor - 1;
+ writel(period | (period << 16), uart_base + UART_BIT_PERIOD);
+ writel(UART_TX_FREE_RUN | UART_TX_DATA_BITS | UART_TX_STOP_BITS,
+ uart_base + UART_TX_CONFIG);
+ writel(UART_RX_DATA_BITS, uart_base + UART_RX_CONFIG);
+ writel(0, uart_base + UART_DATA_CONFIG);
+ writel(0, uart_base + UART_SW_MODE);
+
+ /* Polling only: mask interrupts, disable DMA, and clear both FIFOs. */
+ writel(UART_INT_MASK_ALL, uart_base + UART_INT_MASK);
+ writel(0, uart_base + UART_INT_ENABLE);
+ writel(UART_INT_CLEAR_ALL, uart_base + UART_INT_CLEAR);
+ writel(UART_TX_FIFO_CLEAR | UART_RX_FIFO_CLEAR,
+ uart_base + UART_FIFO_CONFIG0);
+ writel(0, uart_base + UART_FIFO_CONFIG1);
+
+ writel(UART_TX_FREE_RUN | UART_TX_DATA_BITS | UART_TX_STOP_BITS |
+ UART_TX_ENABLE, uart_base + UART_TX_CONFIG);
+ writel(UART_RX_DATA_BITS | UART_RX_ENABLE, uart_base + UART_RX_CONFIG);
+
+ sbi_console_set_device(&bl808_console);
+
+ return 0;
+}
diff --git a/lib/utils/serial/fdt_serial_bl808.c b/lib/utils/serial/fdt_serial_bl808.c
new file mode 100644
index 00000000..99e19bae
--- /dev/null
+++ b/lib/utils/serial/fdt_serial_bl808.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: BSD-2-Clause
+
+#include <libfdt.h>
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/bl808-uart.h>
+#include <sbi_utils/serial/fdt_serial.h>
+
+static int serial_bl808_init(const void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ const fdt32_t *val;
+ u64 addr, size;
+ u32 freq, baud;
+ int len, rc;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, &size);
+ if (rc)
+ return rc;
+ if (size < 0x90 || addr != (unsigned long)addr)
+ return SBI_EINVAL;
+
+ val = fdt_getprop(fdt, nodeoff, "clock-frequency", &len);
+ if (!val || len != sizeof(*val))
+ return SBI_EINVAL;
+ freq = fdt32_to_cpu(*val);
+
+ val = fdt_getprop(fdt, nodeoff, "current-speed", &len);
+ if (!val || len != sizeof(*val))
+ return SBI_EINVAL;
+ baud = fdt32_to_cpu(*val);
+
+ return bl808_uart_init(addr, freq, baud);
+}
+
+static const struct fdt_match serial_bl808_match[] = {
+ { .compatible = "bflb,bl808-uart" },
+ { },
+};
+
+const struct fdt_driver fdt_serial_bl808 = {
+ .match_table = serial_bl808_match,
+ .init = serial_bl808_init,
+};
diff --git a/lib/utils/serial/objects.mk b/lib/utils/serial/objects.mk
index 94cf3a4b..d8659602 100644
--- a/lib/utils/serial/objects.mk
+++ b/lib/utils/serial/objects.mk
@@ -13,6 +13,9 @@ libsbiutils-objs-$(CONFIG_FDT_SERIAL) += serial/fdt_serial_drivers.carray.o
carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_ALTR_JUART) += fdt_serial_altr_juart
libsbiutils-objs-$(CONFIG_FDT_SERIAL_ALTR_JUART) += serial/fdt_serial_altr_juart.o
+carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_BL808) += fdt_serial_bl808
+libsbiutils-objs-$(CONFIG_FDT_SERIAL_BL808) += serial/fdt_serial_bl808.o
+
carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_CADENCE) += fdt_serial_cadence
libsbiutils-objs-$(CONFIG_FDT_SERIAL_CADENCE) += serial/fdt_serial_cadence.o
@@ -41,6 +44,7 @@ carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_XILINX_UARTLITE) += fdt_serial_xln
libsbiutils-objs-$(CONFIG_FDT_SERIAL_XILINX_UARTLITE) += serial/fdt_serial_xlnx_uartlite.o
libsbiutils-objs-$(CONFIG_SERIAL_ALTR_JUART) += serial/altr-juart.o
+libsbiutils-objs-$(CONFIG_SERIAL_BL808) += serial/bl808-uart.o
libsbiutils-objs-$(CONFIG_SERIAL_CADENCE) += serial/cadence-uart.o
libsbiutils-objs-$(CONFIG_SERIAL_GAISLER) += serial/gaisler-uart.o
libsbiutils-objs-$(CONFIG_SERIAL_RENESAS_SCIF) += serial/renesas_scif.o
base-commit: 6ad246a1494807ee91e36ffcf60e4c30bb309d45
--
2.47.3
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
reply other threads:[~2026-10-21 11:50 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261021115017.19344-1-asdfkwang@gmail.com \
--to=asdfkwang@gmail.com \
--cc=anup@brainfault.org \
--cc=opensbi@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox