1// See LICENSE for license details. 2 3#include <string.h> 4#include "uart16750.h" 5#include "fdt.h" 6 7volatile uint32_t* uart16750; 8 9#define UART_REG_QUEUE 0 10#define UART_REG_LINESTAT 5 11#define UART_REG_STATUS_RX 0x01 12#define UART_REG_STATUS_TX 0x20 13 14void uart16750_putchar(uint8_t ch) 15{ 16 while ((uart16750[UART_REG_LINESTAT] & UART_REG_STATUS_TX) == 0); 17 uart16750[UART_REG_QUEUE] = ch; 18} 19 20int uart16750_getchar() 21{ 22 if (uart16750[UART_REG_LINESTAT] & UART_REG_STATUS_RX) 23 return uart16750[UART_REG_QUEUE]; 24 return -1; 25} 26 27struct uart16750_scan 28{ 29 int compat; 30 uint64_t reg; 31 uint32_t freq; 32 uint32_t baud; 33}; 34 35static void uart16750_open(const struct fdt_scan_node *node, void *extra) 36{ 37 struct uart16750_scan *scan = (struct uart16750_scan *)extra; 38 memset(scan, 0, sizeof(*scan)); 39} 40 41static void uart16750_prop(const struct fdt_scan_prop *prop, void *extra) 42{ 43 struct uart16750_scan *scan = (struct uart16750_scan *)extra; 44 if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "ns16750")) { 45 scan->compat = 1; 46 } else if (!strcmp(prop->name, "reg")) { 47 fdt_get_address(prop->node->parent, prop->value, &scan->reg); 48 } else if (!strcmp(prop->name, "clock-frequency")) { 49 fdt_get_value(prop->value, &scan->freq); 50 } else if (!strcmp(prop->name, "current-speed")) { 51 fdt_get_value(prop->value, &scan->baud); 52 } 53} 54 55static void uart16750_done(const struct fdt_scan_node *node, void *extra) 56{ 57 struct uart16750_scan *scan = (struct uart16750_scan *)extra; 58 if (!scan->compat || !scan->reg || uart16750) return; 59 60 uint32_t divisor = scan->freq / (scan->baud << 4); 61 uart16750 = (void*)(uintptr_t)scan->reg; 62 // http://wiki.osdev.org/Serial_Ports 63 uart16750[1] = 0x00; // Disable all interrupts 64 uart16750[3] = 0x80; // Enable DLAB (set baud rate divisor) 65 uart16750[0] = divisor & 0xFF; 66 uart16750[1] = (divisor >> 8) & 0xFF; // (hi byte) 67 uart16750[3] = 0x03; // 8 bits, no parity, one stop bit 68 uart16750[2] = 0xC7; // Enable FIFO, clear them, with 14-byte threshold 69} 70 71void query_uart16750(uintptr_t fdt) 72{ 73 struct fdt_cb cb; 74 struct uart16750_scan scan; 75 76 memset(&cb, 0, sizeof(cb)); 77 cb.open = uart16750_open; 78 cb.prop = uart16750_prop; 79 cb.done = uart16750_done; 80 cb.extra = &scan; 81 82 fdt_scan(fdt, &cb); 83} 84