aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuriy Kolerov <kolerov93@gmail.com>2024-05-21 10:56:52 +0100
committerJeff Johnston <jjohnstn@redhat.com>2024-05-22 14:26:03 -0400
commitf507aef5e766d86ff6ef6b92f87b893c30dcf413 (patch)
tree20cc90632dea57123442d9f4aa33ee71c1bc71e2
parent13ae6cae44d6cc542eff3b945545749f4e38a856 (diff)
downloadnewlib-f507aef5e766d86ff6ef6b92f87b893c30dcf413.zip
newlib-f507aef5e766d86ff6ef6b92f87b893c30dcf413.tar.gz
newlib-f507aef5e766d86ff6ef6b92f87b893c30dcf413.tar.bz2
arc: libgloss: Add UART 8250 library
This library implements libgloss input/output and setup routines for UART 8250 devices of ARC development boards: * EM Starter Kit * HS Development Kit * EM Software Development Platform * IoT Development Kit _uart_8250_setup function with proper parameteres must be called to setup UART 8250 device for a particular board (refer to a board's documentation). Signed-off-by: Vladimir Isaev <vvisaev@gmail.com> Signed-off-by: Yuriy Kolerov <kolerov93@gmail.com>
-rw-r--r--libgloss/arc/uart-8250-stub.c116
-rw-r--r--libgloss/arc/uart-8250.c316
-rw-r--r--libgloss/arc/uart-8250.h25
3 files changed, 457 insertions, 0 deletions
diff --git a/libgloss/arc/uart-8250-stub.c b/libgloss/arc/uart-8250-stub.c
new file mode 100644
index 0000000..ab69d63
--- /dev/null
+++ b/libgloss/arc/uart-8250-stub.c
@@ -0,0 +1,116 @@
+/*
+ * uart-8250-stub.c -- various stubs for 8250 UART libgloss.
+ *
+ * Copyright (c) 2024 Synopsys Inc.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "glue.h"
+
+
+/* Always return character device with 1024 bytes block. */
+int
+_fstat (int fd __attribute__ ((unused)), struct stat *buf)
+{
+ memset (buf, 0, sizeof (*buf));
+ buf->st_mode = S_IFCHR;
+ buf->st_blksize = 1024;
+
+ return 0;
+}
+
+/* ARC UART is actually console so just return 1. */
+int
+_isatty (int fildes __attribute__ ((unused)))
+{
+ return 1;
+}
+
+/* Should be provided by crt0.S. */
+extern void __attribute__((noreturn)) _exit_halt (int ret);
+
+void
+__attribute__((noreturn))
+_exit (int ret)
+{
+ _exit_halt (ret);
+}
+
+/* Not implemented. */
+off_t
+_lseek (int fd __attribute__ ((unused)),
+ off_t offset __attribute__ ((unused)),
+ int whence __attribute__ ((unused)))
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+/* Not implemented. */
+int
+_close (int fd __attribute__ ((unused)))
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+/* Not implemented. */
+int
+_open (const char *path __attribute__ ((unused)),
+ int flags __attribute__ ((unused)), ...)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+/* If PID is equal to __MYPID, exit with sig as retcode. */
+int
+_kill (int pid, int sig)
+{
+ if (pid == __MYPID)
+ _exit (sig);
+
+ errno = ENOSYS;
+ return -1;
+}
+
+/* Return __MYPID. */
+int
+_getpid (void)
+{
+ return __MYPID;
+}
+
+/* No arguments. */
+int
+_argc (void)
+{
+ return 0;
+}
+
+/* No arguments. */
+uint32_t
+_argvlen (int a __attribute__ ((unused)))
+{
+ return 0;
+}
+
+/* No arguments. */
+int
+_argv (int a __attribute__ ((unused)), char *arg __attribute__ ((unused)))
+{
+ return -1;
+}
diff --git a/libgloss/arc/uart-8250.c b/libgloss/arc/uart-8250.c
new file mode 100644
index 0000000..6f4e9f3
--- /dev/null
+++ b/libgloss/arc/uart-8250.c
@@ -0,0 +1,316 @@
+/*
+ * uart-8250.c -- polling driver for 32-bit 8250 UART.
+ * Provides _uart_8250_setup(), _read() and _write(). Please note that
+ * _read() and _write() from this file can only be used for console access.
+ *
+ * Copyright (c) 2024 Synopsys Inc.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+
+/*
+ * List of UART 8250 registers with offsets:
+ *
+ * 0x00 - Transmit Holding Register, WO, LCR_DLAB == 0
+ * 0x00 - Receive Buffer Register, RO, LCR_DLAB == 0
+ * 0x00 - Divisor Latch Low, RW, LCR_DLAB == 1
+ * 0x04 - Divisor Latch High, RW, LCR_DLAB == 1
+ * 0x04 - Interrupt Enable Register, RW, LCR_DLAB == 0
+ * 0x08 - FIFO Control Register, WO
+ * 0x08 - Interrupt Identification Register, RO
+ * 0x0C - Line Control Register, RW
+ * 0x10 - Modem Control Register, RW
+ * 0x14 - Line Status Register, RO
+ * 0x18 - Modem Status Register, RO
+ */
+
+#define THR_OFFSET 0x00
+#define RBR_OFFSET 0x00
+#define DLL_OFFSET 0x00
+#define DLH_OFFSET 0x04
+#define IER_OFFSET 0x04
+#define FCR_OFFSET 0x08
+#define IIR_OFFSET 0x08
+#define LCR_OFFSET 0x0C
+#define MCR_OFFSET 0x10
+#define LSR_OFFSET 0x14
+#define MSR_OFFSET 0x18
+
+/*
+ * LCR (Line Control Register) fields:
+ *
+ * [7] - Divisor Latch Access Bit
+ * [6] - Set Break
+ * [5] - Stick Parity
+ * [4] - Even Parity Select
+ * [3] - Parity Enable
+ * [2] - Number of Stop Bits
+ * [1:0] - Data Length Select. Values:
+ * 0b11 - 8 data bits per character (default)
+ * 0b10 - 7 data bits per character
+ * 0b01 - 6 data bits per character
+ * 0b00 - 5 data bits per character
+ */
+
+#define LCR_DLAB_SHIFT 7
+#define LCR_SB_SHIFT 6
+#define LCR_SP_SHIFT 5
+#define LCR_EPS_SHIFT 4
+#define LCR_PEN_SHIFT 3
+#define LCR_STB_SHIFT 2
+#define LCR_DLS_SHIFT 0
+/*
+ * MCR (Modem Control Register) fields:
+ *
+ * [4] - LoopBack Bit
+ * [3] - Auxiliary Output 2
+ * [2] - Auxiliary Output 1
+ * [1] - Request To Send (ON by default)
+ * [0] - Data Terminal Ready (ON by default)
+ */
+
+#define MCR_LB_SHIFT 4
+#define MCR_OUT2_SHIFT 3
+#define MCR_OUT1_SHIFT 2
+#define MCR_RTS_SHIFT 1
+#define MCR_DTR_SHIFT 0
+
+/*
+ * LSR (Line Status Register) fields:
+ *
+ * [7] - Receiver FIFO Error
+ * [6] - Transmitter Empty
+ * [5] - Transmit Holding Register Empty
+ * [4] - Break Interrupt
+ * [3] - Framing Error
+ * [2] - Parity Error
+ * [1] - Overrun Error
+ * [0] - Data Ready
+ */
+
+#define LSR_RFE_SHIFT 7
+#define LSR_TEMT_SHIFT 6
+#define LSR_THRE_SHIFT 5
+#define LSR_BI_SHIFT 4
+#define LSR_FE_SHIFT 3
+#define LSR_PE_SHIFT 2
+#define LSR_OE_SHIFT 1
+#define LSR_DR_SHIFT 0
+
+/*
+ * Default initial values for configuration registers.
+ */
+
+#define FCR_DEFAULT 0x0
+#define IER_DEFAULT 0x0
+#define LCR_DLS_DEFAULT 0x3
+#define LCR_DEFAULT (LCR_DLS_DEFAULT << LCR_DLS_SHIFT)
+#define MCR_RTS_DEFAULT 0x1
+#define MCR_DTR_DEFAULT 0x1
+#define MCR_DEFAULT ((MCR_RTS_DEFAULT << MCR_RTS_SHIFT) | \
+ (MCR_DTR_DEFAULT << MCR_DTR_SHIFT))
+
+#define LCR_MODE_SETUP (0x1 << LCR_DLAB_SHIFT)
+#define LSR_MODE_GETC (0x1 << LSR_DR_SHIFT)
+#define LSR_MODE_PUTC ((0x1 << LSR_TEMT_SHIFT) | (0x1 << LSR_THRE_SHIFT))
+
+/* Main UART control structure. */
+struct _uart_8250 {
+ volatile char *base; /* Start of UART registers. */
+ uint32_t clk; /* UART clock. */
+ uint32_t baud; /* Baud rate. */
+ int aux_mapped; /* If UART registers are mapped to AUX or memory. */
+ int ready; /* If UART is ready to use or not. */
+};
+
+static struct _uart_8250 _uart_8250;
+
+/* Write 32-bit value to the UART register. */
+static inline void
+_uart_8250_write_reg (const struct _uart_8250 *uart, uint32_t reg,
+ uint32_t value)
+{
+ if (uart->aux_mapped)
+ __builtin_arc_sr (value, (uint32_t) uart->base + reg);
+ else
+ *(volatile uint32_t *)(uart->base + reg) = value;
+}
+
+/* Read 32-bit value from the UART register. */
+static inline uint32_t
+_uart_8250_read_reg (const struct _uart_8250 *uart, uint32_t reg)
+{
+ if (uart->aux_mapped)
+ return __builtin_arc_lr ((uint32_t) uart->base + reg);
+ else
+ return *(volatile uint32_t *)(uart->base + reg);
+}
+
+/* Wait until all flags are set. */
+static inline void
+_uart_8250_wait (const struct _uart_8250 *uart, uint32_t reg, uint32_t flags)
+{
+ while (1)
+ {
+ if ((_uart_8250_read_reg (uart, reg) & flags) == flags)
+ break;
+ }
+}
+
+/* Get one character from UART. CR is converted to NL. */
+static int
+_uart_8250_getc (const struct _uart_8250 *uart)
+{
+ char c;
+
+ _uart_8250_wait (uart, LSR_OFFSET, LSR_MODE_GETC);
+
+ c = _uart_8250_read_reg (uart, RBR_OFFSET);
+
+ if (c == '\r')
+ c = '\n';
+
+ return c;
+}
+
+/* Put one character to UART. CR is placed before NL. */
+static void
+_uart_8250_putc (const struct _uart_8250 *uart, char c)
+{
+ if (c == '\n')
+ _uart_8250_putc (uart, '\r');
+
+ _uart_8250_wait (uart, LSR_OFFSET, LSR_MODE_PUTC);
+
+ _uart_8250_write_reg (uart, THR_OFFSET, c);
+}
+
+/*
+ * Setup UART control structure and following parameters:
+ *
+ * - baudrate if clock and baudrate are passed to function
+ * - 8n1 (8 data bits, no parity bit, one stop bit)
+ * - disable interrupts
+ * - disable FIFO
+ * - set Request To Send and Data Terminal Ready
+ *
+ * Arguments:
+ *
+ * - base - start address of UART registers
+ * - aux_mapped - set if UART registers are mapped to ARC AUX
+ * - clk - UART clock frequency
+ * - baud - UART baudrate to setup
+ *
+ * The function returns 0 on success.
+ */
+int
+_uart_8250_setup (void *base, int aux_mapped, uint32_t clk, uint32_t baud)
+{
+ struct _uart_8250 *uart = &_uart_8250;
+
+ uart->base = base;
+ uart->aux_mapped = aux_mapped;
+ uart->clk = clk;
+ uart->baud = baud;
+
+ if (clk && baud)
+ {
+ uint32_t div;
+
+ div = ((clk + 8 * baud) / baud) / 16;
+ _uart_8250_write_reg (uart, LCR_OFFSET, LCR_MODE_SETUP);
+ _uart_8250_write_reg (uart, DLL_OFFSET, div & 0xFF);
+ _uart_8250_write_reg (uart, DLH_OFFSET, div >> 8);
+ }
+
+ _uart_8250_write_reg (uart, FCR_OFFSET, FCR_DEFAULT);
+ _uart_8250_write_reg (uart, IER_OFFSET, IER_DEFAULT);
+ _uart_8250_write_reg (uart, LCR_OFFSET, LCR_DEFAULT);
+ _uart_8250_write_reg (uart, MCR_OFFSET, MCR_DEFAULT);
+
+ uart->ready = 1;
+
+ return 0;
+}
+
+/* _read() is implemented only for stdin. Each read character is echoed. */
+ssize_t
+_read (int fd, void *buf, size_t count)
+{
+ struct _uart_8250 *uart = &_uart_8250;
+ size_t bytes_read;
+ char *buf_char = buf;
+ int c;
+
+ if (fd != STDIN_FILENO)
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (!uart->ready)
+ {
+ errno = EIO;
+ return -1;
+ }
+
+ bytes_read = 0;
+ c = EOF;
+ /* Break on '\n' to simulate readline behavior. */
+ while (bytes_read != count && c != '\n')
+ {
+ c = _uart_8250_getc (uart);
+ if (c == EOF)
+ break;
+
+ /* Echo character to the console. */
+ _uart_8250_putc (uart, c);
+
+ buf_char[bytes_read] = c;
+ bytes_read++;
+ }
+
+ return bytes_read;
+}
+
+/* _write() is implemented only for stdout and stderr. */
+ssize_t
+_write (int fd, const char *buf, size_t nbyte)
+{
+ struct _uart_8250 *uart = &_uart_8250;
+ uint32_t bytes_written;
+
+ if (fd != STDOUT_FILENO && fd != STDERR_FILENO)
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (!uart->ready)
+ {
+ errno = EIO;
+ return -1;
+ }
+
+ bytes_written = 0;
+ while (bytes_written != nbyte)
+ {
+ _uart_8250_putc (uart, buf[bytes_written]);
+ bytes_written++;
+ }
+
+ return bytes_written;
+}
diff --git a/libgloss/arc/uart-8250.h b/libgloss/arc/uart-8250.h
new file mode 100644
index 0000000..dc60623
--- /dev/null
+++ b/libgloss/arc/uart-8250.h
@@ -0,0 +1,25 @@
+/*
+ * uart-8250.h -- polling driver for 32-bit 8250 UART.
+ * Header defines _uart_8250_setup().
+ *
+ * Copyright (c) 2024 Synopsys Inc.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+
+#ifndef _UART_8250_H
+#define _UART_8250_H
+
+#include <stdint.h>
+
+int _uart_8250_setup (void *base, int aux_mapped, uint32_t clk, uint32_t baud);
+
+#endif /* ! _UART_8250_H */