aboutsummaryrefslogtreecommitdiffstats
path: root/roms/opensbi/lib/utils/serial
diff options
context:
space:
mode:
Diffstat (limited to 'roms/opensbi/lib/utils/serial')
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial.c111
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_htif.c24
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_shakti.c35
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_sifive.c38
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c39
-rw-r--r--roms/opensbi/lib/utils/serial/objects.mk17
-rw-r--r--roms/opensbi/lib/utils/serial/shakti-uart.c48
-rw-r--r--roms/opensbi/lib/utils/serial/sifive-uart.c102
-rw-r--r--roms/opensbi/lib/utils/serial/uart8250.c125
9 files changed, 539 insertions, 0 deletions
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial.c b/roms/opensbi/lib/utils/serial/fdt_serial.c
new file mode 100644
index 000000000..b9ce67ef1
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial.c
@@ -0,0 +1,111 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+
+extern struct fdt_serial fdt_serial_uart8250;
+extern struct fdt_serial fdt_serial_sifive;
+extern struct fdt_serial fdt_serial_htif;
+extern struct fdt_serial fdt_serial_shakti;
+
+static struct fdt_serial *serial_drivers[] = {
+ &fdt_serial_uart8250,
+ &fdt_serial_sifive,
+ &fdt_serial_htif,
+ &fdt_serial_shakti,
+};
+
+static void dummy_putc(char ch)
+{
+}
+
+static int dummy_getc(void)
+{
+ return -1;
+}
+
+static struct fdt_serial dummy = {
+ .match_table = NULL,
+ .init = NULL,
+ .putc = dummy_putc,
+ .getc = dummy_getc,
+};
+
+static struct fdt_serial *current_driver = &dummy;
+
+void fdt_serial_putc(char ch)
+{
+ current_driver->putc(ch);
+}
+
+int fdt_serial_getc(void)
+{
+ return current_driver->getc();
+}
+
+int fdt_serial_init(void)
+{
+ const void *prop;
+ struct fdt_serial *drv;
+ const struct fdt_match *match;
+ int pos, noff = -1, len, coff, rc;
+ void *fdt = sbi_scratch_thishart_arg1_ptr();
+
+ /* Find offset of node pointed by stdout-path */
+ coff = fdt_path_offset(fdt, "/chosen");
+ if (-1 < coff) {
+ prop = fdt_getprop(fdt, coff, "stdout-path", &len);
+ if (prop && len)
+ noff = fdt_path_offset(fdt, prop);
+ }
+
+ /* First check DT node pointed by stdout-path */
+ for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
+ drv = serial_drivers[pos];
+
+ match = fdt_match_node(fdt, noff, drv->match_table);
+ if (!match)
+ continue;
+
+ if (drv->init) {
+ rc = drv->init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ break;
+ }
+
+ /* Check if we found desired driver */
+ if (current_driver != &dummy)
+ goto done;
+
+ /* Lastly check all DT nodes */
+ for (pos = 0; pos < array_size(serial_drivers); pos++) {
+ drv = serial_drivers[pos];
+
+ noff = fdt_find_match(fdt, -1, drv->match_table, &match);
+ if (noff < 0)
+ continue;
+
+ if (drv->init) {
+ rc = drv->init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ break;
+ }
+
+done:
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_htif.c b/roms/opensbi/lib/utils/serial/fdt_serial_htif.c
new file mode 100644
index 000000000..32d695317
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_htif.c
@@ -0,0 +1,24 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/sys/htif.h>
+
+static const struct fdt_match serial_htif_match[] = {
+ { .compatible = "ucb,htif0" },
+ { },
+};
+
+struct fdt_serial fdt_serial_htif = {
+ .match_table = serial_htif_match,
+ .init = NULL,
+ .getc = htif_getc,
+ .putc = htif_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_shakti.c b/roms/opensbi/lib/utils/serial/fdt_serial_shakti.c
new file mode 100644
index 000000000..c6385a577
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_shakti.c
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
+ *
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/serial/shakti-uart.h>
+
+static int serial_shakti_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct platform_uart_data uart;
+
+ rc = fdt_parse_shakti_uart_node(fdt, nodeoff, &uart);
+ if (rc)
+ return rc;
+
+ return shakti_uart_init(uart.addr, uart.freq, uart.baud);
+}
+
+static const struct fdt_match serial_shakti_match[] = {
+ { .compatible = "shakti,uart0" },
+ { },
+};
+
+struct fdt_serial fdt_serial_shakti = {
+ .match_table = serial_shakti_match,
+ .init = serial_shakti_init,
+ .getc = shakti_uart_getc,
+ .putc = shakti_uart_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_sifive.c b/roms/opensbi/lib/utils/serial/fdt_serial_sifive.c
new file mode 100644
index 000000000..9e487a2b5
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_sifive.c
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/serial/sifive-uart.h>
+
+static int serial_sifive_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct platform_uart_data uart;
+
+ rc = fdt_parse_sifive_uart_node(fdt, nodeoff, &uart);
+ if (rc)
+ return rc;
+
+ return sifive_uart_init(uart.addr, uart.freq, uart.baud);
+}
+
+static const struct fdt_match serial_sifive_match[] = {
+ { .compatible = "sifive,fu540-c000-uart" },
+ { .compatible = "sifive,uart0" },
+ { },
+};
+
+struct fdt_serial fdt_serial_sifive = {
+ .match_table = serial_sifive_match,
+ .init = serial_sifive_init,
+ .getc = sifive_uart_getc,
+ .putc = sifive_uart_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c b/roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c
new file mode 100644
index 000000000..5030b823a
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c
@@ -0,0 +1,39 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/serial/uart8250.h>
+
+static int serial_uart8250_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct platform_uart_data uart;
+
+ rc = fdt_parse_uart8250_node(fdt, nodeoff, &uart);
+ if (rc)
+ return rc;
+
+ return uart8250_init(uart.addr, uart.freq, uart.baud,
+ uart.reg_shift, uart.reg_io_width);
+}
+
+static const struct fdt_match serial_uart8250_match[] = {
+ { .compatible = "ns16550" },
+ { .compatible = "ns16550a" },
+ { },
+};
+
+struct fdt_serial fdt_serial_uart8250 = {
+ .match_table = serial_uart8250_match,
+ .init = serial_uart8250_init,
+ .getc = uart8250_getc,
+ .putc = uart8250_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/objects.mk b/roms/opensbi/lib/utils/serial/objects.mk
new file mode 100644
index 000000000..c0746f07e
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/objects.mk
@@ -0,0 +1,17 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbiutils-objs-y += serial/fdt_serial.o
+libsbiutils-objs-y += serial/fdt_serial_htif.o
+libsbiutils-objs-y += serial/fdt_serial_shakti.o
+libsbiutils-objs-y += serial/fdt_serial_sifive.o
+libsbiutils-objs-y += serial/fdt_serial_uart8250.o
+libsbiutils-objs-y += serial/shakti-uart.o
+libsbiutils-objs-y += serial/sifive-uart.o
+libsbiutils-objs-y += serial/uart8250.o
diff --git a/roms/opensbi/lib/utils/serial/shakti-uart.c b/roms/opensbi/lib/utils/serial/shakti-uart.c
new file mode 100644
index 000000000..7c1148ee1
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/shakti-uart.c
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi_utils/serial/shakti-uart.h>
+
+#define REG_BAUD 0x00
+#define REG_TX 0x04
+#define REG_RX 0x08
+#define REG_STATUS 0x0C
+#define REG_DELAY 0x10
+#define REG_CONTROL 0x14
+#define REG_INT_EN 0x18
+#define REG_IQ_CYCLES 0x1C
+#define REG_RX_THRES 0x20
+
+#define UART_TX_FULL 0x2
+#define UART_RX_FULL 0x8
+
+static volatile void *uart_base;
+
+void shakti_uart_putc(char ch)
+{
+ while((readw(uart_base + REG_STATUS) & UART_TX_FULL))
+ ;
+ writeb(ch, uart_base + REG_TX);
+}
+
+int shakti_uart_getc(void)
+{
+ u16 status = readw(uart_base + REG_STATUS);
+ if (status & UART_RX_FULL)
+ return readb(uart_base + REG_RX);
+ return -1;
+}
+
+int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
+{
+ uart_base = (volatile void *)base;
+ u16 baud = (u16)(in_freq/(16 * baudrate));
+ writew(baud, uart_base + REG_BAUD);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/serial/sifive-uart.c b/roms/opensbi/lib/utils/serial/sifive-uart.c
new file mode 100644
index 000000000..72c8a6249
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/sifive-uart.c
@@ -0,0 +1,102 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi_utils/serial/sifive-uart.h>
+
+/* clang-format off */
+
+#define UART_REG_TXFIFO 0
+#define UART_REG_RXFIFO 1
+#define UART_REG_TXCTRL 2
+#define UART_REG_RXCTRL 3
+#define UART_REG_IE 4
+#define UART_REG_IP 5
+#define UART_REG_DIV 6
+
+#define UART_TXFIFO_FULL 0x80000000
+#define UART_RXFIFO_EMPTY 0x80000000
+#define UART_RXFIFO_DATA 0x000000ff
+#define UART_TXCTRL_TXEN 0x1
+#define UART_RXCTRL_RXEN 0x1
+
+/* clang-format on */
+
+static volatile void *uart_base;
+static u32 uart_in_freq;
+static u32 uart_baudrate;
+
+/**
+ * Find minimum divisor divides in_freq to max_target_hz;
+ * Based on uart driver n SiFive FSBL.
+ *
+ * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
+ * The nearest integer solution requires rounding up as to not exceed max_target_hz.
+ * div = ceil(f_in / f_baud) - 1
+ * = floor((f_in - 1 + f_baud) / f_baud) - 1
+ * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
+ * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
+ */
+static inline unsigned int uart_min_clk_divisor(uint64_t in_freq,
+ uint64_t max_target_hz)
+{
+ uint64_t quotient = (in_freq + max_target_hz - 1) / (max_target_hz);
+ /* Avoid underflow */
+ if (quotient == 0) {
+ return 0;
+ } else {
+ return quotient - 1;
+ }
+}
+
+static u32 get_reg(u32 num)
+{
+ return readl(uart_base + (num * 0x4));
+}
+
+static void set_reg(u32 num, u32 val)
+{
+ writel(val, uart_base + (num * 0x4));
+}
+
+void sifive_uart_putc(char ch)
+{
+ while (get_reg(UART_REG_TXFIFO) & UART_TXFIFO_FULL)
+ ;
+
+ set_reg(UART_REG_TXFIFO, ch);
+}
+
+int sifive_uart_getc(void)
+{
+ u32 ret = get_reg(UART_REG_RXFIFO);
+ if (!(ret & UART_RXFIFO_EMPTY))
+ return ret & UART_RXFIFO_DATA;
+ return -1;
+}
+
+int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
+{
+ uart_base = (volatile void *)base;
+ uart_in_freq = in_freq;
+ uart_baudrate = baudrate;
+
+ /* Configure baudrate */
+ if (in_freq)
+ set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate));
+ /* Disable interrupts */
+ set_reg(UART_REG_IE, 0);
+ /* Enable TX */
+ set_reg(UART_REG_TXCTRL, UART_TXCTRL_TXEN);
+ /* Enable Rx */
+ set_reg(UART_REG_RXCTRL, UART_RXCTRL_RXEN);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/serial/uart8250.c b/roms/opensbi/lib/utils/serial/uart8250.c
new file mode 100644
index 000000000..9635ba863
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/uart8250.c
@@ -0,0 +1,125 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi_utils/serial/uart8250.h>
+
+/* clang-format off */
+
+#define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */
+#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */
+#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */
+#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */
+#define UART_DLM_OFFSET 1 /* Out: Divisor Latch High */
+#define UART_FCR_OFFSET 2 /* Out: FIFO Control Register */
+#define UART_IIR_OFFSET 2 /* I/O: Interrupt Identification Register */
+#define UART_LCR_OFFSET 3 /* Out: Line Control Register */
+#define UART_MCR_OFFSET 4 /* Out: Modem Control Register */
+#define UART_LSR_OFFSET 5 /* In: Line Status Register */
+#define UART_MSR_OFFSET 6 /* In: Modem Status Register */
+#define UART_SCR_OFFSET 7 /* I/O: Scratch Register */
+#define UART_MDR1_OFFSET 8 /* I/O: Mode Register */
+
+#define UART_LSR_FIFOE 0x80 /* Fifo error */
+#define UART_LSR_TEMT 0x40 /* Transmitter empty */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+#define UART_LSR_BI 0x10 /* Break interrupt indicator */
+#define UART_LSR_FE 0x08 /* Frame error indicator */
+#define UART_LSR_PE 0x04 /* Parity error indicator */
+#define UART_LSR_OE 0x02 /* Overrun error indicator */
+#define UART_LSR_DR 0x01 /* Receiver data ready */
+#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
+
+/* clang-format on */
+
+static volatile void *uart8250_base;
+static u32 uart8250_in_freq;
+static u32 uart8250_baudrate;
+static u32 uart8250_reg_width;
+static u32 uart8250_reg_shift;
+
+static u32 get_reg(u32 num)
+{
+ u32 offset = num << uart8250_reg_shift;
+
+ if (uart8250_reg_width == 1)
+ return readb(uart8250_base + offset);
+ else if (uart8250_reg_width == 2)
+ return readw(uart8250_base + offset);
+ else
+ return readl(uart8250_base + offset);
+}
+
+static void set_reg(u32 num, u32 val)
+{
+ u32 offset = num << uart8250_reg_shift;
+
+ if (uart8250_reg_width == 1)
+ writeb(val, uart8250_base + offset);
+ else if (uart8250_reg_width == 2)
+ writew(val, uart8250_base + offset);
+ else
+ writel(val, uart8250_base + offset);
+}
+
+void uart8250_putc(char ch)
+{
+ while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
+ ;
+
+ set_reg(UART_THR_OFFSET, ch);
+}
+
+int uart8250_getc(void)
+{
+ if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
+ return get_reg(UART_RBR_OFFSET);
+ return -1;
+}
+
+int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width)
+{
+ u16 bdiv;
+
+ uart8250_base = (volatile void *)base;
+ uart8250_reg_shift = reg_shift;
+ uart8250_reg_width = reg_width;
+ uart8250_in_freq = in_freq;
+ uart8250_baudrate = baudrate;
+
+ bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
+
+ /* Disable all interrupts */
+ set_reg(UART_IER_OFFSET, 0x00);
+ /* Enable DLAB */
+ set_reg(UART_LCR_OFFSET, 0x80);
+
+ if (bdiv) {
+ /* Set divisor low byte */
+ set_reg(UART_DLL_OFFSET, bdiv & 0xff);
+ /* Set divisor high byte */
+ set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
+ }
+
+ /* 8 bits, no parity, one stop bit */
+ set_reg(UART_LCR_OFFSET, 0x03);
+ /* Enable FIFO */
+ set_reg(UART_FCR_OFFSET, 0x01);
+ /* No modem control DTR RTS */
+ set_reg(UART_MCR_OFFSET, 0x00);
+ /* Clear line status */
+ get_reg(UART_LSR_OFFSET);
+ /* Read receive buffer */
+ get_reg(UART_RBR_OFFSET);
+ /* Set scratchpad */
+ set_reg(UART_SCR_OFFSET, 0x00);
+
+ return 0;
+}