1// See LICENSE for license details. 2 3#include <string.h> 4#include "uart.h" 5#include "fdt.h" 6 7volatile uint32_t* uart; 8 9void uart_putchar(uint8_t ch) 10{ 11#ifdef __riscv_atomic 12 int32_t r; 13 do { 14 __asm__ __volatile__ ( 15 "amoor.w %0, %2, %1\n" 16 : "=r" (r), "+A" (uart[UART_REG_TXFIFO]) 17 : "r" (ch)); 18 } while (r < 0); 19#else 20 volatile uint32_t *tx = uart + UART_REG_TXFIFO; 21 while ((int32_t)(*tx) < 0); 22 *tx = ch; 23#endif 24} 25 26int uart_getchar() 27{ 28 int32_t ch = uart[UART_REG_RXFIFO]; 29 if (ch < 0) return -1; 30 return ch; 31} 32 33struct uart_scan 34{ 35 int compat; 36 uint64_t reg; 37}; 38 39static void uart_open(const struct fdt_scan_node *node, void *extra) 40{ 41 struct uart_scan *scan = (struct uart_scan *)extra; 42 memset(scan, 0, sizeof(*scan)); 43} 44 45static void uart_prop(const struct fdt_scan_prop *prop, void *extra) 46{ 47 struct uart_scan *scan = (struct uart_scan *)extra; 48 if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,uart0")) { 49 scan->compat = 1; 50 } else if (!strcmp(prop->name, "reg")) { 51 fdt_get_address(prop->node->parent, prop->value, &scan->reg); 52 } 53} 54 55static void uart_done(const struct fdt_scan_node *node, void *extra) 56{ 57 struct uart_scan *scan = (struct uart_scan *)extra; 58 if (!scan->compat || !scan->reg || uart) return; 59 60 // Enable Rx/Tx channels 61 uart = (void*)(uintptr_t)scan->reg; 62 uart[UART_REG_TXCTRL] = UART_TXEN; 63 uart[UART_REG_RXCTRL] = UART_RXEN; 64} 65 66void query_uart(uintptr_t fdt) 67{ 68 struct fdt_cb cb; 69 struct uart_scan scan; 70 71 memset(&cb, 0, sizeof(cb)); 72 cb.open = uart_open; 73 cb.prop = uart_prop; 74 cb.done = uart_done; 75 cb.extra = &scan; 76 77 fdt_scan(fdt, &cb); 78} 79