[PATCH v5 6/7] lib: utils/serial: Support multiple UART8250 devices
Bo Gan
ganboing at gmail.com
Wed Dec 17 05:29:58 PST 2025
Previously we assume only 1 UART8250 instance can be used. Now we support
multiple instances by introducing counterpart functions to putc/getc/init
which take an extra *dev parameter, and name them as uart8250_device_xyz()
The original functions without the *dev parameter will operate on the
default instance exactly the same as before, so no changes on the caller
is required.
Note: uart8250_device_init only does device initialization without the
console registration logic.
Signed-off-by: Bo Gan <ganboing at gmail.com>
---
include/sbi_utils/serial/uart8250.h | 16 +++++
lib/utils/serial/uart8250.c | 104 ++++++++++++++++------------
2 files changed, 75 insertions(+), 45 deletions(-)
diff --git a/include/sbi_utils/serial/uart8250.h b/include/sbi_utils/serial/uart8250.h
index 70cd2912..78c0e614 100644
--- a/include/sbi_utils/serial/uart8250.h
+++ b/include/sbi_utils/serial/uart8250.h
@@ -14,6 +14,22 @@
#define UART_CAP_UUE BIT(0) /* Check UUE capability for XScale PXA UARTs */
+struct uart8250_device {
+ volatile char *base;
+ u32 in_freq;
+ u32 baudrate;
+ u32 reg_width;
+ u32 reg_shift;
+};
+
+int uart8250_device_getc(struct uart8250_device *dev);
+
+void uart8250_device_putc(struct uart8250_device *dev, char ch);
+
+void uart8250_device_init(struct uart8250_device *dev, unsigned long base,
+ u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width, u32 reg_offset, u32 caps);
+
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width, u32 reg_offset, u32 caps);
diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
index bb209c9a..d65f127d 100644
--- a/lib/utils/serial/uart8250.c
+++ b/lib/utils/serial/uart8250.c
@@ -47,97 +47,111 @@
/* clang-format on */
-static volatile char *uart8250_base;
-static u32 uart8250_in_freq;
-static u32 uart8250_baudrate;
-static u32 uart8250_reg_width;
-static u32 uart8250_reg_shift;
+static struct uart8250_device uart8250_dev;
-static u32 get_reg(u32 num)
+static u32 get_reg(struct uart8250_device *dev, u32 num)
{
- u32 offset = num << uart8250_reg_shift;
+ u32 offset = num << dev->reg_shift;
- if (uart8250_reg_width == 1)
- return readb(uart8250_base + offset);
- else if (uart8250_reg_width == 2)
- return readw(uart8250_base + offset);
+ if (dev->reg_width == 1)
+ return readb(dev->base + offset);
+ else if (dev->reg_width == 2)
+ return readw(dev->base + offset);
else
- return readl(uart8250_base + offset);
+ return readl(dev->base + offset);
}
-static void set_reg(u32 num, u32 val)
+static void set_reg(struct uart8250_device *dev, u32 num, u32 val)
{
- u32 offset = num << uart8250_reg_shift;
+ u32 offset = num << dev->reg_shift;
- if (uart8250_reg_width == 1)
- writeb(val, uart8250_base + offset);
- else if (uart8250_reg_width == 2)
- writew(val, uart8250_base + offset);
+ if (dev->reg_width == 1)
+ writeb(val, dev->base + offset);
+ else if (dev->reg_width == 2)
+ writew(val, dev->base + offset);
else
- writel(val, uart8250_base + offset);
+ writel(val, dev->base + offset);
}
-static void uart8250_putc(char ch)
+void uart8250_device_putc(struct uart8250_device *dev, char ch)
{
- while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
+ while ((get_reg(dev, UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
;
- set_reg(UART_THR_OFFSET, ch);
+ set_reg(dev, UART_THR_OFFSET, ch);
}
-static int uart8250_getc(void)
+static void uart8250_putc(char ch)
{
- if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
- return get_reg(UART_RBR_OFFSET);
+ return uart8250_device_putc(&uart8250_dev, ch);
+}
+
+int uart8250_device_getc(struct uart8250_device *dev)
+{
+ if (get_reg(dev, UART_LSR_OFFSET) & UART_LSR_DR)
+ return get_reg(dev, UART_RBR_OFFSET);
return -1;
}
+static int uart8250_getc(void)
+{
+ return uart8250_device_getc(&uart8250_dev);
+}
+
static struct sbi_console_device uart8250_console = {
.name = "uart8250",
.console_putc = uart8250_putc,
.console_getc = uart8250_getc
};
-int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
- u32 reg_width, u32 reg_offset, u32 caps)
+void uart8250_device_init(struct uart8250_device *dev, unsigned long base,
+ u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width, u32 reg_offset, u32 caps)
{
u16 bdiv = 0;
- uart8250_base = (volatile char *)base + reg_offset;
- uart8250_reg_shift = reg_shift;
- uart8250_reg_width = reg_width;
- uart8250_in_freq = in_freq;
- uart8250_baudrate = baudrate;
+ dev->base = (volatile char *)base + reg_offset;
+ dev->reg_shift = reg_shift;
+ dev->reg_width = reg_width;
+ dev->in_freq = in_freq;
+ dev->baudrate = baudrate;
- if (uart8250_baudrate) {
- bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) /
- (16 * uart8250_baudrate);
+ if (dev->baudrate) {
+ bdiv = (dev->in_freq + 8 * dev->baudrate) /
+ (16 * dev->baudrate);
}
/* Disable all interrupts */
- set_reg(UART_IER_OFFSET, (caps & UART_CAP_UUE) ?
+ set_reg(dev, UART_IER_OFFSET, (caps & UART_CAP_UUE) ?
UART_IER_UUE : 0x00);
/* Enable DLAB */
- set_reg(UART_LCR_OFFSET, 0x80);
+ set_reg(dev, UART_LCR_OFFSET, 0x80);
if (bdiv) {
/* Set divisor low byte */
- set_reg(UART_DLL_OFFSET, bdiv & 0xff);
+ set_reg(dev, UART_DLL_OFFSET, bdiv & 0xff);
/* Set divisor high byte */
- set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
+ set_reg(dev, UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
}
/* 8 bits, no parity, one stop bit */
- set_reg(UART_LCR_OFFSET, 0x03);
+ set_reg(dev, UART_LCR_OFFSET, 0x03);
/* Enable FIFO */
- set_reg(UART_FCR_OFFSET, 0x01);
+ set_reg(dev, UART_FCR_OFFSET, 0x01);
/* No modem control DTR RTS */
- set_reg(UART_MCR_OFFSET, 0x00);
+ set_reg(dev, UART_MCR_OFFSET, 0x00);
/* Clear line status and read receive buffer */
- if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
- get_reg(UART_RBR_OFFSET);
+ if (get_reg(dev, UART_LSR_OFFSET) & UART_LSR_DR)
+ get_reg(dev, UART_RBR_OFFSET);
/* Set scratchpad */
- set_reg(UART_SCR_OFFSET, 0x00);
+ set_reg(dev, UART_SCR_OFFSET, 0x00);
+}
+
+int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width, u32 reg_offset, u32 caps)
+{
+ uart8250_device_init(&uart8250_dev, base, in_freq, baudrate,
+ reg_shift, reg_width, reg_offset, caps);
sbi_console_set_device(&uart8250_console);
--
2.34.1
More information about the opensbi
mailing list