diff options
-rw-r--r-- | machine/machine.mk.in | 2 | ||||
-rw-r--r-- | machine/minit.c | 2 | ||||
-rw-r--r-- | machine/mtrap.c | 5 | ||||
-rw-r--r-- | machine/uart16550.c | 74 | ||||
-rw-r--r-- | machine/uart16550.h | 12 |
5 files changed, 95 insertions, 0 deletions
diff --git a/machine/machine.mk.in b/machine/machine.mk.in index dc8492f..3d19bf0 100644 --- a/machine/machine.mk.in +++ b/machine/machine.mk.in @@ -12,6 +12,7 @@ machine_hdrs = \ mcall.h \ mtrap.h \ uart.h \ + uart16550.h \ finisher.h \ unprivileged_memory.h \ vm.h \ @@ -26,6 +27,7 @@ machine_c_srcs = \ fp_emulation.c \ fp_ldst.c \ uart.c \ + uart16550.c \ finisher.c \ misaligned_ldst.c \ diff --git a/machine/minit.c b/machine/minit.c index 3623f38..ee83f98 100644 --- a/machine/minit.c +++ b/machine/minit.c @@ -4,6 +4,7 @@ #include "fp_emulation.h" #include "fdt.h" #include "uart.h" +#include "uart16550.h" #include "finisher.h" #include "disabled_hart_mask.h" #include "htif.h" @@ -141,6 +142,7 @@ void init_first_hart(uintptr_t hartid, uintptr_t dtb) { // Confirm console as early as possible query_uart(dtb); + query_uart16550(dtb); query_htif(dtb); hart_init(); diff --git a/machine/mtrap.c b/machine/mtrap.c index 0f77def..6c0e99c 100644 --- a/machine/mtrap.c +++ b/machine/mtrap.c @@ -5,6 +5,7 @@ #include "bits.h" #include "vm.h" #include "uart.h" +#include "uart16550.h" #include "finisher.h" #include "fdt.h" #include "unprivileged_memory.h" @@ -22,6 +23,8 @@ static uintptr_t mcall_console_putchar(uint8_t ch) { if (uart) { uart_putchar(ch); + } else if (uart16550) { + uart16550_putchar(ch); } else if (htif) { htif_console_putchar(ch); } @@ -73,6 +76,8 @@ static uintptr_t mcall_console_getchar() { if (uart) { return uart_getchar(); + } else if (uart16550) { + return uart16550_getchar(); } else if (htif) { return htif_console_getchar(); } else { diff --git a/machine/uart16550.c b/machine/uart16550.c new file mode 100644 index 0000000..fe1ba99 --- /dev/null +++ b/machine/uart16550.c @@ -0,0 +1,74 @@ +#include <string.h> +#include "uart16550.h" +#include "fdt.h" + +volatile uint8_t* uart16550; + +#define UART_REG_QUEUE 0 +#define UART_REG_LINESTAT 5 +#define UART_REG_STATUS_RX 0x01 +#define UART_REG_STATUS_TX 0x20 + +void uart16550_putchar(uint8_t ch) +{ + while ((uart16550[UART_REG_LINESTAT] & UART_REG_STATUS_TX) == 0); + uart16550[UART_REG_QUEUE] = ch; +} + +int uart16550_getchar() +{ + if (uart16550[UART_REG_LINESTAT] & UART_REG_STATUS_RX) + return uart16550[UART_REG_QUEUE]; + return -1; +} + +struct uart16550_scan +{ + int compat; + uint64_t reg; +}; + +static void uart16550_open(const struct fdt_scan_node *node, void *extra) +{ + struct uart16550_scan *scan = (struct uart16550_scan *)extra; + memset(scan, 0, sizeof(*scan)); +} + +static void uart16550_prop(const struct fdt_scan_prop *prop, void *extra) +{ + struct uart16550_scan *scan = (struct uart16550_scan *)extra; + if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "ns16550a")) { + scan->compat = 1; + } else if (!strcmp(prop->name, "reg")) { + fdt_get_address(prop->node->parent, prop->value, &scan->reg); + } +} + +static void uart16550_done(const struct fdt_scan_node *node, void *extra) +{ + struct uart16550_scan *scan = (struct uart16550_scan *)extra; + if (!scan->compat || !scan->reg || uart16550) return; + + uart16550 = (void*)(uintptr_t)scan->reg; + // http://wiki.osdev.org/Serial_Ports + uart16550[1] = 0x00; // Disable all interrupts + uart16550[3] = 0x80; // Enable DLAB (set baud rate divisor) + uart16550[0] = 0x03; // Set divisor to 3 (lo byte) 38400 baud + uart16550[1] = 0x00; // (hi byte) + uart16550[3] = 0x03; // 8 bits, no parity, one stop bit + uart16550[2] = 0xC7; // Enable FIFO, clear them, with 14-byte threshold +} + +void query_uart16550(uintptr_t fdt) +{ + struct fdt_cb cb; + struct uart16550_scan scan; + + memset(&cb, 0, sizeof(cb)); + cb.open = uart16550_open; + cb.prop = uart16550_prop; + cb.done = uart16550_done; + cb.extra = &scan; + + fdt_scan(fdt, &cb); +} diff --git a/machine/uart16550.h b/machine/uart16550.h new file mode 100644 index 0000000..d7a0805 --- /dev/null +++ b/machine/uart16550.h @@ -0,0 +1,12 @@ +#ifndef _RISCV_16550_H +#define _RISCV_16550_H + +#include <stdint.h> + +extern volatile uint8_t* uart16550; + +void uart16550_putchar(uint8_t ch); +int uart16550_getchar(); +void query_uart16550(uintptr_t dtb); + +#endif |