[PATCH v2] aarch64/versal: Add UART interrupt support
chrisj at rtems.org
chrisj at rtems.org
Tue Nov 22 10:22:36 UTC 2022
From: Chris Johns <chrisj at rtems.org>
---
.../dev/serial/versal-uart-polled.c | 37 --
.../xilinx-versal/dev/serial/versal-uart.c | 321 ++++++++++++++++++
.../include/dev/serial/versal-uart-regs.h | 1 -
.../include/dev/serial/versal-uart.h | 4 +-
spec/build/bsps/aarch64/xilinx-versal/grp.yml | 2 +
spec/build/bsps/aarch64/xilinx-versal/obj.yml | 1 +
.../bsps/aarch64/xilinx-versal/optconirq.yml | 15 +
7 files changed, 342 insertions(+), 39 deletions(-)
create mode 100644 bsps/aarch64/xilinx-versal/dev/serial/versal-uart.c
create mode 100644 spec/build/bsps/aarch64/xilinx-versal/optconirq.yml
diff --git a/bsps/aarch64/xilinx-versal/dev/serial/versal-uart-polled.c b/bsps/aarch64/xilinx-versal/dev/serial/versal-uart-polled.c
index 83493db909..9453dc248b 100644
--- a/bsps/aarch64/xilinx-versal/dev/serial/versal-uart-polled.c
+++ b/bsps/aarch64/xilinx-versal/dev/serial/versal-uart-polled.c
@@ -152,23 +152,6 @@ int versal_uart_initialize(rtems_termios_device_context *base)
return 0;
}
-static bool versal_uart_first_open(
- struct rtems_termios_tty *tty,
- rtems_termios_device_context *base,
- struct termios *term,
- rtems_libio_open_close_args_t *args
-)
-{
- int rc = versal_uart_initialize(base);
- if ( rc < 0 ) {
- return false;
- }
-
- rtems_termios_set_initial_baud(tty, VERSAL_UART_DEFAULT_BAUD);
-
- return true;
-}
-
int versal_uart_read_polled(rtems_termios_device_context *base)
{
volatile versal_uart *regs = versal_uart_get_regs(base);
@@ -209,23 +192,3 @@ void versal_uart_reset_tx_flush(rtems_termios_device_context *base)
/* Wait for empty */
}
}
-
-static void versal_uart_write_support(
- rtems_termios_device_context *base,
- const char *s,
- size_t n
-)
-{
- size_t i;
-
- for (i = 0; i < n; i++) {
- versal_uart_write_polled(base, s[i]);
- }
-}
-
-const rtems_termios_device_handler versal_uart_handler = {
- .first_open = versal_uart_first_open,
- .write = versal_uart_write_support,
- .poll_read = versal_uart_read_polled,
- .mode = TERMIOS_POLLED
-};
diff --git a/bsps/aarch64/xilinx-versal/dev/serial/versal-uart.c b/bsps/aarch64/xilinx-versal/dev/serial/versal-uart.c
new file mode 100644
index 0000000000..b009f83c37
--- /dev/null
+++ b/bsps/aarch64/xilinx-versal/dev/serial/versal-uart.c
@@ -0,0 +1,321 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2022 Chris Johns <chris at contemporary.software>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <dev/serial/versal-uart.h>
+#include <dev/serial/versal-uart-regs.h>
+#include <bsp/irq.h>
+
+#include <bspopts.h>
+
+#ifdef VERSAL_CONSOLE_USE_INTERRUPTS
+static uint32_t versal_uart_intr_all(void)
+{
+ return VERSAL_UARTI_OEI |
+ VERSAL_UARTI_BEI |
+ VERSAL_UARTI_PEI |
+ VERSAL_UARTI_FEI |
+ VERSAL_UARTI_RTI |
+ VERSAL_UARTI_TXI |
+ VERSAL_UARTI_RXI |
+ VERSAL_UARTI_DSRMI |
+ VERSAL_UARTI_DCDMI |
+ VERSAL_UARTI_CTSMI |
+ VERSAL_UARTI_RIMI;
+}
+
+static void versal_uart_intr_clear(volatile versal_uart *regs, uint32_t ints)
+{
+ regs->uarticr = ints;
+}
+
+static void versal_uart_intr_clearall(volatile versal_uart *regs)
+{
+ versal_uart_intr_clear(regs, versal_uart_intr_all());
+}
+
+static void versal_uart_intr_enable(volatile versal_uart *regs, uint32_t ints)
+{
+ regs->uartimsc |= ints;
+}
+
+static void versal_uart_intr_disable(volatile versal_uart *regs, uint32_t ints)
+{
+ regs->uartimsc &= ~ints;
+}
+
+static void versal_uart_intr_disableall(volatile versal_uart *regs)
+{
+ versal_uart_intr_disable(regs, versal_uart_intr_all());
+}
+
+static bool versal_uart_flags_clear(volatile versal_uart *regs, uint32_t flags)
+{
+ return (regs->uartfr & flags) == 0;
+}
+
+static void versal_uart_interrupt(void *arg)
+{
+ rtems_termios_tty *tty = arg;
+ versal_uart_context *ctx = rtems_termios_get_device_context(tty);
+ volatile versal_uart *regs = ctx->regs;
+ uint32_t uartmis = regs->uartmis;
+
+ versal_uart_intr_clear(regs, uartmis);
+
+ if ((uartmis & (VERSAL_UARTI_RTI | VERSAL_UARTI_RXI)) != 0) {
+ char buf[32];
+ int c = 0;
+ while (c < sizeof(buf) &&
+ versal_uart_flags_clear(regs, VERSAL_UARTFR_RXFE)) {
+ buf[c++] = (char) VERSAL_UARTDR_DATA_GET(regs->uartdr);
+ }
+ rtems_termios_enqueue_raw_characters(tty, buf, c);
+ }
+
+ if (ctx->transmitting) {
+ int sent = ctx->tx_queued;
+ ctx->transmitting = false;
+ ctx->tx_queued = 0;
+ versal_uart_intr_disable(regs, VERSAL_UARTI_TXI);
+ rtems_termios_dequeue_characters(tty, sent);
+ }
+}
+#endif
+
+static bool versal_uart_first_open(
+ rtems_termios_tty *tty,
+ rtems_termios_device_context *base,
+ struct termios *term,
+ rtems_libio_open_close_args_t *args
+)
+{
+#ifdef VERSAL_CONSOLE_USE_INTERRUPTS
+ versal_uart_context *ctx = (versal_uart_context *) base;
+ volatile versal_uart *regs = ctx->regs;
+ rtems_status_code sc;
+
+ ctx->transmitting = false;
+ ctx->tx_queued = 0;
+ ctx->first_send = true;
+#endif
+
+ rtems_termios_set_initial_baud(tty, VERSAL_UART_DEFAULT_BAUD);
+ versal_uart_initialize(base);
+
+#ifdef VERSAL_CONSOLE_USE_INTERRUPTS
+ regs->uartifls = VERSAL_UARTIFLS_RXIFLSEL(2) | VERSAL_UARTIFLS_TXIFLSEL(2);
+ regs->uartlcr_h |= VERSAL_UARTLCR_H_FEN;
+ versal_uart_intr_disableall(regs);
+ sc = rtems_interrupt_handler_install(
+ ctx->irq,
+ "UART",
+ RTEMS_INTERRUPT_SHARED,
+ versal_uart_interrupt,
+ tty
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ return false;
+ }
+ versal_uart_intr_clearall(regs);
+ versal_uart_intr_enable(regs, VERSAL_UARTI_RTI | VERSAL_UARTI_RXI);
+#endif
+
+ return true;
+}
+
+#ifdef VERSAL_CONSOLE_USE_INTERRUPTS
+static void versal_uart_last_close(
+ rtems_termios_tty *tty,
+ rtems_termios_device_context *base,
+ rtems_libio_open_close_args_t *args
+)
+{
+ versal_uart_context *ctx = (versal_uart_context *) base;
+ rtems_interrupt_handler_remove(ctx->irq, versal_uart_interrupt, tty);
+}
+#endif
+
+static void versal_uart_write_support(
+ rtems_termios_device_context *base,
+ const char *buf,
+ size_t len
+)
+{
+#ifdef VERSAL_CONSOLE_USE_INTERRUPTS
+ versal_uart_context *ctx = (versal_uart_context *) base;
+ volatile versal_uart *regs = ctx->regs;
+
+ if (len > 0) {
+ size_t len_remaining = len;
+ const char *p = &buf[0];
+ versal_uart_intr_enable(regs, VERSAL_UARTI_TXI);
+ /*
+ * The PL011 IP in the Versal needs preloading the TX FIFO with
+ * exactly 17 characters for the first TX interrupt to be
+ * generated.
+ */
+ if (ctx->first_send) {
+ ctx->first_send = false;
+ for (int i = 0; i < 17; ++i) {
+ regs->uartdr = VERSAL_UARTDR_DATA('\r');
+ }
+ }
+ while (versal_uart_flags_clear(regs, VERSAL_UARTFR_TXFF) &&
+ len_remaining > 0) {
+ regs->uartdr = VERSAL_UARTDR_DATA(*p++);
+ --len_remaining;
+ }
+ ctx->tx_queued = len - len_remaining;
+ ctx->transmitting = true;
+ }
+#else
+ ssize_t i;
+ for (i = 0; i < len; ++i) {
+ versal_uart_write_polled(base, buf[i]);
+ }
+#endif
+}
+
+static bool versal_uart_set_attributes(
+ rtems_termios_device_context *context,
+ const struct termios *term
+)
+{
+ versal_uart_context *ctx = (versal_uart_context *) context;
+ volatile versal_uart *regs = ctx->regs;
+ int32_t baud;
+ uint32_t ibauddiv = 0;
+ uint32_t fbauddiv = 0;
+ uint32_t mode = 0;
+ int rc;
+
+ /*
+ * Determine the baud rate
+ */
+ baud = rtems_termios_baud_to_number(term->c_ospeed);
+
+ if (baud > 0) {
+ uint32_t maxerr = 3;
+
+ rc = versal_cal_baud_rate(
+ VERSAL_UART_DEFAULT_BAUD,
+ maxerr,
+ &ibauddiv,
+ &fbauddiv
+ );
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ /*
+ * Configure the mode register
+ */
+ mode = regs->uartlcr_h & VERSAL_UARTLCR_H_FEN;
+
+ /*
+ * Parity
+ */
+ if ((term->c_cflag & PARENB) != 0) {
+ mode |= VERSAL_UARTLCR_H_PEN;
+ if ((term->c_cflag & PARODD) == 0) {
+ mode |= VERSAL_UARTLCR_H_EPS;
+ }
+ }
+
+ /*
+ * Character Size
+ */
+ switch (term->c_cflag & CSIZE)
+ {
+ case CS5:
+ mode = VERSAL_UARTLCR_H_WLEN_SET(mode, VERSAL_UARTLCR_H_WLEN_5);
+ break;
+ case CS6:
+ mode = VERSAL_UARTLCR_H_WLEN_SET(mode, VERSAL_UARTLCR_H_WLEN_6);
+ break;
+ case CS7:
+ mode = VERSAL_UARTLCR_H_WLEN_SET(mode, VERSAL_UARTLCR_H_WLEN_7);
+ break;
+ case CS8:
+ default:
+ mode = VERSAL_UARTLCR_H_WLEN_SET(mode, VERSAL_UARTLCR_H_WLEN_8);
+ break;
+ }
+
+ /*
+ * Stop Bits
+ */
+ if (term->c_cflag & CSTOPB) {
+ /* 2 stop bits */
+ mode |= VERSAL_UARTLCR_H_STP2;
+ }
+
+ versal_uart_intr_disableall(regs);
+
+ /*
+ * Wait for any data in the TXFIFO to be sent then wait while the
+ * transmiter is active.
+ */
+ while ((regs->uartfr & VERSAL_UARTFR_TXFE) == 0 ||
+ (regs->uartfr & VERSAL_UARTFR_BUSY) != 0) {
+ /* Wait */
+ }
+
+ regs->uartcr = VERSAL_UARTCR_UARTEN;
+ /* Ignore baud rate of B0. There are no modem control lines to de-assert */
+ if (baud > 0) {
+ regs->uartibrd = VERSAL_UARTIBRD_BAUD_DIVINT(ibauddiv);
+ regs->uartfbrd = VERSAL_UARTFBRD_BAUD_DIVFRAC(fbauddiv);
+ }
+ regs->uartlcr_h = mode;
+
+ /* Control: receive, transmit, uart enable, no CTS, no RTS, no loopback */
+ regs->uartcr = VERSAL_UARTCR_RXE
+ | VERSAL_UARTCR_TXE
+ | VERSAL_UARTCR_UARTEN;
+
+#ifdef VERSAL_CONSOLE_USE_INTERRUPTS
+ versal_uart_intr_clearall(regs);
+ versal_uart_intr_enable(regs, VERSAL_UARTI_RTI | VERSAL_UARTI_RXI);
+#endif
+
+ return true;
+}
+
+const rtems_termios_device_handler versal_uart_handler = {
+ .first_open = versal_uart_first_open,
+ .set_attributes = versal_uart_set_attributes,
+ .write = versal_uart_write_support,
+#ifdef VERSAL_CONSOLE_USE_INTERRUPTS
+ .last_close = versal_uart_last_close,
+ .mode = TERMIOS_IRQ_DRIVEN
+#else
+ .poll_read = versal_uart_read_polled,
+ .mode = TERMIOS_POLLED
+#endif
+};
diff --git a/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart-regs.h b/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart-regs.h
index 59db8f950a..30f918bc60 100644
--- a/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart-regs.h
+++ b/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart-regs.h
@@ -110,7 +110,6 @@ typedef struct versal_uart {
#define VERSAL_UARTCR_RXE BSP_BIT32(9)
#define VERSAL_UARTCR_TXE BSP_BIT32(8)
#define VERSAL_UARTCR_LBE BSP_BIT32(7)
-//#define VERSAL_UARTCR_SIREN BSP_BIT32()?
#define VERSAL_UARTCR_UARTEN BSP_BIT32(0)
uint32_t uartifls;
#define VERSAL_UARTIFLS_RXIFLSEL(val) BSP_FLD32(val, 3, 5)
diff --git a/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart.h b/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart.h
index 95b5172218..cc6b60b77c 100644
--- a/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart.h
+++ b/bsps/aarch64/xilinx-versal/include/dev/serial/versal-uart.h
@@ -54,7 +54,9 @@ extern "C" {
typedef struct {
rtems_termios_device_context base;
volatile struct versal_uart *regs;
- bool transmitting; /* Currently unused */
+ volatile size_t tx_queued;
+ volatile bool transmitting;
+ bool first_send;
rtems_vector_number irq;
} versal_uart_context;
diff --git a/spec/build/bsps/aarch64/xilinx-versal/grp.yml b/spec/build/bsps/aarch64/xilinx-versal/grp.yml
index 262278f214..badfa07fcc 100644
--- a/spec/build/bsps/aarch64/xilinx-versal/grp.yml
+++ b/spec/build/bsps/aarch64/xilinx-versal/grp.yml
@@ -24,6 +24,8 @@ links:
uid: abi
- role: build-dependency
uid: obj
+- role: build-dependency
+ uid: optconirq
- role: build-dependency
uid: optloadoff
- role: build-dependency
diff --git a/spec/build/bsps/aarch64/xilinx-versal/obj.yml b/spec/build/bsps/aarch64/xilinx-versal/obj.yml
index 2daebabc95..ac7e6519db 100644
--- a/spec/build/bsps/aarch64/xilinx-versal/obj.yml
+++ b/spec/build/bsps/aarch64/xilinx-versal/obj.yml
@@ -26,6 +26,7 @@ source:
- bsps/aarch64/shared/mmu/vmsav8-64.c
- bsps/aarch64/xilinx-versal/console/console.c
- bsps/aarch64/xilinx-versal/dev/serial/versal-uart-polled.c
+- bsps/aarch64/xilinx-versal/dev/serial/versal-uart.c
- bsps/aarch64/xilinx-versal/start/bspstart.c
- bsps/aarch64/xilinx-versal/start/bspstarthooks.c
- bsps/aarch64/xilinx-versal/start/bspstartmmu.c
diff --git a/spec/build/bsps/aarch64/xilinx-versal/optconirq.yml b/spec/build/bsps/aarch64/xilinx-versal/optconirq.yml
new file mode 100644
index 0000000000..24108512fc
--- /dev/null
+++ b/spec/build/bsps/aarch64/xilinx-versal/optconirq.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-boolean: null
+- define-condition: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 Chris Johns (chris at contemporary.software)
+default: true
+default-by-variant: []
+description: |
+ use interrupt driven mode for console devices (used by default)
+enabled-by: true
+links: []
+name: VERSAL_CONSOLE_USE_INTERRUPTS
+type: build
--
2.19.1
More information about the devel
mailing list