summaryrefslogtreecommitdiff
path: root/tools/src/uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/src/uart.c')
-rw-r--r--tools/src/uart.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/tools/src/uart.c b/tools/src/uart.c
new file mode 100644
index 0000000..67aa0e3
--- /dev/null
+++ b/tools/src/uart.c
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: MIT */
+
+#include <stdarg.h>
+
+#include "adt.h"
+#include "iodev.h"
+#include "types.h"
+#include "uart.h"
+#include "uart_regs.h"
+#include "utils.h"
+#include "vsprintf.h"
+
+#define UART_CLOCK 24000000
+
+static u64 uart_base = 0;
+
+int uart_init(void)
+{
+ int path[8];
+ int node = adt_path_offset_trace(adt, "/arm-io/uart0", path);
+
+ if (node < 0) {
+ printf("!!! UART node not found!\n");
+ return -1;
+ }
+
+ if (adt_get_reg(adt, path, "reg", 0, &uart_base, NULL)) {
+ printf("!!! Failed to get UART reg property!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void uart_putbyte(u8 c)
+{
+ if (!uart_base)
+ return;
+
+ while (!(read32(uart_base + UTRSTAT) & UTRSTAT_TXBE))
+ ;
+
+ write32(uart_base + UTXH, c);
+}
+
+u8 uart_getbyte(void)
+{
+ if (!uart_base)
+ return 0;
+
+ while (!(read32(uart_base + UTRSTAT) & UTRSTAT_RXD))
+ ;
+
+ return read32(uart_base + URXH);
+}
+
+void uart_putchar(u8 c)
+{
+ if (c == '\n')
+ uart_putbyte('\r');
+
+ uart_putbyte(c);
+}
+
+u8 uart_getchar(void)
+{
+ return uart_getbyte();
+}
+
+void uart_puts(const char *s)
+{
+ while (*s)
+ uart_putchar(*(s++));
+
+ uart_putchar('\n');
+}
+
+void uart_write(const void *buf, size_t count)
+{
+ const u8 *p = buf;
+
+ while (count--)
+ uart_putbyte(*p++);
+}
+
+size_t uart_read(void *buf, size_t count)
+{
+ u8 *p = buf;
+ size_t recvd = 0;
+
+ while (count--) {
+ *p++ = uart_getbyte();
+ recvd++;
+ }
+
+ return recvd;
+}
+
+void uart_setbaud(int baudrate)
+{
+ if (!uart_base)
+ return;
+
+ uart_flush();
+ write32(uart_base + UBRDIV, ((UART_CLOCK / baudrate + 7) / 16) - 1);
+}
+
+void uart_flush(void)
+{
+ if (!uart_base)
+ return;
+
+ while (!(read32(uart_base + UTRSTAT) & UTRSTAT_TXE))
+ ;
+}
+
+void uart_clear_irqs(void)
+{
+ if (!uart_base)
+ return;
+
+ write32(uart_base + UTRSTAT, UTRSTAT_TXTHRESH | UTRSTAT_RXTHRESH | UTRSTAT_RXTO);
+}
+
+int uart_printf(const char *fmt, ...)
+{
+ va_list args;
+ char buffer[512];
+ int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+
+ uart_write(buffer, min(i, (int)(sizeof(buffer) - 1)));
+
+ return i;
+}
+
+static bool uart_iodev_can_write(void *opaque)
+{
+ UNUSED(opaque);
+ return true;
+}
+
+static ssize_t uart_iodev_can_read(void *opaque)
+{
+ UNUSED(opaque);
+
+ if (!uart_base)
+ return 0;
+
+ return (read32(uart_base + UTRSTAT) & UTRSTAT_RXD) ? 1 : 0;
+}
+
+static ssize_t uart_iodev_read(void *opaque, void *buf, size_t len)
+{
+ UNUSED(opaque);
+ return uart_read(buf, len);
+}
+
+static ssize_t uart_iodev_write(void *opaque, const void *buf, size_t len)
+{
+ UNUSED(opaque);
+ uart_write(buf, len);
+ return len;
+}
+
+static struct iodev_ops iodev_uart_ops = {
+ .can_read = uart_iodev_can_read,
+ .can_write = uart_iodev_can_write,
+ .read = uart_iodev_read,
+ .write = uart_iodev_write,
+};
+
+struct iodev iodev_uart = {
+ .ops = &iodev_uart_ops,
+ .usage = USAGE_CONSOLE | USAGE_UARTPROXY,
+ .lock = SPINLOCK_INIT,
+};