[PATCH] lib: utils/serial: Improved 8250 driver
Xiang W
wxjstz at 126.com
Fri May 31 08:33:18 PDT 2024
The previous 8250 driver can only be used as a console. On some
platforms, there are multiple 8250s, one of which is used as a
console, and another may be used to communicate with the MCU to
perform some operations, such as power management, obtaining
motherboard information, etc.
Signed-off-by: Xiang W <wxjstz at 126.com>
---
include/sbi_utils/serial/uart8250.h | 17 +++-
lib/utils/serial/fdt_serial_uart8250.c | 2 +-
lib/utils/serial/uart8250.c | 108 ++++++++++++++-----------
platform/fpga/ariane/platform.c | 2 +-
platform/fpga/openpiton/platform.c | 2 +-
platform/template/platform.c | 2 +-
6 files changed, 79 insertions(+), 54 deletions(-)
diff --git a/include/sbi_utils/serial/uart8250.h b/include/sbi_utils/serial/uart8250.h
index d4a8c13..be9483a 100644
--- a/include/sbi_utils/serial/uart8250.h
+++ b/include/sbi_utils/serial/uart8250.h
@@ -12,7 +12,20 @@
#include <sbi/sbi_types.h>
-int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
- u32 reg_width, u32 reg_offset);
+struct uart8250_device {
+ volatile char * base;
+ u32 in_freq;
+ u32 baudrate;
+ u32 reg_shift;
+ u32 reg_width;
+};
+
+void uart8250_putc(struct uart8250_device *dev, char ch);
+int uart8250_getc(struct uart8250_device *dev);
+int uart8250_init(struct uart8250_device * dev, unsigned long base, u32 in_freq,
+ u32 baudrate, u32 reg_shift, u32 reg_width, u32 reg_offset);
+
+int uart8250_console_init(unsigned long base, u32 in_freq, u32 baudrate,
+ u32 reg_shift, u32 reg_width, u32 reg_offset);
#endif
diff --git a/lib/utils/serial/fdt_serial_uart8250.c b/lib/utils/serial/fdt_serial_uart8250.c
index 7b5d6a4..182bfaf 100644
--- a/lib/utils/serial/fdt_serial_uart8250.c
+++ b/lib/utils/serial/fdt_serial_uart8250.c
@@ -21,7 +21,7 @@ static int serial_uart8250_init(void *fdt, int nodeoff,
if (rc)
return rc;
- return uart8250_init(uart.addr, uart.freq, uart.baud,
+ return uart8250_console_init(uart.addr, uart.freq, uart.baud,
uart.reg_shift, uart.reg_io_width,
uart.reg_offset);
}
diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
index 1fe053f..db35ec3 100644
--- a/lib/utils/serial/uart8250.c
+++ b/lib/utils/serial/uart8250.c
@@ -41,97 +41,109 @@
/* 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 console_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_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)
+int uart8250_getc(struct uart8250_device *dev)
{
- if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
- return get_reg(UART_RBR_OFFSET);
+ if (get_reg(dev, UART_LSR_OFFSET) & UART_LSR_DR)
+ return get_reg(dev, UART_RBR_OFFSET);
return -1;
}
+static void uart8250_console_putc(char ch)
+{
+ uart8250_putc(&console_dev, ch);
+}
+
+static int uart8250_console_getc(void)
+{
+ return uart8250_getc(&console_dev);
+}
+
static struct sbi_console_device uart8250_console = {
.name = "uart8250",
- .console_putc = uart8250_putc,
- .console_getc = uart8250_getc
+ .console_putc = uart8250_console_putc,
+ .console_getc = uart8250_console_getc
};
-int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
- u32 reg_width, u32 reg_offset)
+int uart8250_init(struct uart8250_device * dev, unsigned long base, u32 in_freq,
+ u32 baudrate, u32 reg_shift, u32 reg_width, u32 reg_offset)
{
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 (baudrate)
+ bdiv = (in_freq + 8 * baudrate) / (16 * baudrate);
/* Disable all interrupts */
- set_reg(UART_IER_OFFSET, 0x00);
+ set_reg(dev, UART_IER_OFFSET, 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 */
- get_reg(UART_LSR_OFFSET);
+ get_reg(dev, UART_LSR_OFFSET);
/* Read receive buffer */
- get_reg(UART_RBR_OFFSET);
+ get_reg(dev, UART_RBR_OFFSET);
/* Set scratchpad */
- set_reg(UART_SCR_OFFSET, 0x00);
+ set_reg(dev, UART_SCR_OFFSET, 0x00);
+
+ return 0;
+}
+
+int uart8250_console_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width, u32 reg_offset)
+{
+ uart8250_init(&console_dev, base, in_freq, baudrate, reg_shift, reg_width, reg_offset);
sbi_console_set_device(&uart8250_console);
diff --git a/platform/fpga/ariane/platform.c b/platform/fpga/ariane/platform.c
index 8be5e6c..a59b74d 100644
--- a/platform/fpga/ariane/platform.c
+++ b/platform/fpga/ariane/platform.c
@@ -92,7 +92,7 @@ static int ariane_final_init(bool cold_boot)
*/
static int ariane_console_init(void)
{
- return uart8250_init(ARIANE_UART_ADDR,
+ return uart8250_console_init(ARIANE_UART_ADDR,
ARIANE_UART_FREQ,
ARIANE_UART_BAUDRATE,
ARIANE_UART_REG_SHIFT,
diff --git a/platform/fpga/openpiton/platform.c b/platform/fpga/openpiton/platform.c
index 2317a89..21f3ccd 100644
--- a/platform/fpga/openpiton/platform.c
+++ b/platform/fpga/openpiton/platform.c
@@ -127,7 +127,7 @@ static int openpiton_final_init(bool cold_boot)
*/
static int openpiton_console_init(void)
{
- return uart8250_init(uart.addr,
+ return uart8250_console_init(uart.addr,
uart.freq,
uart.baud,
OPENPITON_DEFAULT_UART_REG_SHIFT,
diff --git a/platform/template/platform.c b/platform/template/platform.c
index 4b3f2ac..59a377b 100644
--- a/platform/template/platform.c
+++ b/platform/template/platform.c
@@ -81,7 +81,7 @@ static int platform_final_init(bool cold_boot)
static int platform_console_init(void)
{
/* Example if the generic UART8250 driver is used */
- return uart8250_init(PLATFORM_UART_ADDR, PLATFORM_UART_INPUT_FREQ,
+ return uart8250_console_init(PLATFORM_UART_ADDR, PLATFORM_UART_INPUT_FREQ,
PLATFORM_UART_BAUDRATE, 0, 1, 0);
}
--
2.43.0
More information about the opensbi
mailing list