From adf17f76bb5f0055ce5764c5cd607f4ff65ba688 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 25 Oct 2024 12:40:10 +0300 Subject: [PATCH 1/2] imx9/serial: Clean up the flow control code - Remove GPIO (SW) based flow control. It didn't work, and pure HW flow control seems to work fine - Remove some unneeded ifdefs and change bit-field flags to booleans to clean up the code Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/imx9_lpuart.c | 301 +++++++----------------------- 1 file changed, 70 insertions(+), 231 deletions(-) diff --git a/arch/arm64/src/imx9/imx9_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c index 601770b01f840..0128a73080fd3 100644 --- a/arch/arm64/src/imx9/imx9_lpuart.c +++ b/arch/arm64/src/imx9/imx9_lpuart.c @@ -294,36 +294,28 @@ struct imx9_uart_s { - struct uart_dev_s dev; /* Generic UART device */ - const uint32_t uartbase; /* Base address of UART registers */ - const int uartnum; /* LPUART number 1-8 */ - uint32_t baud; /* Configured baud */ - uint32_t ie; /* Saved enabled interrupts */ - uint8_t irq; /* IRQ associated with this UART */ - uint8_t parity; /* 0=none, 1=odd, 2=even */ - uint8_t bits; /* Number of bits (7 or 8) */ -#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) - uint8_t inviflow:1; /* Invert RTS sense */ - const uint32_t rts_gpio; /* LPUART RTS GPIO pin configuration */ -#endif -#ifdef CONFIG_SERIAL_OFLOWCONTROL - const uint32_t cts_gpio; /* LPUART CTS GPIO pin configuration */ -#endif - uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */ -#ifdef CONFIG_SERIAL_IFLOWCONTROL - uint8_t iflow:1; /* input flow control (RTS) enabled */ -#endif -#ifdef CONFIG_SERIAL_OFLOWCONTROL - uint8_t oflow:1; /* output flow control (CTS) enabled */ -#endif -#ifdef CONFIG_SERIAL_RS485CONTROL - uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */ -#endif + struct uart_dev_s dev; /* Generic UART device */ + + const uint32_t uartbase; /* Base address of UART registers */ + const int uartnum; /* LPUART number 1-8 */ + const bool usects; /* output flow control (CTS) available */ + const bool userts; /* input flow control (RTS) available */ + const bool rs485mode; /* We are in RS485 (RTS on TX) mode */ + const bool inviflow; /* Invert RTS sense */ + uint32_t baud; /* Configured baud */ + uint32_t ie; /* Saved enabled interrupts */ + uint8_t irq; /* IRQ associated with this UART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* true: Configure with 2 stop bits vs 1 */ + bool oflow; /* output flow control (CTS) enabled */ + bool iflow; /* input flow control (RTS) enabled */ + /* TX DMA state */ #ifdef SERIAL_HAVE_TXDMA - const unsigned int txch; /* DMAMUX source of TX DMA request */ - DMACH_HANDLE txdma; /* currently-open transmit DMA stream */ + const unsigned int txch; /* DMAMUX source of TX DMA request */ + DMACH_HANDLE txdma; /* currently-open transmit DMA stream */ #endif /* RX DMA state */ @@ -369,10 +361,6 @@ static bool imx9_rxavailable(struct uart_dev_s *dev); static void imx9_txint(struct uart_dev_s *dev, bool enable); #endif -#ifdef CONFIG_SERIAL_IFLOWCONTROL -static bool imx9_rxflowcontrol(struct uart_dev_s *dev, - unsigned int nbuffered, bool upper); -#endif static void imx9_send(struct uart_dev_s *dev, int ch); static bool imx9_txready(struct uart_dev_s *dev); @@ -430,7 +418,7 @@ static const struct uart_ops_s g_lpuart_ops = .rxint = imx9_rxint, .rxavailable = imx9_rxavailable, #ifdef CONFIG_SERIAL_IFLOWCONTROL - .rxflowcontrol = imx9_rxflowcontrol, + .rxflowcontrol = NULL, #endif .send = imx9_send, .txint = imx9_txint, @@ -451,7 +439,7 @@ static const struct uart_ops_s g_lpuart_rxtxdma_ops = .rxint = imx9_dma_rxint, .rxavailable = imx9_dma_rxavailable, #ifdef CONFIG_SERIAL_IFLOWCONTROL - .rxflowcontrol = imx9_rxflowcontrol, + .rxflowcontrol = NULL, #endif .send = imx9_send, .txint = imx9_dma_txint, @@ -474,7 +462,7 @@ static const struct uart_ops_s g_lpuart_rxdma_ops = .rxint = imx9_dma_rxint, .rxavailable = imx9_dma_rxavailable, #ifdef CONFIG_SERIAL_IFLOWCONTROL - .rxflowcontrol = imx9_rxflowcontrol, + .rxflowcontrol = NULL, #endif .send = imx9_send, .txint = imx9_txint, @@ -495,7 +483,7 @@ static const struct uart_ops_s g_lpuart_txdma_ops = .rxint = imx9_rxint, .rxavailable = imx9_rxavailable, #ifdef CONFIG_SERIAL_IFLOWCONTROL - .rxflowcontrol = imx9_rxflowcontrol, + .rxflowcontrol = NULL, #endif .send = imx9_send, .txint = imx9_dma_txint, @@ -638,24 +626,19 @@ static struct imx9_uart_s g_lpuart1priv = .bits = CONFIG_LPUART1_BITS, .stopbits2 = CONFIG_LPUART1_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART1_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART1_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART1_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART1_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART1_TXDMA @@ -663,7 +646,7 @@ static struct imx9_uart_s g_lpuart1priv = # endif # ifdef CONFIG_LPUART1_RXDMA .rxch = DMA_REQUEST_MUXLPUART1RX, - .rxfifo = g_lpuart1rxfifo, + .rxfifo = g_lpuart1rxfifo, # endif }; #endif @@ -702,24 +685,19 @@ static struct imx9_uart_s g_lpuart2priv = .bits = CONFIG_LPUART2_BITS, .stopbits2 = CONFIG_LPUART2_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART2_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART2_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART2_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART2_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART2_TXDMA @@ -766,24 +744,19 @@ static struct imx9_uart_s g_lpuart3priv = .bits = CONFIG_LPUART3_BITS, .stopbits2 = CONFIG_LPUART3_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART3_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART3_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART3_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART3_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART3_TXDMA @@ -830,24 +803,19 @@ static struct imx9_uart_s g_lpuart4priv = .bits = CONFIG_LPUART4_BITS, .stopbits2 = CONFIG_LPUART4_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART4_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART4_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART4_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART4_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART4_TXDMA @@ -894,24 +862,19 @@ static struct imx9_uart_s g_lpuart5priv = .bits = CONFIG_LPUART5_BITS, .stopbits2 = CONFIG_LPUART5_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART5_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART5_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART5_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART5_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART5_TXDMA @@ -958,24 +921,19 @@ static struct imx9_uart_s g_lpuart6priv = .bits = CONFIG_LPUART6_BITS, .stopbits2 = CONFIG_LPUART6_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART6_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART6_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART6_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART6_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART6_TXDMA @@ -1022,24 +980,19 @@ static struct imx9_uart_s g_lpuart7priv = .bits = CONFIG_LPUART7_BITS, .stopbits2 = CONFIG_LPUART7_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART7_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART7_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART7_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART7_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART7_TXDMA @@ -1086,24 +1039,19 @@ static struct imx9_uart_s g_lpuart8priv = .bits = CONFIG_LPUART8_BITS, .stopbits2 = CONFIG_LPUART8_2STOP, # if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART8_OFLOWCONTROL) - .oflow = 1, - .cts_gpio = GPIO_LPUART8_CTS, + .usects = true, # endif # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL) - .iflow = 1, -# endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) || \ - (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL))) - .rts_gpio = GPIO_LPUART8_RTS, + .userts = true, # endif # if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ defined(CONFIG_LPUART8_INVERTIFLOWCONTROL) - .inviflow = 1, + .inviflow = true, # endif # if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL) - .rs485mode = 1, + .rs485mode = true, # endif # ifdef CONFIG_LPUART8_TXDMA @@ -1358,37 +1306,21 @@ static int imx9_setup(struct uart_dev_s *dev) { struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; #ifndef CONFIG_SUPPRESS_LPUART_CONFIG - struct uart_config_s config = - { - 0 - }; - + struct uart_config_s config; int ret; /* Configure the UART */ + memset(&config, 0, sizeof(config)); config.baud = priv->baud; /* Configured baud */ config.parity = priv->parity; /* 0=none, 1=odd, 2=even */ config.bits = priv->bits; /* Number of bits (5-9) */ config.stopbits2 = priv->stopbits2; /* true: Configure with 2 stop bits instead of 1 */ -#ifdef CONFIG_SERIAL_OFLOWCONTROL - config.usects = priv->oflow; /* Flow control on outbound side */ -#endif -#ifdef CONFIG_SERIAL_IFLOWCONTROL - /* Flow control on outbound side if not GPIO based */ - - if (priv->rts_gpio == 0) - { - config.userts = priv->iflow; - } -#endif -#ifdef CONFIG_SERIAL_RS485CONTROL config.users485 = priv->rs485mode; /* Switch into RS485 mode */ -#endif -#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) + config.userts = priv->iflow; config.invrts = priv->inviflow; /* Inversion of outbound flow control */ -#endif + config.usects = priv->oflow; ret = imx9_lpuart_configure(priv->uartbase, priv->uartnum, &config); @@ -1697,20 +1629,21 @@ static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg) /* Return parity */ - termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | - ((priv->parity == 1) ? PARODD : 0); + termiosp->c_cflag = (!priv->parity ? PARENB : 0) | + (priv->parity ? PARODD : 0); /* Return stop bits */ - termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0; + termiosp->c_cflag |= priv->stopbits2 ? CSTOPB : 0; /* Return flow control */ #ifdef CONFIG_SERIAL_OFLOWCONTROL - termiosp->c_cflag |= ((priv->oflow) ? CCTS_OFLOW : 0); + termiosp->c_cflag |= (priv->oflow ? CCTS_OFLOW : 0); + #endif #ifdef CONFIG_SERIAL_IFLOWCONTROL - termiosp->c_cflag |= ((priv->iflow) ? CRTS_IFLOW : 0); + termiosp->c_cflag |= (priv->iflow ? CRTS_IFLOW : 0); #endif /* Return baud */ @@ -1758,12 +1691,12 @@ static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg) if ((!termiosp) #ifdef CONFIG_SERIAL_OFLOWCONTROL - || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) + || ((termiosp->c_cflag & CCTS_OFLOW) && !priv->usects) #endif #ifdef CONFIG_SERIAL_IFLOWCONTROL - || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) + || ((termiosp->c_cflag & CRTS_IFLOW) && !priv->userts) #endif - ) + ) { ret = -EINVAL; break; @@ -1829,12 +1762,9 @@ static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg) priv->parity = parity; priv->bits = nbits; priv->stopbits2 = stop2; -#ifdef CONFIG_SERIAL_OFLOWCONTROL priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; -#endif -#ifdef CONFIG_SERIAL_IFLOWCONTROL priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; -#endif + /* effect the changes immediately - note that we do not * implement TCSADRAIN / TCSAFLUSH */ @@ -2022,97 +1952,6 @@ static bool imx9_rxavailable(struct uart_dev_s *dev) } #endif -/**************************************************************************** - * Name: imx9_rxflowcontrol - * - * Description: - * Called when Rx buffer is full (or exceeds configured watermark levels - * if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined). - * Return true if UART activated RX flow control to block more incoming - * data - * - * Input Parameters: - * dev - UART device instance - * nbuffered - the number of characters currently buffered - * (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is - * not defined the value will be 0 for an empty buffer or the - * defined buffer size for a full buffer) - * upper - true indicates the upper watermark was crossed where - * false indicates the lower watermark has been crossed - * - * Returned Value: - * true if RX flow control activated. - * - ****************************************************************************/ - -#ifdef CONFIG_SERIAL_IFLOWCONTROL -static bool imx9_rxflowcontrol(struct uart_dev_s *dev, - unsigned int nbuffered, bool upper) -{ - struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; - - if (priv->iflow && (priv->rts_gpio != 0)) - { - /* Assert/de-assert nRTS set it high resume/stop sending */ - - imx9_gpiowrite(priv->rts_gpio, upper); - - if (upper) - { - /* With heavy Rx traffic, RXNE might be set and data pending. - * Returning 'true' in such case would cause RXNE left unhandled - * and causing interrupt storm. Sending end might be also be slow - * to react on nRTS, and returning 'true' here would prevent - * processing that data. - * - * Therefore, return 'false' so input data is still being processed - * until sending end reacts on nRTS signal and stops sending more. - */ - - return false; - } - - return upper; - } - else - { - /* Is the RX buffer full? */ - - if (upper) - { - /* Disable Rx interrupt to prevent more data being from - * peripheral. When hardware RTS is enabled, this will - * prevent more data from coming in. - * - * This function is only called when UART recv buffer is full, - * that is: "dev->recv.head + 1 == dev->recv.tail". - * - * Logic in "uart_read" will automatically toggle Rx interrupts - * when buffer is read empty and thus we do not have to re- - * enable Rx interrupts. - */ - - uart_disablerxint(dev); - return true; - } - - /* No.. The RX buffer is empty */ - - else - { - /* We might leave Rx interrupt disabled if full recv buffer was - * read empty. Enable Rx interrupt to make sure that more input is - * received. - */ - - uart_enablerxint(dev); - } - } - - return false; -} -#endif - /**************************************************************************** * Name: imx9_dma_receive * From 5d4d296a033e3101f6b8c9a278ab8385b6e29e21 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Mon, 28 Oct 2024 09:32:16 +0200 Subject: [PATCH 2/2] imx9/serial: Take proper use of RX/TX FIFOs, clean up interrupt service 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 --- arch/arm64/src/imx9/hardware/imx9_lpuart.h | 24 ++-- arch/arm64/src/imx9/imx9_lowputc.c | 5 + arch/arm64/src/imx9/imx9_lpuart.c | 155 ++++++++++----------- 3 files changed, 93 insertions(+), 91 deletions(-) diff --git a/arch/arm64/src/imx9/hardware/imx9_lpuart.h b/arch/arm64/src/imx9/hardware/imx9_lpuart.h index c688d5966a14e..f29cde48a2171 100644 --- a/arch/arm64/src/imx9/hardware/imx9_lpuart.h +++ b/arch/arm64/src/imx9/hardware/imx9_lpuart.h @@ -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) */ diff --git a/arch/arm64/src/imx9/imx9_lowputc.c b/arch/arm64/src/imx9/imx9_lowputc.c index a6448ddcb5e90..b81494374d64f 100644 --- a/arch/arm64/src/imx9/imx9_lowputc.c +++ b/arch/arm64/src/imx9/imx9_lowputc.c @@ -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; diff --git a/arch/arm64/src/imx9/imx9_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c index 0128a73080fd3..93dcb4f3e30e3 100644 --- a/arch/arm64/src/imx9/imx9_lpuart.c +++ b/arch/arm64/src/imx9/imx9_lpuart.c @@ -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; @@ -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; @@ -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 @@ -2356,7 +2340,7 @@ 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 * ****************************************************************************/ @@ -2364,16 +2348,29 @@ 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 * ****************************************************************************/ @@ -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; } /****************************************************************************