[PATCH rtems] arm/xilinx: Fix zynq-uart interrupt receive

Joel Sherrill joel at rtems.org
Tue Aug 17 13:21:31 UTC 2021


I'm only asking where and how did this get tested? BSPs? Qemu/HW? Input?

Long overdue. I just hope it stays fixed.

On Tue, Aug 17, 2021, 3:39 AM <chrisj at rtems.org> wrote:

> From: Chris Johns <chrisj at rtems.org>
>
> - Trigger on a single character entering the RX FIFO
>
> - Disable the RX timeout
>
> - Send up to a FIFO full of data
> ---
>  bsps/include/dev/serial/zynq-uart.h       |  1 +
>  bsps/shared/dev/serial/zynq-uart-polled.c | 18 ++-----
>  bsps/shared/dev/serial/zynq-uart.c        | 66 +++++++++++------------
>  3 files changed, 36 insertions(+), 49 deletions(-)
>
> diff --git a/bsps/include/dev/serial/zynq-uart.h
> b/bsps/include/dev/serial/zynq-uart.h
> index 220d9b7717..b21e16f6de 100644
> --- a/bsps/include/dev/serial/zynq-uart.h
> +++ b/bsps/include/dev/serial/zynq-uart.h
> @@ -52,6 +52,7 @@ extern "C" {
>  typedef struct {
>    rtems_termios_device_context base;
>    volatile struct zynq_uart *regs;
> +  int tx_queued;
>    bool transmitting;
>    rtems_vector_number irq;
>  } zynq_uart_context;
> diff --git a/bsps/shared/dev/serial/zynq-uart-polled.c
> b/bsps/shared/dev/serial/zynq-uart-polled.c
> index 95c51dea11..201d9070d3 100644
> --- a/bsps/shared/dev/serial/zynq-uart-polled.c
> +++ b/bsps/shared/dev/serial/zynq-uart-polled.c
> @@ -126,30 +126,18 @@ void
> zynq_uart_initialize(rtems_termios_device_context *base)
>
>    zynq_cal_baud_rate(ZYNQ_UART_DEFAULT_BAUD, &brgr, &bauddiv, regs->mode);
>
> -  regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
> -  regs->control = ZYNQ_UART_CONTROL_RXDIS
> -    | ZYNQ_UART_CONTROL_TXDIS;
> +  regs->control = ZYNQ_UART_CONTROL_RXDIS | ZYNQ_UART_CONTROL_TXDIS;
>    regs->mode = ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL)
>      | ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE)
>      | ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
>    regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
>    regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
>    /* A Tx/Rx logic reset must be issued after baud rate manipulation */
> -  regs->control = ZYNQ_UART_CONTROL_RXDIS
> -    | ZYNQ_UART_CONTROL_TXDIS
> -    | ZYNQ_UART_CONTROL_RXRES
> -    | ZYNQ_UART_CONTROL_TXRES;
> +  regs->control = ZYNQ_UART_CONTROL_RXRES | ZYNQ_UART_CONTROL_TXRES;
>    regs->rx_fifo_trg_lvl = ZYNQ_UART_RX_FIFO_TRG_LVL_RTRIG(0);
>    regs->rx_timeout = ZYNQ_UART_RX_TIMEOUT_RTO(0);
>    regs->control = ZYNQ_UART_CONTROL_RXEN
> -    | ZYNQ_UART_CONTROL_TXEN
> -    | ZYNQ_UART_CONTROL_RSTTO;
> -
> -  /*
> -   * 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(base, 0);
> +    | ZYNQ_UART_CONTROL_TXEN;
>  }
>
>  int zynq_uart_read_polled(rtems_termios_device_context *base)
> diff --git a/bsps/shared/dev/serial/zynq-uart.c
> b/bsps/shared/dev/serial/zynq-uart.c
> index 8503e31d49..5906a015d9 100644
> --- a/bsps/shared/dev/serial/zynq-uart.c
> +++ b/bsps/shared/dev/serial/zynq-uart.c
> @@ -37,24 +37,25 @@ 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 &&
> +      (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) != 0) {
> +    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
> @@ -76,11 +77,10 @@ static bool zynq_uart_first_open(
>    zynq_uart_initialize(base);
>
>  #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",
> @@ -119,18 +119,22 @@ static void zynq_uart_write_support(
>    zynq_uart_context *ctx = (zynq_uart_context *) base;
>    volatile zynq_uart *regs = ctx->regs;
>
> +  regs->irq_dis = ZYNQ_UART_TEMPTY;
> +
>    if (len > 0) {
> -    ctx->transmitting = true;
> +    const char *p = &buf[0];
>      regs->irq_sts = ZYNQ_UART_TEMPTY;
> +    while (ctx->tx_queued < 32 && 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;
> -
>    for (i = 0; i < len; ++i) {
>      zynq_uart_write_polled(base, buf[i]);
>    }
> @@ -208,22 +212,16 @@ 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->control = ZYNQ_UART_CONTROL_RXDIS | ZYNQ_UART_CONTROL_TXDIS;
>    regs->mode = mode;
>    /* 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->irq_sts = 0xffffffff;
> +  regs->control = ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
>
>    return true;
>  }
> --
> 2.24.1
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20210817/0ccfc8b0/attachment.html>


More information about the devel mailing list