From 113434de9985aa54601c3b50d22ae13edbb47b61 Mon Sep 17 00:00:00 2001 From: Peter van der Perk Date: Fri, 22 Dec 2023 15:14:08 +0100 Subject: [PATCH] s32k1xx: backport s32k3xx serial driver changes to s32k1xx --- arch/arm/src/s32k1xx/s32k1xx_edma.c | 18 + arch/arm/src/s32k1xx/s32k1xx_edma.h | 15 + arch/arm/src/s32k1xx/s32k1xx_serial.c | 477 ++++++++++++++++++-------- 3 files changed, 364 insertions(+), 146 deletions(-) diff --git a/arch/arm/src/s32k1xx/s32k1xx_edma.c b/arch/arm/src/s32k1xx/s32k1xx_edma.c index 97fe1ecbe52d1..91f312ab30111 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_edma.c +++ b/arch/arm/src/s32k1xx/s32k1xx_edma.c @@ -1231,6 +1231,24 @@ unsigned int s32k1xx_dmach_getcount(DMACH_HANDLE *handle) return remaining; } +/**************************************************************************** + * Name: s32k3xx_dmach_idle + * + * Description: + * This function checks if the dma is idle + * + * Returned Value: + * 0 - if idle + * !0 - not + * + ****************************************************************************/ + +unsigned int s32k1xx_dmach_idle(DMACH_HANDLE handle) +{ + struct s32k1xx_dmach_s *dmach = (struct s32k1xx_dmach_s *)handle; + return dmach->state == S32K1XX_DMA_IDLE ? 0 : -1; +} + /**************************************************************************** * Name: s32k1xx_dmasample * diff --git a/arch/arm/src/s32k1xx/s32k1xx_edma.h b/arch/arm/src/s32k1xx/s32k1xx_edma.h index ac85a0a03fb71..83c50c6d0ee18 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_edma.h +++ b/arch/arm/src/s32k1xx/s32k1xx_edma.h @@ -413,6 +413,21 @@ void s32k1xx_dmach_stop(DMACH_HANDLE handle); unsigned int s32k1xx_dmach_getcount(DMACH_HANDLE *handle); + +/**************************************************************************** + * Name: s32k3xx_dmach_idle + * + * Description: + * This function checks if the dma is idle + * + * Returned Value: + * 0 - if idle + * !0 - not + * + ****************************************************************************/ + +unsigned int s32k1xx_dmach_idle(DMACH_HANDLE handle); + /**************************************************************************** * Name: s32k1xx_dmasample * diff --git a/arch/arm/src/s32k1xx/s32k1xx_serial.c b/arch/arm/src/s32k1xx/s32k1xx_serial.c index 7053b6337315f..70b3fda2303cf 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_serial.c +++ b/arch/arm/src/s32k1xx/s32k1xx_serial.c @@ -18,6 +18,8 @@ * ****************************************************************************/ +/* Copyright 2022 NXP */ + /**************************************************************************** * Included Files ****************************************************************************/ @@ -53,6 +55,7 @@ #include "s32k1xx_edma.h" #include "hardware/s32k1xx_dmamux.h" #include "hardware/s32k1xx_pinmux.h" +#include "hardware/s32k1xx_pinmux.h" #include "s32k1xx_config.h" #include "s32k1xx_pin.h" #include "s32k1xx_lowputc.h" @@ -66,7 +69,92 @@ * Pre-processor Definitions ****************************************************************************/ -/* Which LPUART with be tty0/console and which tty1-7? The console will +/* The DMA buffer size when using RX DMA to emulate a FIFO. + * + * When streaming data, the generic serial layer will be called every time + * the FIFO receives half this number of bytes. + * + * This buffer size should be an even multiple of the Cortex-M7 D-Cache line + * size, ARMV7M_DCACHE_LINESIZE, so that it can be individually invalidated. + * + * Should there be a Cortex-M7 without a D-Cache, ARMV7M_DCACHE_LINESIZE + * would be zero! + */ + +# if !defined(ARMV7M_DCACHE_LINESIZE) || ARMV7M_DCACHE_LINESIZE == 0 +# undef ARMV7M_DCACHE_LINESIZE +# define ARMV7M_DCACHE_LINESIZE 32 +# endif + +# if !defined(CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE) || \ + (CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE < ARMV7M_DCACHE_LINESIZE) +# undef CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE +# define CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE ARMV7M_DCACHE_LINESIZE +# endif + +# define RXDMA_BUFFER_MASK (ARMV7M_DCACHE_LINESIZE - 1) +# define RXDMA_BUFFER_SIZE ((CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK) + +/* The DMA buffer size when using TX DMA. + * + * This TX buffer size should be an even multiple of the Cortex-M7 D-Cache + * line size, ARMV7M_DCACHE_LINESIZE, so that it can be individually + * invalidated. + * + * Should there be a Cortex-M7 without a D-Cache, ARMV7M_DCACHE_LINESIZE + * would be zero! + */ + +#define TXDMA_BUFFER_MASK (ARMV7M_DCACHE_LINESIZE - 1) +#define TXDMA_BUFFER_SIZE ((CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK) + +/* If built with CONFIG_ARMV7M_DCACHE Buffers need to be aligned and + * multiples of ARMV7M_DCACHE_LINESIZE + */ + +#if defined(CONFIG_ARMV7M_DCACHE) +# define TXDMA_BUF_SIZE(b) (((b) + TXDMA_BUFFER_MASK) & ~TXDMA_BUFFER_MASK) +# define TXDMA_BUF_ALIGN aligned_data(ARMV7M_DCACHE_LINESIZE); +#else +# define TXDMA_BUF_SIZE(b) (b) +# define TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART0_TXDMA) +# define LPUART0_TXBUFSIZE_ADJUSTED CONFIG_LPUART0_TXBUFSIZE +# define LPUART0_TXBUFSIZE_ALGN +#else +# define LPUART0_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART0_TXBUFSIZE) +# define LPUART0_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART1_TXDMA) +# define LPUART1_TXBUFSIZE_ADJUSTED CONFIG_LPUART1_TXBUFSIZE +# define LPUART1_TXBUFSIZE_ALGN +#else +# define LPUART1_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART1_TXBUFSIZE) +# define LPUART1_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART2_TXDMA) +# define LPUART2_TXBUFSIZE_ADJUSTED CONFIG_LPUART2_TXBUFSIZE +# define LPUART2_TXBUFSIZE_ALGN +#else +# define LPUART2_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART2_TXBUFSIZE) +# define LPUART2_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART3_TXDMA) +# define LPUART3_TXBUFSIZE_ADJUSTED CONFIG_LPUART3_TXBUFSIZE +# define LPUART3_TXBUFSIZE_ALGN +#else +# define LPUART3_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART3_TXBUFSIZE) +# define LPUART3_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +/* Which LPUART with be tty0/console and which tty0-15? The console will * always be ttyS0. If there is no console then will use the lowest * numbered LPUART. */ @@ -76,7 +164,7 @@ #if defined(CONFIG_LPUART0_SERIAL_CONSOLE) # define CONSOLE_DEV g_lpuart0priv /* LPUART0 is console */ # define TTYS0_DEV g_lpuart0priv /* LPUART0 is ttyS0 */ -# define UART1_ASSIGNED 1 +# define LPUART0_ASSIGNED 1 # if defined(CONFIG_LPUART0_RXDMA) # define SERIAL_HAVE_CONSOLE_RXDMA 1 # endif @@ -86,7 +174,7 @@ #elif defined(CONFIG_LPUART1_SERIAL_CONSOLE) # define CONSOLE_DEV g_lpuart1priv /* LPUART1 is console */ # define TTYS0_DEV g_lpuart1priv /* LPUART1 is ttyS0 */ -# define UART2_ASSIGNED 1 +# define LPUART1_ASSIGNED 1 # if defined(CONFIG_LPUART1_RXDMA) # define SERIAL_HAVE_CONSOLE_RXDMA 1 # endif @@ -96,7 +184,7 @@ #elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) # define CONSOLE_DEV g_lpuart2priv /* LPUART2 is console */ # define TTYS0_DEV g_lpuart2priv /* LPUART2 is ttyS0 */ -# define UART2_ASSIGNED 1 +# define LPUART2_ASSIGNED 1 # if defined(CONFIG_LPUART2_RXDMA) # define SERIAL_HAVE_CONSOLE_RXDMA 1 # endif @@ -107,47 +195,48 @@ # undef CONSOLE_DEV /* No console */ # if defined(CONFIG_S32K1XX_LPUART0) # define TTYS0_DEV g_lpuart0priv /* LPUART0 is ttyS0 */ -# define UART1_ASSIGNED 1 +# define LPUART0_ASSIGNED 1 # elif defined(CONFIG_S32K1XX_LPUART1) # define TTYS0_DEV g_lpuart1priv /* LPUART1 is ttyS0 */ -# define UART2_ASSIGNED 1 +# define LPUART1_ASSIGNED 1 # elif defined(CONFIG_S32K1XX_LPUART2) # define TTYS0_DEV g_lpuart2priv /* LPUART2 is ttyS0 */ -# define UART3_ASSIGNED 1 +# define LPUART2_ASSIGNED 1 # endif #endif -/* Pick ttys1. This could be any of LPUART0-2 excluding the console UART. - * One of LPUART0-8 could be the console; one of UART0-2 has already been - * assigned to ttys0. +#if defined(SERIAL_HAVE_CONSOLE_RXDMA) || defined(SERIAL_HAVE_CONSOLE_TXDMA) +# define SERIAL_HAVE_CONSOLE_DMA +#endif + +/* Pick ttys1. + * One of LPUART0-3 could be the console; */ -#if defined(CONFIG_S32K1XX_LPUART0) && !defined(UART1_ASSIGNED) +#if defined(CONFIG_S32K1XX_LPUART0) && !defined(LPUART0_ASSIGNED) # define TTYS1_DEV g_lpuart0priv /* LPUART0 is ttyS1 */ -# define UART1_ASSIGNED 1 -#elif defined(CONFIG_S32K1XX_LPUART1) && !defined(UART2_ASSIGNED) +# define LPUART0_ASSIGNED 1 +#elif defined(CONFIG_S32K1XX_LPUART1) && !defined(LPUART1_ASSIGNED) # define TTYS1_DEV g_lpuart1priv /* LPUART1 is ttyS1 */ -# define UART2_ASSIGNED 1 -#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(UART3_ASSIGNED) +# define LPUART1_ASSIGNED 1 +#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(LPUART2_ASSIGNED) # define TTYS1_DEV g_lpuart2priv /* LPUART2 is ttyS1 */ -# define UART3_ASSIGNED 1 +# define LPUART2_ASSIGNED 1 #endif -#if defined(SERIAL_HAVE_CONSOLE_RXDMA) || defined(SERIAL_HAVE_CONSOLE_TXDMA) -# define SERIAL_HAVE_CONSOLE_DMA -#endif - -/* Pick ttys2. This could be one of LPUART0-2. It can't be LPUART0 because - * that was either assigned as ttyS0 or ttys1. One of LPUART0-2 could be the - * console. One of UART1-2 has already been assigned to ttys0 or ttyS1. +/* Pick ttys2. + * One of LPUART0-3 could be the console; */ -#if defined(CONFIG_S32K1XX_LPUART1) && !defined(UART2_ASSIGNED) +#if defined(CONFIG_S32K1XX_LPUART0) && !defined(LPUART0_ASSIGNED) +# define TTYS2_DEV g_lpuart0priv /* LPUART0 is ttyS2 */ +# define LPUART0_ASSIGNED 1 +#elif defined(CONFIG_S32K1XX_LPUART1) && !defined(LPUART1_ASSIGNED) # define TTYS2_DEV g_lpuart1priv /* LPUART1 is ttyS2 */ -# define UART2_ASSIGNED 1 -#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(UART3_ASSIGNED) +# define LPUART1_ASSIGNED 1 +#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(LPUART2_ASSIGNED) # define TTYS2_DEV g_lpuart2priv /* LPUART2 is ttyS2 */ -# define UART3_ASSIGNED 1 +# define LPUART2_ASSIGNED 1 #endif /* Power management definitions */ @@ -166,12 +255,6 @@ # define CONFIG_PM_SERIAL2 #endif -#if !defined(CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE) -# define CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE 32 -#endif - -#define RXDMA_BUFFER_SIZE CONFIG_S32K1XX_SERIAL_RXDMA_BUFFER_SIZE - /**************************************************************************** * Private Types ****************************************************************************/ @@ -187,10 +270,13 @@ struct s32k1xx_uart_s 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; /* U[S]ART RTS GPIO pin configuration */ + const uint32_t rts_gpio; /* LPUART RTS GPIO pin configuration */ #endif #ifdef CONFIG_SERIAL_OFLOWCONTROL - const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */ + const uint32_t cts_gpio; /* LPUART CTS GPIO pin configuration */ +#endif +#ifdef CONFIG_S32K1XX_LPUART_SINGLEWIRE + const uint32_t tx_gpio; /* TX GPIO pin configuration */ #endif uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */ @@ -207,8 +293,7 @@ struct s32k1xx_uart_s #ifdef SERIAL_HAVE_TXDMA const unsigned int dma_txreqsrc; /* DMAMUX source of TX DMA request */ - DMACH_HANDLE txdma; /* currently-open trasnmit DMA stream */ - sem_t txdmasem; /* Indicate TX DMA completion */ + DMACH_HANDLE txdma; /* currently-open transmit DMA stream */ #endif /* RX DMA state */ @@ -218,6 +303,10 @@ struct s32k1xx_uart_s DMACH_HANDLE rxdma; /* currently-open receive DMA stream */ bool rxenable; /* DMA-based reception en/disable */ uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */ +#ifdef CONFIG_ARMV7M_DCACHE + uint32_t rxdmaavail; /* Number of bytes available without need to + * to invalidate the data cache */ +#endif char *const rxfifo; /* Receive DMA buffer */ #endif }; @@ -371,9 +460,9 @@ static const struct uart_ops_s g_lpuart_txdma_ops = .receive = s32k1xx_receive, .rxint = s32k1xx_rxint, .rxavailable = s32k1xx_rxavailable, -#ifdef CONFIG_SERIAL_IFLOWCONTROL - .rxflowcontrol = s32k1xx_rxflowcontrol, -#endif + #ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = s32k1xx_rxflowcontrol, + #endif .send = s32k1xx_send, .txint = s32k1xx_dma_txint, .txready = s32k1xx_txready, @@ -439,17 +528,18 @@ static struct s32k1xx_uart_s g_lpuart0priv = .size = CONFIG_LPUART0_TXBUFSIZE, .buffer = g_lpuart0txbuffer, }, -# if defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + #if defined(CONFIG_LPUART0_RXDMA) && defined(CONFIG_LPUART0_TXDMA) .ops = &g_lpuart_rxtxdma_ops, -# elif defined(CONFIG_LPUART1_RXDMA) && !defined(CONFIG_LPUART1_TXDMA) + #elif defined(CONFIG_LPUART0_RXDMA) && !defined(CONFIG_LPUART0_TXDMA) .ops = &g_lpuart_rxdma_ops, -# elif !defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + #elif !defined(CONFIG_LPUART0_RXDMA) && defined(CONFIG_LPUART0_TXDMA) .ops = &g_lpuart_txdma_ops, -# else + #else .ops = &g_lpuart_ops, -# endif - .priv = &g_lpuart0priv, - }, + #endif + .priv = &g_lpuart0priv, + }, + .uartbase = S32K1XX_LPUART0_BASE, .baud = CONFIG_LPUART0_BAUD, .irq = S32K1XX_IRQ_LPUART0, @@ -463,13 +553,16 @@ static struct s32k1xx_uart_s g_lpuart0priv = # if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART0_IFLOWCONTROL) .iflow = 1, # endif -# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART0_RS485RTSCONTROL)) \ - || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART0_IFLOWCONTROL))) +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART0_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART0_IFLOWCONTROL))) .rts_gpio = PIN_LPUART0_RTS, # endif +# ifdef CONFIG_S32K1XX_LPUART_SINGLEWIRE + .tx_gpio = PIN_LPUART0_TX, +# endif -# if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ - && defined(CONFIG_LPUART0_INVERTIFLOWCONTROL)) +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART0_INVERTIFLOWCONTROL) .inviflow = 1, # endif @@ -503,17 +596,17 @@ static struct s32k1xx_uart_s g_lpuart1priv = .size = CONFIG_LPUART1_TXBUFSIZE, .buffer = g_lpuart1txbuffer, }, -# if defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) - .ops = &g_lpuart_rxtxdma_ops, -# elif defined(CONFIG_LPUART1_RXDMA) && !defined(CONFIG_LPUART1_TXDMA) - .ops = &g_lpuart_rxdma_ops, -# elif !defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) - .ops = &g_lpuart_txdma_ops, -# else - .ops = &g_lpuart_ops, -# endif - .priv = &g_lpuart1priv, - }, +# if defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART1_RXDMA) && !defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + .priv = &g_lpuart1priv, + }, .uartbase = S32K1XX_LPUART1_BASE, .baud = CONFIG_LPUART1_BAUD, @@ -528,12 +621,16 @@ static struct s32k1xx_uart_s g_lpuart1priv = # 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))) +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) .rts_gpio = PIN_LPUART1_RTS, # endif -# if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ - && defined(CONFIG_LPUART1_INVERTIFLOWCONTROL)) +# ifdef CONFIG_S32K1XX_LPUART_SINGLEWIRE + .tx_gpio = PIN_LPUART1_TX, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART1_INVERTIFLOWCONTROL) .inviflow = 1, # endif @@ -565,17 +662,17 @@ static struct s32k1xx_uart_s g_lpuart2priv = .size = CONFIG_LPUART2_TXBUFSIZE, .buffer = g_lpuart2txbuffer, }, -# if defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) +# if defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) .ops = &g_lpuart_rxtxdma_ops, -# elif defined(CONFIG_LPUART1_RXDMA) && !defined(CONFIG_LPUART1_TXDMA) +# elif defined(CONFIG_LPUART2_RXDMA) && !defined(CONFIG_LPUART2_TXDMA) .ops = &g_lpuart_rxdma_ops, -# elif !defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) +# elif !defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) .ops = &g_lpuart_txdma_ops, # else .ops = &g_lpuart_ops, # endif - .priv = &g_lpuart2priv, - }, + .priv = &g_lpuart2priv, + }, .uartbase = S32K1XX_LPUART2_BASE, .baud = CONFIG_LPUART2_BAUD, @@ -590,12 +687,16 @@ static struct s32k1xx_uart_s g_lpuart2priv = # 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))) +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) .rts_gpio = PIN_LPUART2_RTS, # endif -# if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ - && defined(CONFIG_LPUART2_INVERTIFLOWCONTROL)) +# ifdef CONFIG_S32K1XX_LPUART_SINGLEWIRE + .tx_gpio = PIN_LPUART2_TX, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART2_INVERTIFLOWCONTROL) .inviflow = 1, # endif @@ -657,6 +758,7 @@ static inline void s32k1xx_serialout(struct s32k1xx_uart_s *priv, static int s32k1xx_dma_nextrx(struct s32k1xx_uart_s *priv) { int dmaresidual = s32k1xx_dmach_getcount(priv->rxdma); + DEBUGASSERT(dmaresidual <= RXDMA_BUFFER_SIZE); return (RXDMA_BUFFER_SIZE - dmaresidual) % RXDMA_BUFFER_SIZE; } @@ -746,13 +848,11 @@ static int s32k1xx_dma_setup(struct uart_dev_s *dev) if (priv->txdma == NULL) { priv->txdma = s32k1xx_dmach_alloc(priv->dma_txreqsrc | - DMAMUX_CHCFG_ENBL, 0); + DMAMUX_CHCFG_ENBL, 0); if (priv->txdma == NULL) { return -EBUSY; } - - nxsem_init(&priv->txdmasem, 0, 1); } /* Enable Tx DMA for the UART */ @@ -770,7 +870,7 @@ static int s32k1xx_dma_setup(struct uart_dev_s *dev) if (priv->rxdma == NULL) { priv->rxdma = s32k1xx_dmach_alloc(priv->dma_rxreqsrc | - DMAMUX_CHCFG_ENBL, 0); + DMAMUX_CHCFG_ENBL, 0); if (priv->rxdma == NULL) { @@ -785,7 +885,7 @@ static int s32k1xx_dma_setup(struct uart_dev_s *dev) /* Configure for circular DMA reception into the RX FIFO */ config.saddr = priv->uartbase + S32K1XX_LPUART_DATA_OFFSET; - config.daddr = (uint32_t)priv->rxfifo; + config.daddr = (uint32_t) priv->rxfifo; config.soff = 0; config.doff = 1; config.iter = RXDMA_BUFFER_SIZE; @@ -807,18 +907,21 @@ static int s32k1xx_dma_setup(struct uart_dev_s *dev) */ priv->rxdmanext = 0; +#ifdef CONFIG_ARMV7M_DCACHE + priv->rxdmaavail = 0; +#endif /* Enable receive Rx DMA for the UART */ modifyreg32(priv->uartbase + S32K1XX_LPUART_BAUD_OFFSET, 0, LPUART_BAUD_RDMAE); - /* Enable itnerrupt on Idel and errors */ + /* 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_PEIE | + LPUART_CTRL_FEIE | + LPUART_CTRL_NEIE | LPUART_CTRL_ILIE); /* Start the DMA channel, and arrange for callbacks at the half and @@ -839,7 +942,7 @@ static int s32k1xx_dma_setup(struct uart_dev_s *dev) * * Description: * Configure the UART baud, bits, parity, fifos, etc. This - * method is called the first time that the serial port is + * method is called the first time that the serial priv is * opened. * ****************************************************************************/ @@ -865,7 +968,7 @@ static int s32k1xx_setup(struct uart_dev_s *dev) config.usects = priv->oflow; /* Flow control on outbound side */ #endif #ifdef CONFIG_SERIAL_IFLOWCONTROL - /* Flow control on inbound side if not GPIO based */ + /* Flow control on outbound side if not GPIO based */ if ((priv->rts_gpio & _PIN_MODE_MASK) != _PIN_MODE_GPIO) { @@ -880,14 +983,8 @@ static int s32k1xx_setup(struct uart_dev_s *dev) config.invrts = priv->inviflow; /* Inversion of outbound flow control */ #endif - /* configure the LPUART */ - ret = s32k1xx_lpuart_configure(priv->uartbase, &config); - /* get the current interrupt bits and place them in ie */ - - /* (used to use the interrupts) */ - priv->ie = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET) & \ LPUART_ALL_INTS; return ret; @@ -904,7 +1001,7 @@ static int s32k1xx_setup(struct uart_dev_s *dev) * * Description: * Disable the UART. This method is called when the serial - * port is closed + * priv is closed * ****************************************************************************/ @@ -914,13 +1011,7 @@ static void s32k1xx_shutdown(struct uart_dev_s *dev) /* Disable the UART */ - /* set the reset bit */ - s32k1xx_serialout(priv, S32K1XX_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST); - - /* clear the reset bit again */ - - s32k1xx_serialout(priv, S32K1XX_LPUART_GLOBAL_OFFSET, 0); } /**************************************************************************** @@ -966,7 +1057,6 @@ static void s32k1xx_dma_shutdown(struct uart_dev_s *dev) s32k1xx_dmach_free(priv->txdma); priv->txdma = NULL; - nxsem_destroy(&priv->txdmasem); } #endif } @@ -977,12 +1067,12 @@ static void s32k1xx_dma_shutdown(struct uart_dev_s *dev) * * Description: * Configure the UART to operation in interrupt driven mode. This method - * is called when the serial port is opened. Normally, this is just after + * is called when the serial priv is opened. Normally, this is just after * the setup() method is called, however, the serial console may operate * in a non-interrupt driven mode during the boot phase. * * RX and TX interrupts are not enabled when by the attach method (unless - * the hardware supports multiple levels of interrupt enabling). The RX + * the hardware supprivs multiple levels of interrupt enabling). The RX * and TX interrupts are not enabled until the txint() and rxint() methods * are called. * @@ -1012,7 +1102,7 @@ static int s32k1xx_attach(struct uart_dev_s *dev) * Name: s32k1xx_detach * * Description: - * Detach UART interrupts. This method is called when the serial port is + * Detach UART interrupts. This method is called when the serial priv is * closed normally just before the shutdown method is called. The * exception is the serial console which is never shutdown. * @@ -1043,14 +1133,15 @@ static int s32k1xx_interrupt(int irq, void *context, void *arg) struct uart_dev_s *dev = (struct uart_dev_s *)arg; struct s32k1xx_uart_s *priv; uint32_t usr; + uint32_t lsr; int passes = 0; bool handled; - DEBUGASSERT(dev != NULL && dev->priv != NULL); + DEBUGASSERT(dev != NULL && dev != NULL); priv = (struct s32k1xx_uart_s *)dev->priv; #if defined(CONFIG_PM) && CONFIG_S32K1XX_PM_SERIAL_ACTIVITY > 0 - /* Report serial activity to the power management logic */ + /* Repriv serial activity to the power management logic */ pm_activity(PM_IDLE_DOMAIN, CONFIG_S32K1XX_PM_SERIAL_ACTIVITY); #endif @@ -1069,6 +1160,16 @@ static int s32k1xx_interrupt(int irq, void *context, void *arg) */ usr = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); + + /* 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); + + /* 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); @@ -1078,25 +1179,25 @@ static int s32k1xx_interrupt(int irq, void *context, void *arg) if ((usr & LPUART_STAT_OR) != 0) { s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, - LPUART_STAT_OR); + LPUART_STAT_OR | lsr); } if ((usr & LPUART_STAT_NF) != 0) { s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, - LPUART_STAT_NF); + LPUART_STAT_NF | lsr); } if ((usr & LPUART_STAT_PF) != 0) { s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, - LPUART_STAT_PF); + LPUART_STAT_PF | lsr); } if ((usr & LPUART_STAT_FE) != 0) { s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, - LPUART_STAT_FE); + LPUART_STAT_FE | lsr); } if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0) @@ -1112,7 +1213,7 @@ static int s32k1xx_interrupt(int irq, void *context, void *arg) if ((usr & LPUART_STAT_IDLE) != 0) { s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, - LPUART_STAT_IDLE); + LPUART_STAT_IDLE | lsr); s32k1xx_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE); } #endif @@ -1149,11 +1250,9 @@ static int s32k1xx_interrupt(int irq, void *context, void *arg) static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) { -#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) \ - || defined(CONFIG_SERIAL_TERMIOS) \ - || defined(CONFIG_S32K1XX_LPUART_INVERT) +#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) struct inode *inode = filep->f_inode; - struct uart_dev_s *dev = inode->i_private; + struct uart_dev_s *dev = inode->i_private; irqstate_t flags; #endif int ret = OK; @@ -1230,9 +1329,11 @@ static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) termiosp->c_cflag |= CS8; break; +#if defined(CS9) case 9: - termiosp->c_cflag |= CS8 /* CS9 */; + termiosp->c_cflag |= CS9; break; +#endif } } break; @@ -1284,7 +1385,8 @@ static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) case CS8: nbits = 8; break; -#if 0 + +#if defined(CS9) case CS9: nbits = 9; break; @@ -1329,7 +1431,7 @@ static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) * implement TCSADRAIN / TCSAFLUSH */ - flags = spin_lock_irqsave(NULL); + flags = spin_lock_irqsave(NULL); s32k1xx_disableuartint(priv, &ie); ret = dev->ops->setup(dev); @@ -1343,12 +1445,39 @@ static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif /* CONFIG_SERIAL_TERMIOS */ +#ifdef CONFIG_S32K1XX_LPUART_SINGLEWIRE + case TIOCSSINGLEWIRE: + { + uint32_t regval; + irqstate_t flags; + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + + flags = spin_lock_irqsave(NULL); + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET); + + if ((arg & SER_SINGLEWIRE_ENABLED) != 0) + { + regval |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC; + } + else + { + regval &= ~(LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC); + } + + s32k1xx_serialout(priv, S32K1XX_LPUART_CTRL_OFFSET, regval); + + spin_unlock_irqrestore(NULL, flags); + } + break; +#endif + #ifdef CONFIG_S32K1XX_LPUART_INVERT case TIOCSINVERT: { uint32_t ctrl; uint32_t stat; uint32_t regval; + irqstate_t flags; struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; flags = spin_lock_irqsave(NULL); @@ -1375,7 +1504,10 @@ static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) stat &= ~LPUART_STAT_RXINV; } - if (arg & SER_INVERT_ENABLED_TX) + /* Do not invert TX when in TIOCSSINGLEWIRE */ + + if ((arg & SER_INVERT_ENABLED_TX) && + ((ctrl & LPUART_CTRL_LOOPS) != LPUART_CTRL_LOOPS)) { ctrl |= LPUART_CTRL_TXINV; } @@ -1507,7 +1639,7 @@ static bool s32k1xx_rxavailable(struct uart_dev_s *dev) #ifdef CONFIG_SERIAL_IFLOWCONTROL static bool s32k1xx_rxflowcontrol(struct uart_dev_s *dev, - unsigned int nbuffered, bool upper) + unsigned int nbuffered, bool upper) { struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; bool use_swhs = false; @@ -1592,13 +1724,56 @@ static bool s32k1xx_rxflowcontrol(struct uart_dev_s *dev, 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; + uint32_t nextrx = s32k1xx_dma_nextrx(priv); + int c = 0; /* Check if more data is available */ if (nextrx != priv->rxdmanext) { +#ifdef CONFIG_ARMV7M_DCACHE + /* If the data cache is enabled, then we will also need to manage + * cache coherency. Are any bytes available in the currently coherent + * region of the data cache? + */ + + if (priv->rxdmaavail == 0) + { + uint32_t rxdmaavail; + uintptr_t addr; + + /* No.. then we will have to invalidate additional space in the Rx + * DMA buffer. + */ + + if (nextrx > priv->rxdmanext) + { + /* Number of available bytes */ + + rxdmaavail = nextrx - priv->rxdmanext; + } + else + { + /* Number of available bytes up to the end of RXDMA buffer */ + + rxdmaavail = RXDMA_BUFFER_SIZE - priv->rxdmanext; + } + + /* Invalidate the DMA buffer range */ + + addr = (uintptr_t)&priv->rxfifo[priv->rxdmanext]; + up_invalidate_dcache(addr, addr + rxdmaavail); + + /* We don't need to invalidate the data cache for the next + * rxdmaavail number of next bytes. + */ + + priv->rxdmaavail = rxdmaavail; + } + + priv->rxdmaavail--; +#endif + /* Now read from the DMA buffer */ c = priv->rxfifo[priv->rxdmanext]; @@ -1663,6 +1838,9 @@ static void s32k1xx_dma_reenable(struct s32k1xx_uart_s *priv) */ priv->rxdmanext = 0; +#ifdef CONFIG_ARMV7M_DCACHE + priv->rxdmaavail = 0; +#endif /* 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 @@ -1734,7 +1912,7 @@ static bool s32k1xx_dma_rxavailable(struct uart_dev_s *dev) #ifdef SERIAL_HAVE_TXDMA static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, - int result) + int result) { struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)arg; /* Update 'nbytes' indicating number of bytes actually transferred by DMA. @@ -1747,9 +1925,9 @@ static void s32k1xx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, uart_xmitchars_done(&priv->dev); - /* Release waiter */ + /* Send more data if available */ - nxsem_post(&priv->txdmasem); + s32k1xx_dma_txavailable(&priv->dev); } #endif @@ -1768,9 +1946,7 @@ static void s32k1xx_dma_txavailable(struct uart_dev_s *dev) /* Only send when the DMA is idle */ - int rv = nxsem_trywait(&priv->txdmasem); - - if (rv == OK) + if (s32k1xx_dmach_idle(priv->txdma) == 0) { uart_xmitchars_dma(dev); } @@ -1809,7 +1985,7 @@ static void s32k1xx_dma_send(struct uart_dev_s *dev) config.ssize = EDMA_8BIT; config.dsize = EDMA_8BIT; config.nbytes = sizeof(dev->dmatx.buffer[0]); - config.saddr = (uint32_t)dev->dmatx.buffer; + 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; @@ -1817,6 +1993,11 @@ static void s32k1xx_dma_send(struct uart_dev_s *dev) config.linkch = 0; #endif + /* Flush the contents of the TX buffer into physical memory */ + + up_clean_dcache((uintptr_t)dev->dmatx.buffer, + (uintptr_t)dev->dmatx.buffer + dev->dmatx.length); + /* Setup first half */ s32k1xx_dmach_xfrsetup(priv->txdma, &config); @@ -1826,7 +2007,12 @@ static void s32k1xx_dma_send(struct uart_dev_s *dev) if (dev->dmatx.nbuffer) { config.iter = priv->dev.dmatx.nlength; - config.saddr = (uint32_t)priv->dev.dmatx.nbuffer; + config.saddr = (uint32_t) priv->dev.dmatx.nbuffer; + + /* Flush the contents of the next TX buffer into physical memory */ + + up_clean_dcache((uintptr_t)dev->dmatx.nbuffer, + (uintptr_t)dev->dmatx.nbuffer + dev->dmatx.nlength); s32k1xx_dmach_xfrsetup(priv->txdma, &config); } @@ -1867,8 +2053,8 @@ static void s32k1xx_dma_txint(struct uart_dev_s *dev, bool enable) /* In case of DMA transfer we do not want to make use of UART interrupts. * Instead, we use DMA interrupts that are activated once during boot * sequence. Furthermore we can use s32k1xx_dma_txcallback() to handle - * stuff at half DMA transfer or after transfer completion (depending on - * the configuration). + * stuff at half DMA transfer or after transfer completion (depending + * on the configuration). */ } #endif @@ -1914,17 +2100,17 @@ static void s32k1xx_txint(struct uart_dev_s *dev, bool enable) * Name: s32k1xx_txready * * Description: - * Return true if the transmit is completed + * Return true if the transmit register is available to be written to * ****************************************************************************/ static bool s32k1xx_txready(struct uart_dev_s *dev) { - struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev; uint32_t regval; regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); - return ((regval & LPUART_STAT_TC) != 0); + return ((regval & LPUART_STAT_TDRE) != 0); } /**************************************************************************** @@ -1955,7 +2141,7 @@ static bool s32k1xx_txempty(struct uart_dev_s *dev) #ifdef SERIAL_HAVE_RXDMA static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, - int result) + int result) { struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)arg; uint32_t sr; @@ -1979,9 +2165,9 @@ static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, 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)); + sr & (LPUART_STAT_OR | + LPUART_STAT_NF | + LPUART_STAT_FE)); } } #endif @@ -1991,7 +2177,7 @@ static void s32k1xx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, * * Description: * Notify the driver of new power state. This callback is called after - * all drivers have had the opportunity to prepare for the new power state. + * all drivers have had the opprivunity to prepare for the new power state. * * Input Parameters: * @@ -2498,7 +2684,7 @@ void s32k1xx_earlyserialinit(void) * Name: arm_serialinit * * Description: - * Register serial console and serial ports. This assumes + * Register serial console and serial privs. This assumes * that s32k1xx_earlyserialinit was called previously. * ****************************************************************************/ @@ -2520,9 +2706,9 @@ void arm_serialinit(void) #ifdef CONSOLE_DEV uart_register("/dev/console", &CONSOLE_DEV.dev); -# if defined(SERIAL_HAVE_CONSOLE_DMA) +#if defined(SERIAL_HAVE_CONSOLE_DMA) s32k1xx_dma_setup(&CONSOLE_DEV.dev); -# endif +#endif #endif /* Register all UARTs */ @@ -2540,15 +2726,14 @@ void arm_serialinit(void) * Name: up_putc * * Description: - * Provide priority, low-level access to support OS debug writes + * Provide priority, low-level access to suppriv OS debug writes * ****************************************************************************/ int up_putc(int ch) { #ifdef CONSOLE_DEV - struct s32k1xx_uart_s *priv = - (struct s32k1xx_uart_s *)CONSOLE_DEV.dev.priv; + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)&CONSOLE_DEV; uint32_t ie; s32k1xx_disableuartint(priv, &ie); @@ -2575,7 +2760,7 @@ int up_putc(int ch) * Name: up_putc * * Description: - * Provide priority, low-level access to support OS debug writes + * Provide priority, low-level access to suppriv OS debug writes * ****************************************************************************/