From 62bb5daea5ef014616b00a63c106afdd07e68ffd Mon Sep 17 00:00:00 2001 From: gsomlo Date: Tue, 15 Dec 2020 16:11:40 -0500 Subject: Add support for the UART interface on the LiteX SoC (#230) Tested using the RocketChip CPU option. (see https://github.com/enjoy-digital/litex) Signed-off-by: Gabriel Somlo --- machine/machine.mk.in | 4 ++- machine/minit.c | 2 ++ machine/mtrap.c | 5 ++++ machine/uart_litex.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ machine/uart_litex.h | 14 ++++++++++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 machine/uart_litex.c create mode 100644 machine/uart_litex.h diff --git a/machine/machine.mk.in b/machine/machine.mk.in index ee0fc36..3543106 100644 --- a/machine/machine.mk.in +++ b/machine/machine.mk.in @@ -15,6 +15,7 @@ machine_hdrs = \ mtrap.h \ uart.h \ uart16550.h \ + uart_litex.h \ finisher.h \ unprivileged_memory.h \ vm.h \ @@ -30,6 +31,7 @@ machine_c_srcs = \ fp_ldst.c \ uart.c \ uart16550.c \ + uart_litex.c \ finisher.c \ misaligned_ldst.c \ flush_icache.c \ @@ -43,4 +45,4 @@ mentry.o: custom.dtb custom.dtb: $(CUSTOM_DTS) dtc -O dtb $^ -o $@ -endif \ No newline at end of file +endif diff --git a/machine/minit.c b/machine/minit.c index f0587cc..2fb67a4 100644 --- a/machine/minit.c +++ b/machine/minit.c @@ -7,6 +7,7 @@ #include "fdt.h" #include "uart.h" #include "uart16550.h" +#include "uart_litex.h" #include "finisher.h" #include "disabled_hart_mask.h" #include "htif.h" @@ -173,6 +174,7 @@ void init_first_hart(uintptr_t hartid, uintptr_t dtb) // Confirm console as early as possible query_uart(dtb); query_uart16550(dtb); + query_uart_litex(dtb); query_htif(dtb); printm("bbl loader\r\n"); diff --git a/machine/mtrap.c b/machine/mtrap.c index 42006b8..1acf802 100644 --- a/machine/mtrap.c +++ b/machine/mtrap.c @@ -8,6 +8,7 @@ #include "vm.h" #include "uart.h" #include "uart16550.h" +#include "uart_litex.h" #include "finisher.h" #include "fdt.h" #include "unprivileged_memory.h" @@ -27,6 +28,8 @@ static uintptr_t mcall_console_putchar(uint8_t ch) uart_putchar(ch); } else if (uart16550) { uart16550_putchar(ch); + } else if (uart_litex) { + uart_litex_putchar(ch); } else if (htif) { htif_console_putchar(ch); } @@ -69,6 +72,8 @@ static uintptr_t mcall_console_getchar() return uart_getchar(); } else if (uart16550) { return uart16550_getchar(); + } else if (uart_litex) { + return uart_litex_getchar(); } else if (htif) { return htif_console_getchar(); } else { diff --git a/machine/uart_litex.c b/machine/uart_litex.c new file mode 100644 index 0000000..1fe0359 --- /dev/null +++ b/machine/uart_litex.c @@ -0,0 +1,77 @@ +// See LICENSE for license details. + +#include +#include "uart_litex.h" +#include "fdt.h" + +volatile unsigned int *uart_litex; + +#define UART_REG_RXTX 0 +#define UART_REG_TXFULL 1 +#define UART_REG_RXEMPTY 2 +#define UART_REG_EV_STATUS 3 +#define UART_REG_EV_PENDING 4 +#define UART_REG_EV_ENABLE 5 + +void uart_litex_putchar(uint8_t c) +{ + while ((uart_litex[UART_REG_TXFULL] & 0x01)); // wait while tx-buffer full + uart_litex[UART_REG_RXTX] = c; +} + +int uart_litex_getchar() +{ + int c = -1; + if (!(uart_litex[UART_REG_RXEMPTY] & 0x01)) { // if rx-buffer not empty + c = uart_litex[UART_REG_RXTX]; + uart_litex[UART_REG_EV_PENDING] = 0x02; // ack (UART_EV_RX) + } + return c; +} + +struct uart_litex_scan +{ + int compat; + uint64_t reg; +}; + +static void uart_litex_open(const struct fdt_scan_node *node, void *extra) +{ + struct uart_litex_scan *scan = (struct uart_litex_scan *)extra; + memset(scan, 0, sizeof(*scan)); +} + +static void uart_litex_prop(const struct fdt_scan_prop *prop, void *extra) +{ + struct uart_litex_scan *scan = (struct uart_litex_scan *)extra; + if (!strcmp(prop->name, "compatible") && + !strcmp((const char *)prop->value, "litex,uart0")) { + scan->compat = 1; + } else if (!strcmp(prop->name, "reg")) { + fdt_get_address(prop->node->parent, prop->value, &scan->reg); + } +} + +static void uart_litex_done(const struct fdt_scan_node *node, void *extra) +{ + struct uart_litex_scan *scan = (struct uart_litex_scan *)extra; + if (!scan->compat || !scan->reg || uart_litex) + return; + + // Initialize LiteX UART + uart_litex = (void *)(uintptr_t)scan->reg; +} + +void query_uart_litex(uintptr_t fdt) +{ + struct fdt_cb cb; + struct uart_litex_scan scan; + + memset(&cb, 0, sizeof(cb)); + cb.open = uart_litex_open; + cb.prop = uart_litex_prop; + cb.done = uart_litex_done; + cb.extra = &scan; + + fdt_scan(fdt, &cb); +} diff --git a/machine/uart_litex.h b/machine/uart_litex.h new file mode 100644 index 0000000..a10dc57 --- /dev/null +++ b/machine/uart_litex.h @@ -0,0 +1,14 @@ +// See LICENSE for license details. + +#ifndef _RISCV_UARTLR_H +#define _RISCV_UARTLR_H + +#include + +extern volatile unsigned int *uart_litex; + +void uart_litex_putchar(uint8_t ch); +int uart_litex_getchar(); +void query_uart_litex(uintptr_t dtb); + +#endif -- cgit v1.1