summaryrefslogtreecommitdiffstats
path: root/bsps/shared/dev/serial/zynq-uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/shared/dev/serial/zynq-uart.c')
-rw-r--r--bsps/shared/dev/serial/zynq-uart.c99
1 files changed, 58 insertions, 41 deletions
diff --git a/bsps/shared/dev/serial/zynq-uart.c b/bsps/shared/dev/serial/zynq-uart.c
index 8503e31d49..0489288271 100644
--- a/bsps/shared/dev/serial/zynq-uart.c
+++ b/bsps/shared/dev/serial/zynq-uart.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (C) 2013, 2017 embedded brains GmbH
+ * Copyright (C) 2013, 2017 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
#include <dev/serial/zynq-uart.h>
#include <dev/serial/zynq-uart-regs.h>
#include <bsp/irq.h>
+#include <rtems/termiostypes.h>
#include <bspopts.h>
@@ -37,24 +38,24 @@ static void zynq_uart_interrupt(void *arg)
rtems_termios_tty *tty = arg;
zynq_uart_context *ctx = rtems_termios_get_device_context(tty);
volatile zynq_uart *regs = ctx->regs;
- uint32_t channel_sts;
- if ((regs->irq_sts & (ZYNQ_UART_TIMEOUT | ZYNQ_UART_RTRIG)) != 0) {
- regs->irq_sts = ZYNQ_UART_TIMEOUT | ZYNQ_UART_RTRIG;
-
- do {
- char c = (char) ZYNQ_UART_TX_RX_FIFO_FIFO_GET(regs->tx_rx_fifo);
-
- rtems_termios_enqueue_raw_characters(tty, &c, 1);
-
- channel_sts = regs->channel_sts;
- } while ((channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) == 0);
- } else {
- channel_sts = regs->channel_sts;
+ if ((regs->irq_sts & ZYNQ_UART_RTRIG) != 0) {
+ char buf[32];
+ int c = 0;
+ regs->irq_sts = ZYNQ_UART_RTRIG;
+ while (c < sizeof(buf) &&
+ (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) == 0) {
+ buf[c++] = (char) ZYNQ_UART_TX_RX_FIFO_FIFO_GET(regs->tx_rx_fifo);
+ }
+ rtems_termios_enqueue_raw_characters(tty, buf, c);
}
- if (ctx->transmitting && (channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) != 0) {
- rtems_termios_dequeue_characters(tty, 1);
+ if (ctx->transmitting) {
+ int sent = ctx->tx_queued;
+ regs->irq_dis = ZYNQ_UART_TEMPTY;
+ ctx->transmitting = false;
+ ctx->tx_queued = 0;
+ rtems_termios_dequeue_characters(tty, sent);
}
}
#endif
@@ -66,21 +67,20 @@ static bool zynq_uart_first_open(
rtems_libio_open_close_args_t *args
)
{
-#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
zynq_uart_context *ctx = (zynq_uart_context *) base;
volatile zynq_uart *regs = ctx->regs;
+#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
rtems_status_code sc;
#endif
rtems_termios_set_initial_baud(tty, ZYNQ_UART_DEFAULT_BAUD);
- zynq_uart_initialize(base);
+ zynq_uart_initialize(regs);
#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
- regs->rx_timeout = 32;
- regs->rx_fifo_trg_lvl = ZYNQ_UART_FIFO_DEPTH / 2;
+ regs->rx_fifo_trg_lvl = 1;
regs->irq_dis = 0xffffffff;
regs->irq_sts = 0xffffffff;
- regs->irq_en = ZYNQ_UART_RTRIG | ZYNQ_UART_TIMEOUT;
+ regs->irq_en = ZYNQ_UART_RTRIG;
sc = rtems_interrupt_handler_install(
ctx->irq,
"UART",
@@ -109,30 +109,43 @@ static void zynq_uart_last_close(
}
#endif
+#ifndef ZYNQ_CONSOLE_USE_INTERRUPTS
+static int zynq_uart_read_polled(rtems_termios_device_context *base)
+{
+ zynq_uart_context *ctx = (zynq_uart_context *) base;
+ return zynq_uart_read_char_polled(ctx->regs);
+}
+#endif
+
static void zynq_uart_write_support(
rtems_termios_device_context *base,
const char *buf,
size_t len
)
{
-#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
zynq_uart_context *ctx = (zynq_uart_context *) base;
volatile zynq_uart *regs = ctx->regs;
+#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
+
+ regs->irq_dis = ZYNQ_UART_TEMPTY;
if (len > 0) {
- ctx->transmitting = true;
+ const char *p = &buf[0];
regs->irq_sts = ZYNQ_UART_TEMPTY;
+ while (((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TNFUL) == 0) &&
+ len > 0) {
+ regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(*p);
+ ++p;
+ ++ctx->tx_queued;
+ --len;
+ }
+ ctx->transmitting = true;
regs->irq_en = ZYNQ_UART_TEMPTY;
- regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(buf[0]);
- } else {
- ctx->transmitting = false;
- regs->irq_dis = ZYNQ_UART_TEMPTY;
}
#else
- ssize_t i;
-
+ size_t i;
for (i = 0; i < len; ++i) {
- zynq_uart_write_polled(base, buf[i]);
+ zynq_uart_write_char_polled(regs, buf[i]);
}
#endif
}
@@ -164,6 +177,7 @@ static bool zynq_uart_set_attributes(
/*
* Configure the mode register
*/
+ mode = regs->mode & ZYNQ_UART_MODE_CLKS;
mode |= ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL);
/*
@@ -208,22 +222,25 @@ static bool zynq_uart_set_attributes(
mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_1);
}
- regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
- regs->mode = mode;
+ /*
+ * Wait for any data in the TXFIFO to be sent then wait while the
+ * transmiter is active.
+ */
+ while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0 ||
+ (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TACTIVE) != 0) {
+ /* Wait */
+ }
+
+ regs->control = ZYNQ_UART_CONTROL_RXDIS | ZYNQ_UART_CONTROL_TXDIS;
/* Ignore baud rate of B0. There are no modem control lines to de-assert */
if (baud > 0) {
regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
- regs->control |= ZYNQ_UART_CONTROL_RXRES
- | ZYNQ_UART_CONTROL_TXRES;
}
- regs->control |= ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
-
- /*
- * Some ZynqMP UARTs have a hardware bug that causes TX/RX logic restarts to
- * require a kick after baud rate registers are initialized.
- */
- zynq_uart_write_polled(context, 0);
+ regs->control = ZYNQ_UART_CONTROL_RXRES | ZYNQ_UART_CONTROL_TXRES;
+ regs->mode = mode;
+ regs->irq_sts = 0xffffffff;
+ regs->control = ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
return true;
}