Skip to content

Commit

Permalink
imx9/serial: Take proper use of RX/TX FIFOs, clean up interrupt servi…
Browse files Browse the repository at this point in the history
…ce routine

- i.MX93 LPUARTs have 16-byte RX and TX FIFOs. Take those into use and correct some related register definitions
- There is no reason to loop inside interrupt handler, remove the looping

Signed-off-by: Jukka Laitinen <[email protected]>
  • Loading branch information
Jukka Laitinen committed Oct 29, 2024
1 parent adf17f7 commit 5d4d296
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 91 deletions.
24 changes: 12 additions & 12 deletions arch/arm64/src/imx9/hardware/imx9_lpuart.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,22 +287,22 @@

/* LPUART Watermark Register (WATER) */

#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-1: Transmit Watermark (TXWATER) */
#define LPUART_WATER_TXWATER_MASK (0x03 << LPUART_WATER_TXWATER_SHIFT)
#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-3: Transmit Watermark (TXWATER) */
#define LPUART_WATER_TXWATER_MASK (0x0f << LPUART_WATER_TXWATER_SHIFT)
# define LPUART_WATER_TXWATER(n) ((n) << LPUART_WATER_TXWATER_SHIFT)
/* Bits 2-7: Reserved */
#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-10: Transmit Counter (TXCOUNT) */
#define LPUART_WATER_TXCOUNT_MASK (0x07 << LPUART_WATER_TXCOUNT_SHIFT)
/* Bits 4-7: Reserved */
#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-12: Transmit Counter (TXCOUNT) */
#define LPUART_WATER_TXCOUNT_MASK (0x1f << LPUART_WATER_TXCOUNT_SHIFT)
# define LPUART_WATER_TXCOUNT(n) ((n) << LPUART_WATER_TXCOUNT_SHIFT)
/* Bits 11-15: Reserved */
#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-17: Receive Watermark (RXWATER) */
#define LPUART_WATER_RXWATER_MASK (0x03 << LPUART_WATER_RXWATER_SHIFT)
/* Bits 13-15: Reserved */
#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-19: Receive Watermark (RXWATER) */
#define LPUART_WATER_RXWATER_MASK (0x0f << LPUART_WATER_RXWATER_SHIFT)
# define LPUART_WATER_RXWATER(n) ((n) << LPUART_WATER_RXWATER_SHIFT)
/* Bits 18-23: Reserved */
#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-26: Receive Counter (RXCOUNT) */
#define LPUART_WATER_RXCOUNT_MASK (0x07 << LPUART_WATER_RXCOUNT_SHIFT)
/* Bits 20-23: Reserved */
#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-28: Receive Counter (RXCOUNT) */
#define LPUART_WATER_RXCOUNT_MASK (0x1f << LPUART_WATER_RXCOUNT_SHIFT)
# define LPUART_WATER_RXCOUNT(n) ((n) << LPUART_WATER_RXCOUNT_SHIFT)
/* Bits 27-31: Reserved */
/* Bits 29-31: Reserved */

/* Data read-only Register (DATARO) */

Expand Down
5 changes: 5 additions & 0 deletions arch/arm64/src/imx9/imx9_lowputc.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,11 @@ int imx9_lpuart_configure(uint32_t base, int uartnum,
regval &= ~LPUART_GLOBAL_RST;
putreg32(regval, base + IMX9_LPUART_GLOBAL_OFFSET);

/* Enable RX and TX FIFOs */

putreg32(LPUART_FIFO_RXFE | LPUART_FIFO_TXFE,
base + IMX9_LPUART_FIFO_OFFSET);

/* Construct MODIR register */

regval = 0;
Expand Down
155 changes: 76 additions & 79 deletions arch/arm64/src/imx9/imx9_lpuart.c
Original file line number Diff line number Diff line change
Expand Up @@ -1473,8 +1473,6 @@ static int imx9_interrupt(int irq, void *context, void *arg)
struct imx9_uart_s *priv;
uint32_t usr;
uint32_t lsr;
int passes = 0;
bool handled;

DEBUGASSERT(dev != NULL && dev != NULL);
priv = (struct imx9_uart_s *)dev;
Expand All @@ -1485,96 +1483,82 @@ static int imx9_interrupt(int irq, void *context, void *arg)
pm_activity(PM_IDLE_DOMAIN, CONFIG_IMX9_PM_SERIAL_ACTIVITY);
#endif

/* Loop until there are no characters to be transferred or,
* until we have been looping for a long time.
/* Get the current UART status and check for loop
* termination conditions
*/

handled = true;
for (passes = 0; passes < 256 && handled; passes++)
{
handled = false;

/* Get the current UART status and check for loop
* termination conditions
*/
usr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);

usr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
/* Removed all W1C from the last sr */

/* Removed all W1C from the last sr */
lsr = usr & ~(LPUART_STAT_LBKDIF | LPUART_STAT_RXEDGIF |
LPUART_STAT_IDLE | LPUART_STAT_OR |
LPUART_STAT_NF | LPUART_STAT_FE |
LPUART_STAT_PF | LPUART_STAT_MA1F |
LPUART_STAT_MA2F);

lsr = usr & ~(LPUART_STAT_LBKDIF | LPUART_STAT_RXEDGIF |
LPUART_STAT_IDLE | LPUART_STAT_OR |
LPUART_STAT_NF | LPUART_STAT_FE |
LPUART_STAT_PF | LPUART_STAT_MA1F |
LPUART_STAT_MA2F);
/* Keep what we will service */

/* Keep what we will service */
usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR |
LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF |
LPUART_STAT_IDLE);

usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR |
LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF |
LPUART_STAT_IDLE);
/* Clear serial overrun, parity and framing errors */

/* Clear serial overrun, parity and framing errors */

if ((usr & LPUART_STAT_OR) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_OR | lsr);
}
if ((usr & LPUART_STAT_OR) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_OR | lsr);
}

if ((usr & LPUART_STAT_NF) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_NF | lsr);
}
if ((usr & LPUART_STAT_NF) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_NF | lsr);
}

if ((usr & LPUART_STAT_PF) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_PF | lsr);
}
if ((usr & LPUART_STAT_PF) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_PF | lsr);
}

if ((usr & LPUART_STAT_FE) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_FE | lsr);
}
if ((usr & LPUART_STAT_FE) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_FE | lsr);
}

if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0)
{
/* Discard data */
if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0)
{
/* Discard data */

imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET);
}
imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET);
}

#ifdef SERIAL_HAVE_RXDMA
/* The line going to idle, deliver any fractions of RX data */
/* The line going to idle, deliver any fractions of RX data */

if ((usr & LPUART_STAT_IDLE) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_IDLE | lsr);
imx9_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE);
}
if ((usr & LPUART_STAT_IDLE) != 0)
{
imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
LPUART_STAT_IDLE | lsr);
imx9_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE);
}
#endif

/* Handle incoming, receive bytes */
/* Handle incoming, receive bytes */

if ((usr & LPUART_STAT_RDRF) != 0 &&
(priv->ie & LPUART_CTRL_RIE) != 0)
{
uart_recvchars(dev);
handled = true;
}
if ((priv->ie & LPUART_CTRL_RIE) != 0 && imx9_rxavailable(&priv->dev))
{
uart_recvchars(dev);
}

/* Handle outgoing, transmit bytes */
/* Handle outgoing, transmit bytes */

if ((usr & LPUART_STAT_TDRE) != 0 &&
(priv->ie & LPUART_CTRL_TIE) != 0)
{
uart_xmitchars(dev);
handled = true;
}
if ((priv->ie & LPUART_CTRL_TIE) != 0)
{
uart_xmitchars(dev);
}

return OK;
Expand Down Expand Up @@ -1947,8 +1931,8 @@ static bool imx9_rxavailable(struct uart_dev_s *dev)

/* Return true is data is ready in the Rx FIFO */

regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
return ((regval & LPUART_STAT_RDRF) != 0);
regval = imx9_serialin(priv, IMX9_LPUART_WATER_OFFSET);
return ((regval & LPUART_WATER_RXCOUNT_MASK) != 0);
}
#endif

Expand Down Expand Up @@ -2356,24 +2340,37 @@ static void imx9_txint(struct uart_dev_s *dev, bool enable)
* Name: imx9_txready
*
* Description:
* Return true if the transmit register is available to be written to
* Return true if the transmit fifo is available to be written to
*
****************************************************************************/

static bool imx9_txready(struct uart_dev_s *dev)
{
struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
uint32_t regval;
uint32_t fifo_size;
uint32_t fifo_count;

/* Read the fifo size and current fill ratio. Return true if fifo is not
* full
*/

regval = imx9_serialin(priv, IMX9_LPUART_FIFO_OFFSET);
fifo_size = (regval & LPUART_FIFO_TXFIFOSIZE_MASK) >>
LPUART_FIFO_TXFIFOSIZE_SHIFT;
fifo_size = fifo_size == 0 ? 1 : (1 << (fifo_size + 1));
regval = imx9_serialin(priv, IMX9_LPUART_WATER_OFFSET);
fifo_count = (regval & LPUART_WATER_TXCOUNT_MASK) >>
LPUART_WATER_TXCOUNT_SHIFT;

regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
return ((regval & LPUART_STAT_TDRE) != 0);
return fifo_count < fifo_size;
}

/****************************************************************************
* Name: imx9_txempty
*
* Description:
* Return true if the transmit reg is empty
* Return true if the transmit fifo is empty
*
****************************************************************************/

Expand All @@ -2382,8 +2379,8 @@ static bool imx9_txempty(struct uart_dev_s *dev)
struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
uint32_t regval;

regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
return ((regval & LPUART_STAT_TDRE) != 0);
regval = imx9_serialin(priv, IMX9_LPUART_WATER_OFFSET);
return (regval & LPUART_WATER_TXCOUNT_MASK) == 0;
}

/****************************************************************************
Expand Down

0 comments on commit 5d4d296

Please sign in to comment.