diff options
Diffstat (limited to 'roms/opensbi/lib/utils/serial')
-rw-r--r-- | roms/opensbi/lib/utils/serial/fdt_serial.c | 111 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/fdt_serial_htif.c | 24 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/fdt_serial_shakti.c | 35 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/fdt_serial_sifive.c | 38 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c | 39 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/objects.mk | 17 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/shakti-uart.c | 48 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/sifive-uart.c | 102 | ||||
-rw-r--r-- | roms/opensbi/lib/utils/serial/uart8250.c | 125 |
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; +} |