From: Yuriy Kolerov <[email protected]>
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 <[email protected]>
Signed-off-by: Yuriy Kolerov <[email protected]>
---
libgloss/arc/uart-8250-stub.c | 116 +++++++++++++
libgloss/arc/uart-8250.c | 316 ++++++++++++++++++++++++++++++++++
libgloss/arc/uart-8250.h | 25 +++
3 files changed, 457 insertions(+)
create mode 100644 libgloss/arc/uart-8250-stub.c
create mode 100644 libgloss/arc/uart-8250.c
create mode 100644 libgloss/arc/uart-8250.h
diff --git a/libgloss/arc/uart-8250-stub.c b/libgloss/arc/uart-8250-stub.c
new file mode 100644
index 000000000..ab69d6354
--- /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 000000000..6f4e9f3d6
--- /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 000000000..dc6062334
--- /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 */
--
2.39.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.