mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-19 10:50:57 +08:00
arm/xilinx: Fix zynq-uart interrupt receive
- Trigger on a single character entering the RX FIFO - Disable the RX timeout - Send up to a FIFO full of data
This commit is contained in:
@@ -121,35 +121,35 @@ void zynq_uart_initialize(rtems_termios_device_context *base)
|
||||
volatile zynq_uart *regs = ctx->regs;
|
||||
uint32_t brgr = 0x3e;
|
||||
uint32_t bauddiv = 0x6;
|
||||
uint32_t mode_clks = regs->mode & ZYNQ_UART_MODE_CLKS;
|
||||
|
||||
zynq_uart_reset_tx_flush(ctx);
|
||||
while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0 ||
|
||||
(regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TACTIVE) != 0) {
|
||||
/* Wait */
|
||||
}
|
||||
|
||||
zynq_cal_baud_rate(ZYNQ_UART_DEFAULT_BAUD, &brgr, &bauddiv, regs->mode);
|
||||
zynq_cal_baud_rate(ZYNQ_UART_DEFAULT_BAUD, &brgr, &bauddiv, mode_clks);
|
||||
|
||||
regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
|
||||
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->control = 0;
|
||||
regs->control = ZYNQ_UART_CONTROL_RXDIS | ZYNQ_UART_CONTROL_TXDIS;
|
||||
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_RXDIS | ZYNQ_UART_CONTROL_TXDIS;
|
||||
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;
|
||||
regs->control = ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
|
||||
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)
|
||||
| mode_clks;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
while (zynq_uart_read_polled(base) >= 0) {
|
||||
/* Drop */
|
||||
}
|
||||
|
||||
zynq_uart_reset_tx_flush(ctx);
|
||||
}
|
||||
|
||||
int zynq_uart_read_polled(rtems_termios_device_context *base)
|
||||
@@ -172,7 +172,7 @@ void zynq_uart_write_polled(
|
||||
zynq_uart_context *ctx = (zynq_uart_context *) base;
|
||||
volatile zynq_uart *regs = ctx->regs;
|
||||
|
||||
while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TFUL) != 0) {
|
||||
while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TNFUL) != 0) {
|
||||
/* Wait */
|
||||
}
|
||||
|
||||
@@ -187,7 +187,8 @@ void zynq_uart_reset_tx_flush(zynq_uart_context *ctx)
|
||||
while (c-- > 0)
|
||||
zynq_uart_write_polled(&ctx->base, '\r');
|
||||
|
||||
while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0) {
|
||||
while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0 ||
|
||||
(regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TACTIVE) != 0) {
|
||||
/* Wait */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,24 +37,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
|
||||
@@ -76,11 +76,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 +118,23 @@ 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 (((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;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
zynq_uart_write_polled(base, buf[i]);
|
||||
}
|
||||
@@ -164,6 +168,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 +213,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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user