drivers/apbuart: add TX FIFO interrupt support

Use TX FIFO level interrupt if available in hardware. It matches the
Zephyr UART API and avoids "bootstrapping" which is needed when using
the TX edge interrupt ("TI"). TX FIFO has room for up to 32 characters
and will typically reduce the number of interrupts.

Details:
APBUART can be synthesized with or without support for TX/RX FIFO.
Edge interrupts which fire when TX holding register changes and RX data
available are always available, independent of the FIFO configuration.
If FIFO is made available at synthesis time, two additional interrupts
become available: TX FIFO half-empty and RX FIFO half-full. These
are level interrupts.

Signed-off-by: Martin Åberg <martin.aberg@gaisler.com>
This commit is contained in:
Martin Åberg 2021-01-07 14:21:29 +01:00 committed by Anas Nashif
commit 40ab00ac3d

View file

@ -312,6 +312,17 @@ static int apbuart_fifo_fill(const struct device *dev, const uint8_t *tx_data,
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
int i;
if (DEV_DATA(dev)->usefifo) {
/* Transmitter FIFO full flag is available. */
for (
i = 0;
(i < size) && !(regs->status & APBUART_STATUS_TF);
i++
) {
regs->data = tx_data[i];
}
return i;
}
for (i = 0; (i < size) && (regs->status & APBUART_STATUS_TE); i++) {
regs->data = tx_data[i];
}
@ -337,6 +348,12 @@ static void apbuart_irq_tx_enable(const struct device *dev)
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
unsigned int key;
if (DEV_DATA(dev)->usefifo) {
/* Enable the FIFO level interrupt */
regs->ctrl |= APBUART_CTRL_TF;
return;
}
regs->ctrl |= APBUART_CTRL_TI;
/*
* The "TI" interrupt is an edge interrupt. It fires each time the TX
@ -358,13 +375,16 @@ static void apbuart_irq_tx_disable(const struct device *dev)
{
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
regs->ctrl &= ~APBUART_CTRL_TI;
regs->ctrl &= ~(APBUART_CTRL_TF | APBUART_CTRL_TI);
}
static int apbuart_irq_tx_ready(const struct device *dev)
{
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
if (DEV_DATA(dev)->usefifo) {
return !(regs->status & APBUART_STATUS_TF);
}
return !!(regs->status & APBUART_STATUS_TE);
}
@ -405,9 +425,18 @@ static int apbuart_irq_is_pending(const struct device *dev)
if ((ctrl & APBUART_CTRL_RI) && (status & APBUART_STATUS_DR)) {
return 1;
}
if ((ctrl & APBUART_CTRL_TI) && (status & APBUART_STATUS_TE)) {
return 1;
if (DEV_DATA(dev)->usefifo) {
/* TH is the TX FIFO half-empty flag */
if (status & APBUART_STATUS_TH) {
return 1;
}
} else {
if ((ctrl & APBUART_CTRL_TI) && (status & APBUART_STATUS_TE)) {
return 1;
}
}
return 0;
}