pkarashchenko commented on code in PR #7869: URL: https://github.com/apache/nuttx/pull/7869#discussion_r1047627445
########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -191,12 +241,46 @@ static int s32k1xx_attach(struct uart_dev_s *dev); static void s32k1xx_detach(struct uart_dev_s *dev); static int s32k1xx_interrupt(int irq, void *context, void *arg); static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg); +#if !defined(SERIAL_HAVE_ONLY_RXDMA) static int s32k1xx_receive(struct uart_dev_s *dev, unsigned int *status); static void s32k1xx_rxint(struct uart_dev_s *dev, bool enable); static bool s32k1xx_rxavailable(struct uart_dev_s *dev); -static void s32k1xx_send(struct uart_dev_s *dev, int ch); +#endif +#if !defined(SERIAL_HAVE_ONLY_TXDMA) static void s32k1xx_txint(struct uart_dev_s *dev, bool enable); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool s32k1xx_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper); +#endif +static void s32k1xx_send(struct uart_dev_s *dev, int ch); static bool s32k1xx_txready(struct uart_dev_s *dev); +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_send(struct uart_dev_s *dev); +static void s32k1xx_dma_txint(struct uart_dev_s *dev, bool enable); +static void s32k1xx_dma_txavailable(struct uart_dev_s *dev); +static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); Review Comment: ```suggestion static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, int result); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -191,12 +241,46 @@ static int s32k1xx_attach(struct uart_dev_s *dev); static void s32k1xx_detach(struct uart_dev_s *dev); static int s32k1xx_interrupt(int irq, void *context, void *arg); static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg); +#if !defined(SERIAL_HAVE_ONLY_RXDMA) static int s32k1xx_receive(struct uart_dev_s *dev, unsigned int *status); static void s32k1xx_rxint(struct uart_dev_s *dev, bool enable); static bool s32k1xx_rxavailable(struct uart_dev_s *dev); -static void s32k1xx_send(struct uart_dev_s *dev, int ch); +#endif +#if !defined(SERIAL_HAVE_ONLY_TXDMA) static void s32k1xx_txint(struct uart_dev_s *dev, bool enable); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool s32k1xx_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper); Review Comment: ```suggestion static bool s32k1xx_rxflowcontrol(struct uart_dev_s *dev, unsigned int nbuffered, bool upper); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -473,6 +709,132 @@ static inline void s32k1xx_restoreuartint(struct s32k1xx_uart_s *priv, spin_unlock_irqrestore(NULL, flags); } +/**************************************************************************** + * Name: s32k1xx_dma_setup + * + * Description: + * Configure the LPUART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int s32k1xx_dma_setup(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; +#if defined(SERIAL_HAVE_RXDMA) + struct s32k1xx_edma_xfrconfig_s config; +#endif + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = s32k1xx_setup(dev); + if (result != OK) + { + return result; + } + } + +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ + + if (priv->dma_txreqsrc != 0) + { + if (priv->txdma == NULL) + { + priv->txdma = s32k1xx_dmach_alloc(priv->dma_txreqsrc | + DMAMUX_CHCFG_ENBL, 0); + if (priv->txdma == NULL) + { + return -EBUSY; + } + + nxsem_init(&priv->txdmasem, 0, 1); + nxsem_set_protocol(&priv->txdmasem, SEM_PRIO_NONE); + } + + /* Enable Tx DMA for the UART */ + + modifyreg32(priv->uartbase + S32K1XX_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_TDMAE); + } +#endif + +#if defined(SERIAL_HAVE_RXDMA) + /* Acquire the Rx DMA channel. This should always succeed. */ + + if (priv->dma_rxreqsrc != 0) + { + if (priv->rxdma == NULL) + { + priv->rxdma = s32k1xx_dmach_alloc(priv->dma_rxreqsrc | + DMAMUX_CHCFG_ENBL, 0); + + if (priv->rxdma == NULL) + { + return -EBUSY; + } + } + else + { + s32k1xx_dmach_stop(priv->rxdma); + } + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + S32K1XX_LPUART_DATA_OFFSET; + config.daddr = (uint32_t) priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; + #ifdef CONFIG_KINETIS_EDMA_ELINK + config.linkch = 0; + #endif + + s32k1xx_dmach_xfrsetup(priv->rxdma , &config); + + /* Reset our DMA shadow pointer and Rx data availability count to + * match the address just programmed above. + */ + + priv->rxdmanext = 0; + + /* Enable receive Rx DMA for the UART */ + + modifyreg32(priv->uartbase + S32K1XX_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_RDMAE); + + /* Enable itnerrupt on Idel and erros */ + + modifyreg32(priv->uartbase + S32K1XX_LPUART_CTRL_OFFSET, 0, + LPUART_CTRL_PEIE | + LPUART_CTRL_FEIE | + LPUART_CTRL_NEIE | + LPUART_CTRL_ILIE); Review Comment: ```suggestion modifyreg32(priv->uartbase + S32K1XX_LPUART_CTRL_OFFSET, 0, LPUART_CTRL_PEIE | LPUART_CTRL_FEIE | LPUART_CTRL_NEIE | LPUART_CTRL_ILIE); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -703,6 +1151,7 @@ static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) #if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) struct inode *inode = filep->f_inode; struct uart_dev_s *dev = inode->i_private; Review Comment: ```suggestion struct uart_dev_s *dev = inode->i_private; ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -1022,6 +1478,359 @@ static bool s32k1xx_rxavailable(struct uart_dev_s *dev) regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); return ((regval & LPUART_STAT_RDRF) != 0); } +#endif + +/**************************************************************************** + * Name: s32k1xx_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 s32k1xx_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) Review Comment: ```suggestion static bool s32k1xx_rxflowcontrol(struct uart_dev_s *dev, unsigned int nbuffered, bool upper) ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -1022,6 +1478,359 @@ static bool s32k1xx_rxavailable(struct uart_dev_s *dev) regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); return ((regval & LPUART_STAT_RDRF) != 0); } +#endif + +/**************************************************************************** + * Name: s32k1xx_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 s32k1xx_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + bool use_swhs = false; + +#if defined(CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS) + use_swhs = (priv->rts_gpio & _PIN_MODE_MASK) == _PIN_MODE_GPIO; +#endif + + if (use_swhs && priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + s32k1xx_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: s32k1xx_dma_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the LPUART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int s32k1xx_dma_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + uint32_t nextrx = s32k1xx_dma_nextrx(priv); + int c = 0; + + /* Check if more data is available */ + + if (nextrx != priv->rxdmanext) + { + /* Now read from the DMA buffer */ + + c = priv->rxfifo[priv->rxdmanext]; + + priv->rxdmanext++; + + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) + { + priv->rxdmanext = 0; + } + } + + /* NOTE: If no data is available, then we would return NULL which is, + * of course, valid binary data. The protocol is that the upper half + * driver must call s32k1xx_dma_rxavailable prior to calling this + * function to assure that this never happens. + */ + + return c; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_reenable + * + * Description: + * Call to re-enable RX DMA. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) +static void s32k1xx_dma_reenable(struct s32k1xx_uart_s *priv) +{ + struct s32k1xx_edma_xfrconfig_s config; + + /* Stop an reset the RX DMA */ + + s32k1xx_dmach_stop(priv->rxdma); + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + S32K1XX_LPUART_DATA_OFFSET; + config.daddr = (uint32_t) priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; +#ifdef CONFIG_KINETIS_EDMA_ELINK + config.linkch = 0; +#endif + + s32k1xx_dmach_xfrsetup(priv->rxdma, &config); + + /* Reset our DMA shadow pointer and Rx data availability count to match + * the address just programmed above. + */ + + priv->rxdmanext = 0; + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + s32k1xx_dmach_start(priv->rxdma, s32k1xx_dma_rxcallback, (void *)priv); + + /* Clear DMA suspended flag. */ + + priv->rxdmasusp = false; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void s32k1xx_dma_rxint(struct uart_dev_s *dev, bool enable) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Enable/disable DMA reception. + * + * Note that it is not safe to check for available bytes and immediately + * pass them to uart_recvchars as that could potentially recurse back + * to us again. Instead, bytes must wait until the next up_dma_poll or + * DMA event. + */ + + priv->rxenable = enable; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static bool s32k1xx_dma_rxavailable(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ + + return (s32k1xx_dma_nextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)arg; + /* Update 'nbytes' indicating number of bytes actually transferred by DMA. + * This is important to free TX buffer space by 'uart_xmitchars_done'. + */ + + priv->dev.dmatx.nbytes = priv->dev.dmatx.length + priv->dev.dmatx.nlength; + + /* Adjust the pointers */ + + uart_xmitchars_done(&priv->dev); + + /* Release waiter */ + + nxsem_post(&priv->txdmasem); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_txavailable + * + * Description: + * Informs DMA that Tx data is available and is ready for transfer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_txavailable(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Only send when the DMA is idle */ + + nxsem_wait(&priv->txdmasem); + + uart_xmitchars_dma(dev); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_send + * + * Description: + * Called (usually) from the interrupt level to start DMA transfer. + * (Re-)Configures DMA Stream updating buffer and buffer length. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_send(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + struct s32k1xx_edma_xfrconfig_s config; + + /* We need to stop DMA before reconfiguration */ + + s32k1xx_dmach_stop(priv->txdma); + + /* Reset the number sent */ + + dev->dmatx.nbytes = 0; + + /* Make use of setup function to update buffer and its length for next + * transfer + */ + + config.iter = dev->dmatx.length; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = sizeof(dev->dmatx.buffer[0]); + config.saddr = (uint32_t) dev->dmatx.buffer; Review Comment: ```suggestion config.saddr = (uint32_t)dev->dmatx.buffer; ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -877,13 +1326,15 @@ static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) * implement TCSADRAIN / TCSAFLUSH */ + flags = spin_lock_irqsave(NULL); Review Comment: ```suggestion flags = spin_lock_irqsave(NULL); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -473,6 +709,132 @@ static inline void s32k1xx_restoreuartint(struct s32k1xx_uart_s *priv, spin_unlock_irqrestore(NULL, flags); } +/**************************************************************************** + * Name: s32k1xx_dma_setup + * + * Description: + * Configure the LPUART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int s32k1xx_dma_setup(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; +#if defined(SERIAL_HAVE_RXDMA) + struct s32k1xx_edma_xfrconfig_s config; +#endif + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = s32k1xx_setup(dev); + if (result != OK) + { + return result; + } + } + +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ + + if (priv->dma_txreqsrc != 0) + { + if (priv->txdma == NULL) + { + priv->txdma = s32k1xx_dmach_alloc(priv->dma_txreqsrc | + DMAMUX_CHCFG_ENBL, 0); + if (priv->txdma == NULL) + { + return -EBUSY; + } + + nxsem_init(&priv->txdmasem, 0, 1); + nxsem_set_protocol(&priv->txdmasem, SEM_PRIO_NONE); + } + + /* Enable Tx DMA for the UART */ + + modifyreg32(priv->uartbase + S32K1XX_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_TDMAE); + } +#endif + +#if defined(SERIAL_HAVE_RXDMA) + /* Acquire the Rx DMA channel. This should always succeed. */ + + if (priv->dma_rxreqsrc != 0) + { + if (priv->rxdma == NULL) + { + priv->rxdma = s32k1xx_dmach_alloc(priv->dma_rxreqsrc | + DMAMUX_CHCFG_ENBL, 0); Review Comment: ```suggestion priv->rxdma = s32k1xx_dmach_alloc(priv->dma_rxreqsrc | DMAMUX_CHCFG_ENBL, 0); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -191,12 +241,46 @@ static int s32k1xx_attach(struct uart_dev_s *dev); static void s32k1xx_detach(struct uart_dev_s *dev); static int s32k1xx_interrupt(int irq, void *context, void *arg); static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg); +#if !defined(SERIAL_HAVE_ONLY_RXDMA) static int s32k1xx_receive(struct uart_dev_s *dev, unsigned int *status); static void s32k1xx_rxint(struct uart_dev_s *dev, bool enable); static bool s32k1xx_rxavailable(struct uart_dev_s *dev); -static void s32k1xx_send(struct uart_dev_s *dev, int ch); +#endif +#if !defined(SERIAL_HAVE_ONLY_TXDMA) static void s32k1xx_txint(struct uart_dev_s *dev, bool enable); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool s32k1xx_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper); +#endif +static void s32k1xx_send(struct uart_dev_s *dev, int ch); static bool s32k1xx_txready(struct uart_dev_s *dev); +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_send(struct uart_dev_s *dev); +static void s32k1xx_dma_txint(struct uart_dev_s *dev, bool enable); +static void s32k1xx_dma_txavailable(struct uart_dev_s *dev); +static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int s32k1xx_dma_setup(struct uart_dev_s *dev); +static void s32k1xx_dma_shutdown(struct uart_dev_s *dev); +#endif + +#ifdef SERIAL_HAVE_RXDMA +static int s32k1xx_dma_receive(struct uart_dev_s *dev, + unsigned int *status); +#ifdef CONFIG_PM +static void s32k1xx_dma_reenable(struct s32k1xx_uart_s *priv); +#endif +static void s32k1xx_dma_rxint(struct uart_dev_s *dev, bool enable); +static bool s32k1xx_dma_rxavailable(struct uart_dev_s *dev); + +static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); Review Comment: ```suggestion static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, int result); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -473,6 +709,132 @@ static inline void s32k1xx_restoreuartint(struct s32k1xx_uart_s *priv, spin_unlock_irqrestore(NULL, flags); } +/**************************************************************************** + * Name: s32k1xx_dma_setup + * + * Description: + * Configure the LPUART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int s32k1xx_dma_setup(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; +#if defined(SERIAL_HAVE_RXDMA) + struct s32k1xx_edma_xfrconfig_s config; +#endif + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = s32k1xx_setup(dev); + if (result != OK) + { + return result; + } + } + +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ + + if (priv->dma_txreqsrc != 0) + { + if (priv->txdma == NULL) + { + priv->txdma = s32k1xx_dmach_alloc(priv->dma_txreqsrc | + DMAMUX_CHCFG_ENBL, 0); Review Comment: ```suggestion priv->txdma = s32k1xx_dmach_alloc(priv->dma_txreqsrc | DMAMUX_CHCFG_ENBL, 0); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -473,6 +709,132 @@ static inline void s32k1xx_restoreuartint(struct s32k1xx_uart_s *priv, spin_unlock_irqrestore(NULL, flags); } +/**************************************************************************** + * Name: s32k1xx_dma_setup + * + * Description: + * Configure the LPUART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int s32k1xx_dma_setup(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; +#if defined(SERIAL_HAVE_RXDMA) + struct s32k1xx_edma_xfrconfig_s config; +#endif + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = s32k1xx_setup(dev); + if (result != OK) + { + return result; + } + } + +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ + + if (priv->dma_txreqsrc != 0) + { + if (priv->txdma == NULL) + { + priv->txdma = s32k1xx_dmach_alloc(priv->dma_txreqsrc | + DMAMUX_CHCFG_ENBL, 0); + if (priv->txdma == NULL) + { + return -EBUSY; + } + + nxsem_init(&priv->txdmasem, 0, 1); + nxsem_set_protocol(&priv->txdmasem, SEM_PRIO_NONE); + } + + /* Enable Tx DMA for the UART */ + + modifyreg32(priv->uartbase + S32K1XX_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_TDMAE); + } +#endif + +#if defined(SERIAL_HAVE_RXDMA) + /* Acquire the Rx DMA channel. This should always succeed. */ + + if (priv->dma_rxreqsrc != 0) + { + if (priv->rxdma == NULL) + { + priv->rxdma = s32k1xx_dmach_alloc(priv->dma_rxreqsrc | + DMAMUX_CHCFG_ENBL, 0); + + if (priv->rxdma == NULL) + { + return -EBUSY; + } + } + else + { + s32k1xx_dmach_stop(priv->rxdma); + } + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + S32K1XX_LPUART_DATA_OFFSET; + config.daddr = (uint32_t) priv->rxfifo; Review Comment: ```suggestion config.daddr = (uint32_t)priv->rxfifo; ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -1106,6 +1939,48 @@ static bool s32k1xx_txempty(struct uart_dev_s *dev) return ((regval & LPUART_STAT_TDRE) != 0); } +/**************************************************************************** + * Name: s32k1xx_dma_rxcallback + * + * Description: + * This function checks the current DMA state and calls the generic + * serial stack when bytes appear to be available. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) Review Comment: ```suggestion static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, int result) ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -1022,6 +1478,359 @@ static bool s32k1xx_rxavailable(struct uart_dev_s *dev) regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); return ((regval & LPUART_STAT_RDRF) != 0); } +#endif + +/**************************************************************************** + * Name: s32k1xx_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 s32k1xx_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + bool use_swhs = false; + +#if defined(CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS) + use_swhs = (priv->rts_gpio & _PIN_MODE_MASK) == _PIN_MODE_GPIO; +#endif + + if (use_swhs && priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + s32k1xx_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: s32k1xx_dma_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the LPUART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int s32k1xx_dma_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + uint32_t nextrx = s32k1xx_dma_nextrx(priv); + int c = 0; + + /* Check if more data is available */ + + if (nextrx != priv->rxdmanext) + { + /* Now read from the DMA buffer */ + + c = priv->rxfifo[priv->rxdmanext]; + + priv->rxdmanext++; + + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) + { + priv->rxdmanext = 0; + } + } + + /* NOTE: If no data is available, then we would return NULL which is, + * of course, valid binary data. The protocol is that the upper half + * driver must call s32k1xx_dma_rxavailable prior to calling this + * function to assure that this never happens. + */ + + return c; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_reenable + * + * Description: + * Call to re-enable RX DMA. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) +static void s32k1xx_dma_reenable(struct s32k1xx_uart_s *priv) +{ + struct s32k1xx_edma_xfrconfig_s config; + + /* Stop an reset the RX DMA */ + + s32k1xx_dmach_stop(priv->rxdma); + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + S32K1XX_LPUART_DATA_OFFSET; + config.daddr = (uint32_t) priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; +#ifdef CONFIG_KINETIS_EDMA_ELINK + config.linkch = 0; +#endif + + s32k1xx_dmach_xfrsetup(priv->rxdma, &config); + + /* Reset our DMA shadow pointer and Rx data availability count to match + * the address just programmed above. + */ + + priv->rxdmanext = 0; + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + s32k1xx_dmach_start(priv->rxdma, s32k1xx_dma_rxcallback, (void *)priv); + + /* Clear DMA suspended flag. */ + + priv->rxdmasusp = false; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void s32k1xx_dma_rxint(struct uart_dev_s *dev, bool enable) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Enable/disable DMA reception. + * + * Note that it is not safe to check for available bytes and immediately + * pass them to uart_recvchars as that could potentially recurse back + * to us again. Instead, bytes must wait until the next up_dma_poll or + * DMA event. + */ + + priv->rxenable = enable; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static bool s32k1xx_dma_rxavailable(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ + + return (s32k1xx_dma_nextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) Review Comment: ```suggestion static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, int result) ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -1022,6 +1478,359 @@ static bool s32k1xx_rxavailable(struct uart_dev_s *dev) regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); return ((regval & LPUART_STAT_RDRF) != 0); } +#endif + +/**************************************************************************** + * Name: s32k1xx_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 s32k1xx_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + bool use_swhs = false; + +#if defined(CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS) + use_swhs = (priv->rts_gpio & _PIN_MODE_MASK) == _PIN_MODE_GPIO; +#endif + + if (use_swhs && priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + s32k1xx_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: s32k1xx_dma_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the LPUART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int s32k1xx_dma_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + uint32_t nextrx = s32k1xx_dma_nextrx(priv); + int c = 0; + + /* Check if more data is available */ + + if (nextrx != priv->rxdmanext) + { + /* Now read from the DMA buffer */ + + c = priv->rxfifo[priv->rxdmanext]; + + priv->rxdmanext++; + + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) + { + priv->rxdmanext = 0; + } + } + + /* NOTE: If no data is available, then we would return NULL which is, + * of course, valid binary data. The protocol is that the upper half + * driver must call s32k1xx_dma_rxavailable prior to calling this + * function to assure that this never happens. + */ + + return c; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_reenable + * + * Description: + * Call to re-enable RX DMA. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) +static void s32k1xx_dma_reenable(struct s32k1xx_uart_s *priv) +{ + struct s32k1xx_edma_xfrconfig_s config; + + /* Stop an reset the RX DMA */ + + s32k1xx_dmach_stop(priv->rxdma); + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + S32K1XX_LPUART_DATA_OFFSET; + config.daddr = (uint32_t) priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; +#ifdef CONFIG_KINETIS_EDMA_ELINK + config.linkch = 0; +#endif + + s32k1xx_dmach_xfrsetup(priv->rxdma, &config); + + /* Reset our DMA shadow pointer and Rx data availability count to match + * the address just programmed above. + */ + + priv->rxdmanext = 0; + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + s32k1xx_dmach_start(priv->rxdma, s32k1xx_dma_rxcallback, (void *)priv); + + /* Clear DMA suspended flag. */ + + priv->rxdmasusp = false; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void s32k1xx_dma_rxint(struct uart_dev_s *dev, bool enable) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Enable/disable DMA reception. + * + * Note that it is not safe to check for available bytes and immediately + * pass them to uart_recvchars as that could potentially recurse back + * to us again. Instead, bytes must wait until the next up_dma_poll or + * DMA event. + */ + + priv->rxenable = enable; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static bool s32k1xx_dma_rxavailable(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ + + return (s32k1xx_dma_nextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)arg; + /* Update 'nbytes' indicating number of bytes actually transferred by DMA. + * This is important to free TX buffer space by 'uart_xmitchars_done'. + */ + + priv->dev.dmatx.nbytes = priv->dev.dmatx.length + priv->dev.dmatx.nlength; + + /* Adjust the pointers */ + + uart_xmitchars_done(&priv->dev); + + /* Release waiter */ + + nxsem_post(&priv->txdmasem); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_txavailable + * + * Description: + * Informs DMA that Tx data is available and is ready for transfer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_txavailable(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + + /* Only send when the DMA is idle */ + + nxsem_wait(&priv->txdmasem); + + uart_xmitchars_dma(dev); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_dma_send + * + * Description: + * Called (usually) from the interrupt level to start DMA transfer. + * (Re-)Configures DMA Stream updating buffer and buffer length. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void s32k1xx_dma_send(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; + struct s32k1xx_edma_xfrconfig_s config; + + /* We need to stop DMA before reconfiguration */ + + s32k1xx_dmach_stop(priv->txdma); + + /* Reset the number sent */ + + dev->dmatx.nbytes = 0; + + /* Make use of setup function to update buffer and its length for next + * transfer + */ + + config.iter = dev->dmatx.length; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = sizeof(dev->dmatx.buffer[0]); + config.saddr = (uint32_t) dev->dmatx.buffer; + config.daddr = priv->uartbase + S32K1XX_LPUART_DATA_OFFSET; + config.soff = sizeof(dev->dmatx.buffer[0]); + config.doff = 0; +#ifdef CONFIG_S32K1XX_EDMA_ELINK + config.linkch = 0; +#endif + + /* Setup first half */ + + s32k1xx_dmach_xfrsetup(priv->txdma, &config); + + /* Is this a split transfer? */ + + if (dev->dmatx.nbuffer) + { + config.iter = priv->dev.dmatx.nlength; + config.saddr = (uint32_t) priv->dev.dmatx.nbuffer; Review Comment: ```suggestion config.saddr = (uint32_t)priv->dev.dmatx.nbuffer; ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.c: ########## @@ -1106,6 +1939,48 @@ static bool s32k1xx_txempty(struct uart_dev_s *dev) return ((regval & LPUART_STAT_TDRE) != 0); } +/**************************************************************************** + * Name: s32k1xx_dma_rxcallback + * + * Description: + * This function checks the current DMA state and calls the generic + * serial stack when bytes appear to be available. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)arg; + uint32_t sr; + + if (priv->rxenable && s32k1xx_dma_rxavailable(&priv->dev)) + { + uart_recvchars(&priv->dev); + } + + /* Get the masked LPUART status word to check and clear error flags. + * + * When wake-up from low power mode was not fast enough, UART is resumed + * too late and sometimes exactly when character was coming over UART, + * resulting to frame error. + * If error flag is not cleared, Rx DMA will be stuck. Clearing errors + * will release Rx DMA. + */ + + sr = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); + + if ((sr & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE)) != 0) + { + s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, + sr & (LPUART_STAT_OR | + LPUART_STAT_NF | + LPUART_STAT_FE)); Review Comment: ```suggestion s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, sr & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE)); ``` ########## arch/arm/src/s32k1xx/s32k1xx_serial.h: ########## @@ -34,6 +34,115 @@ * Pre-processor Definitions ****************************************************************************/ +#if defined(CONFIG_S32K1XX_LPUART0) || defined(CONFIG_S32K1XX_LPUART1) || \ + defined(CONFIG_S32K1XX_LPUART2) +# define HAVE_UART 1 +#endif + +/* Assume DMA is not used on the console UART */ + +#undef SERIAL_HAVE_CONSOLE_RXDMA +#undef SERIAL_HAVE_CONSOLE_TXDMA + +#if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA) +# undef CONFIG_LPUART0_RXDMA +# undef CONFIG_LPUART0_TXDMA +# undef CONFIG_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +#endif + +/* Disable the DMA configuration on all unused LPUARTs */ + +#ifndef CONFIG_S32K1XX_LPUART0 +# undef CONFIG_LPUART0_RXDMA +# undef CONFIG_LPUART0_TXDMA +#endif + +#ifndef CONFIG_S32K1XX_LPUART1 +# undef CONFIG_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +#endif + +#ifndef CONFIG_S32K1XX_LPUART2 +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +#endif + +/* Is RX DMA available on any (enabled) LPUART? */ + +#undef SERIAL_HAVE_RXDMA +#if defined(CONFIG_LPUART0_RXDMA) || defined(CONFIG_LPUART1_RXDMA) || \ + defined(CONFIG_LPUART2_RXDMA) +# define SERIAL_HAVE_RXDMA 1 +#endif + +/* Is TX DMA available on any (enabled) LPUART? */ +#undef SERIAL_HAVE_TXDMA +#if defined(CONFIG_LPUART0_TXDMA) || defined(CONFIG_LPUART1_TXDMA) || \ + defined(CONFIG_LPUART2_TXDMA) +# define SERIAL_HAVE_TXDMA 1 +#endif + +/* Is RX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_RXDMA 1 +#if defined(CONFIG_S32K1XX_LPUART0) && !defined(CONFIG_LPUART0_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_S32K1XX_LPUART1) && !defined(CONFIG_LPUART1_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(CONFIG_LPUART2_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#endif + +/* Is TX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_TXDMA 1 +#if defined(CONFIG_S32K1XX_LPUART0) && !defined(CONFIG_LPUART0_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_S32K1XX_LPUART1) && !defined(CONFIG_LPUART1_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(CONFIG_LPUART2_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#endif + +#undef SERIAL_HAVE_ONLY_DMA +#if defined(SERIAL_HAVE_ONLY_RXDMA) && defined(SERIAL_HAVE_ONLY_TXDMA) +#define SERIAL_HAVE_ONLY_DMA +#endif + +/* Verify that DMA has been enabled and the DMA channel has been defined. + */ + +# if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA) +# ifndef CONFIG_S32K1XX_EDMA +# error S32K1XX LPUART receive or transmit DMA requires CONFIG_S32K1XX_EDMA +# endif +# endif Review Comment: ```suggestion #if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA) # ifndef CONFIG_S32K1XX_EDMA # error S32K1XX LPUART receive or transmit DMA requires CONFIG_S32K1XX_EDMA # endif #endif ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org