From fa58381e58846362e22de0f7a5384ec84315c899 Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Thu, 9 Jun 2022 13:31:43 -0700 Subject: [PATCH] imxrt:serial add TX & RX DMA support imxrt:serial ioctl should call to proper setup --- arch/arm/src/imxrt/imxrt_serial.c | 1798 +++++++++++++++++++++++------ arch/arm/src/imxrt/imxrt_serial.h | 184 +++ 2 files changed, 1656 insertions(+), 326 deletions(-) diff --git a/arch/arm/src/imxrt/imxrt_serial.c b/arch/arm/src/imxrt/imxrt_serial.c index a3eba38136e..5c650737cf9 100644 --- a/arch/arm/src/imxrt/imxrt_serial.c +++ b/arch/arm/src/imxrt/imxrt_serial.c @@ -51,15 +51,136 @@ #include "arm_internal.h" #include "hardware/imxrt_lpuart.h" #include "imxrt_gpio.h" +#include "imxrt_edma.h" +#include "hardware/imxrt_dmamux.h" #include "hardware/imxrt_pinmux.h" #include "imxrt_config.h" #include "imxrt_lowputc.h" +#include "imxrt_serial.h" #ifdef USE_SERIALDRIVER -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ +/* 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_IMXRT_SERIAL_RXDMA_BUFFER_SIZE) || \ + (CONFIG_IMXRT_SERIAL_RXDMA_BUFFER_SIZE < ARMV7M_DCACHE_LINESIZE) +# undef CONFIG_IMXRT_SERIAL_RXDMA_BUFFER_SIZE +# define CONFIG_IMXRT_SERIAL_RXDMA_BUFFER_SIZE ARMV7M_DCACHE_LINESIZE +# endif + +# define RXDMA_BUFFER_MASK (ARMV7M_DCACHE_LINESIZE - 1) +# define RXDMA_BUFFER_SIZE ((CONFIG_IMXRT_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! + */ + +#if !defined(ARMV7M_DCACHE_LINESIZE) || ARMV7M_DCACHE_LINESIZE == 0 +# undef ARMV7M_DCACHE_LINESIZE +# define ARMV7M_DCACHE_LINESIZE 32 +#endif + +#define TXDMA_BUFFER_MASK (ARMV7M_DCACHE_LINESIZE - 1) +#define TXDMA_BUFFER_SIZE ((CONFIG_IMXRT_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_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 + +#if !defined(CONFIG_LPUART4_TXDMA) +# define LPUART4_TXBUFSIZE_ADJUSTED CONFIG_LPUART4_TXBUFSIZE +# define LPUART4_TXBUFSIZE_ALGN +#else +# define LPUART4_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART4_TXBUFSIZE) +# define LPUART4_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART5_TXDMA) +# define LPUART5_TXBUFSIZE_ADJUSTED CONFIG_LPUART5_TXBUFSIZE +# define LPUART5_TXBUFSIZE_ALGN +#else +# define LPUART5_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART5_TXBUFSIZE) +# define LPUART5_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART6_TXDMA) +# define LPUART6_TXBUFSIZE_ADJUSTED CONFIG_LPUART6_TXBUFSIZE +# define LPUART6_TXBUFSIZE_ALGN +#else +# define LPUART6_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART6_TXBUFSIZE) +# define LPUART6_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART7_TXDMA) +# define LPUART7_TXBUFSIZE_ADJUSTED CONFIG_LPUART7_TXBUFSIZE +# define LPUART7_TXBUFSIZE_ALGN +#else +# define LPUART7_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART7_TXBUFSIZE) +# define LPUART7_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART8_TXDMA) +# define LPUART8_TXBUFSIZE_ADJUSTED CONFIG_LPUART8_TXBUFSIZE +# define LPUART8_TXBUFSIZE_ALGN +#else +# define LPUART8_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART8_TXBUFSIZE) +# define LPUART8_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif /* Which LPUART with be tty0/console and which tty1-7? The console will * always be ttyS0. If there is no console then will use the lowest @@ -69,95 +190,147 @@ /* First pick the console and ttys0. This could be any of LPUART1-8 */ #if defined(CONFIG_LPUART1_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart1port /* LPUART1 is console */ -# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */ -# define UART1_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart1priv /* LPUART1 is console */ +# define TTYS0_DEV g_lpuart1priv /* LPUART1 is ttyS0 */ +# define LPUART1_ASSIGNED 1 +# if defined(CONFIG_LPUART1_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART1_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart2port /* LPUART2 is console */ -# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */ -# define UART2_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart2priv /* LPUART2 is console */ +# define TTYS0_DEV g_lpuart2priv /* LPUART2 is ttyS0 */ +# define LPUART2_ASSIGNED 1 +# if defined(CONFIG_LPUART2_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART2_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #elif defined(CONFIG_LPUART3_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart3port /* LPUART3 is console */ -# define TTYS0_DEV g_uart3port /* LPUART3 is ttyS0 */ -# define UART3_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart3priv /* LPUART3 is console */ +# define TTYS0_DEV g_lpuart3priv /* LPUART3 is ttyS0 */ +# define LPUART3_ASSIGNED 1 +# if defined(CONFIG_LPUART3_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART3_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #elif defined(CONFIG_LPUART4_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart4port /* LPUART4 is console */ -# define TTYS0_DEV g_uart4port /* LPUART4 is ttyS0 */ -# define UART4_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart4priv /* LPUART4 is console */ +# define TTYS0_DEV g_lpuart4priv /* LPUART4 is ttyS0 */ +# define LPUART4_ASSIGNED 1 +# if defined(CONFIG_LPUART4_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART4_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #elif defined(CONFIG_LPUART5_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart5port /* LPUART5 is console */ -# define TTYS0_DEV g_uart5port /* LPUART5 is ttyS0 */ -# define UART5_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart5priv /* LPUART5 is console */ +# define TTYS0_DEV g_lpuart5priv /* LPUART5 is ttyS0 */ +# define LPUART5_ASSIGNED 1 +# if defined(CONFIG_LPUART5_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART5_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #elif defined(CONFIG_LPUART6_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart6port /* LPUART6 is console */ -# define TTYS0_DEV g_uart6port /* LPUART6 is ttyS0 */ -# define UART6_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart6priv /* LPUART6 is console */ +# define TTYS0_DEV g_lpuart6priv /* LPUART6 is ttyS0 */ +# define LPUART6_ASSIGNED 1 +# if defined(CONFIG_LPUART6_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART6_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #elif defined(CONFIG_LPUART7_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart7port /* LPUART7 is console */ -# define TTYS0_DEV g_uart7port /* LPUART7 is ttyS0 */ -# define UART7_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart7priv /* LPUART7 is console */ +# define TTYS0_DEV g_lpuart7priv /* LPUART7 is ttyS0 */ +# define LPUART7_ASSIGNED 1 +# if defined(CONFIG_LPUART7_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART7_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #elif defined(CONFIG_LPUART8_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart8port /* LPUART8 is console */ -# define TTYS0_DEV g_uart8port /* LPUART8 is ttyS0 */ -# define UART8_ASSIGNED 1 +# define CONSOLE_DEV g_lpuart8priv /* LPUART8 is console */ +# define TTYS0_DEV g_lpuart8priv /* LPUART8 is ttyS0 */ +# define LPUART8_ASSIGNED 1 +# if defined(CONFIG_LPUART8_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART9_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif #else # undef CONSOLE_DEV /* No console */ # if defined(CONFIG_IMXRT_LPUART1) -# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */ +# define TTYS0_DEV g_lpuart1priv /* LPUART1 is ttyS0 */ # define UART1_ASSIGNED 1 # elif defined(CONFIG_IMXRT_LPUART2) -# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */ +# define TTYS0_DEV g_lpuart2priv /* LPUART2 is ttyS0 */ # define UART2_ASSIGNED 1 # elif defined(CONFIG_IMXRT_LPUART3) -# define TTYS0_DEV g_uart3port /* LPUART3 is ttyS0 */ +# define TTYS0_DEV g_lpuart3priv /* LPUART3 is ttyS0 */ # define UART3_ASSIGNED 1 # elif defined(CONFIG_IMXRT_LPUART4) -# define TTYS0_DEV g_uart4port /* LPUART4 is ttyS0 */ +# define TTYS0_DEV g_lpuart4priv /* LPUART4 is ttyS0 */ # define UART4_ASSIGNED 1 # elif defined(CONFIG_IMXRT_LPUART5) -# define TTYS0_DEV g_uart5port /* LPUART5 is ttyS0 */ +# define TTYS0_DEV g_lpuart5priv /* LPUART5 is ttyS0 */ # define UART5_ASSIGNED 1 # elif defined(CONFIG_IMXRT_LPUART6) -# define TTYS0_DEV g_uart6port /* LPUART6 is ttyS0 */ +# define TTYS0_DEV g_lpuart6priv /* LPUART6 is ttyS0 */ # define UART6_ASSIGNED 1 # elif defined(CONFIG_IMXRT_LPUART7) -# define TTYS0_DEV g_uart7port /* LPUART7 is ttyS0 */ +# define TTYS0_DEV g_lpuart7priv /* LPUART7 is ttyS0 */ # define UART7_ASSIGNED 1 # elif defined(CONFIG_IMXRT_LPUART8) -# define TTYS0_DEV g_uart8port /* LPUART8 is ttyS0 */ +# define TTYS0_DEV g_lpuart8priv /* LPUART8 is ttyS0 */ # define UART8_ASSIGNED 1 # endif #endif +#if defined(SERIAL_HAVE_CONSOLE_RXDMA) || defined(SERIAL_HAVE_CONSOLE_TXDMA) +# define SERIAL_HAVE_CONSOLE_DMA +#endif + /* Pick ttys1. This could be any of UART1-8 excluding the console UART. * One of UART1-8 could be the console; one of UART1-8 has already been * assigned to ttys0. */ -#if defined(CONFIG_IMXRT_LPUART1) && !defined(UART1_ASSIGNED) -# define TTYS1_DEV g_uart1port /* LPUART1 is ttyS1 */ -# define UART1_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART2) && !defined(UART2_ASSIGNED) -# define TTYS1_DEV g_uart2port /* LPUART2 is ttyS1 */ -# define UART2_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART3) && !defined(UART3_ASSIGNED) -# define TTYS1_DEV g_uart3port /* LPUART3 is ttyS1 */ -# define UART3_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) -# define TTYS1_DEV g_uart4port /* LPUART4 is ttyS1 */ -# define UART4_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) -# define TTYS1_DEV g_uart5port /* LPUART5 is ttyS1 */ -# define UART5_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) -# define TTYS1_DEV g_uart6port /* LPUART6 is ttyS1 */ -# define UART6_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) -# define TTYS1_DEV g_uart7port /* LPUART7 is ttyS1 */ -# define UART7_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) -# define TTYS1_DEV g_uart8port /* LPUART8 is ttyS1 */ -# define UART8_ASSIGNED 1 +#if defined(CONFIG_IMXRT_LPUART1) && !defined(LPUART1_ASSIGNED) +# define TTYS1_DEV g_lpuart1priv /* LPUART1 is ttyS1 */ +# define LPUART1_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART2) && !defined(LPUART2_ASSIGNED) +# define TTYS1_DEV g_lpuart2priv /* LPUART2 is ttyS1 */ +# define LPUART2_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART3) && !defined(LPUART3_ASSIGNED) +# define TTYS1_DEV g_lpuart3priv /* LPUART3 is ttyS1 */ +# define LPUART3_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(LPUART4_ASSIGNED) +# define TTYS1_DEV g_lpuart4priv /* LPUART4 is ttyS1 */ +# define LPUART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(LPUART5_ASSIGNED) +# define TTYS1_DEV g_lpuart5priv /* LPUART5 is ttyS1 */ +# define LPUART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(LPUART6_ASSIGNED) +# define TTYS1_DEV g_lpuart6priv /* LPUART6 is ttyS1 */ +# define LPUART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(LPUART7_ASSIGNED) +# define TTYS1_DEV g_lpuart7priv /* LPUART7 is ttyS1 */ +# define LPUART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(LPUART8_ASSIGNED) +# define TTYS1_DEV g_lpuart8priv /* LPUART8 is ttyS1 */ +# define LPUART8_ASSIGNED 1 #endif /* Pick ttys2. This could be one of UART2-8. It can't be UART1 because that @@ -165,27 +338,27 @@ * console. One of UART2-8 has already been assigned to ttys0 or ttyS1. */ -#if defined(CONFIG_IMXRT_LPUART2) && !defined(UART2_ASSIGNED) -# define TTYS2_DEV g_uart2port /* LPUART2 is ttyS2 */ -# define UART2_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART3) && !defined(UART3_ASSIGNED) -# define TTYS2_DEV g_uart3port /* LPUART3 is ttyS2 */ -# define UART3_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) -# define TTYS2_DEV g_uart4port /* LPUART4 is ttyS2 */ -# define UART4_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) -# define TTYS2_DEV g_uart5port /* LPUART5 is ttyS2 */ -# define UART5_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) -# define TTYS2_DEV g_uart6port /* LPUART6 is ttyS2 */ -# define UART6_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) -# define TTYS2_DEV g_uart7port /* LPUART7 is ttyS2 */ -# define UART7_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) -# define TTYS2_DEV g_uart8port /* LPUART8 is ttyS2 */ -# define UART8_ASSIGNED 1 +#if defined(CONFIG_IMXRT_LPUART2) && !defined(LPUART2_ASSIGNED) +# define TTYS2_DEV g_lpuart2priv /* LPUART2 is ttyS2 */ +# define LPUART2_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART3) && !defined(LPUART3_ASSIGNED) +# define TTYS2_DEV g_lpuart3priv /* LPUART3 is ttyS2 */ +# define LPUART3_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(LPUART4_ASSIGNED) +# define TTYS2_DEV g_lpuart4priv /* LPUART4 is ttyS2 */ +# define LPUART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(LPUART5_ASSIGNED) +# define TTYS2_DEV g_lpuart5priv /* LPUART5 is ttyS2 */ +# define LPUART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(LPUART6_ASSIGNED) +# define TTYS2_DEV g_lpuart6priv /* LPUART6 is ttyS2 */ +# define LPUART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(LPUART7_ASSIGNED) +# define TTYS2_DEV g_lpuart7priv /* LPUART7 is ttyS2 */ +# define LPUART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(LPUART8_ASSIGNED) +# define TTYS2_DEV g_lpuart8priv /* LPUART8 is ttyS2 */ +# define LPUART8_ASSIGNED 1 #endif /* Pick ttys3. This could be one of UART3-8. It can't be UART1-2 because @@ -194,24 +367,24 @@ * been assigned to ttys0, 1, or 3. */ -#if defined(CONFIG_IMXRT_LPUART3) && !defined(UART3_ASSIGNED) -# define TTYS3_DEV g_uart3port /* LPUART3 is ttyS3 */ -# define UART3_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) -# define TTYS3_DEV g_uart4port /* LPUART4 is ttyS3 */ -# define UART4_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) -# define TTYS3_DEV g_uart5port /* LPUART5 is ttyS3 */ -# define UART5_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) -# define TTYS3_DEV g_uart6port /* LPUART6 is ttyS3 */ -# define UART6_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) -# define TTYS3_DEV g_uart7port /* LPUART7 is ttyS3 */ -# define UART7_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) -# define TTYS3_DEV g_uart8port /* LPUART8 is ttyS3 */ -# define UART8_ASSIGNED 1 +#if defined(CONFIG_IMXRT_LPUART3) && !defined(LPUART3_ASSIGNED) +# define TTYS3_DEV g_lpuart3priv /* LPUART3 is ttyS3 */ +# define LPUART3_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(LPUART4_ASSIGNED) +# define TTYS3_DEV g_lpuart4priv /* LPUART4 is ttyS3 */ +# define LPUART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(LPUART5_ASSIGNED) +# define TTYS3_DEV g_lpuart5priv /* LPUART5 is ttyS3 */ +# define LPUART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(LPUART6_ASSIGNED) +# define TTYS3_DEV g_lpuart6priv /* LPUART6 is ttyS3 */ +# define LPUART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(LPUART7_ASSIGNED) +# define TTYS3_DEV g_lpuart7priv /* LPUART7 is ttyS3 */ +# define LPUART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(LPUART8_ASSIGNED) +# define TTYS3_DEV g_lpuart8priv /* LPUART8 is ttyS3 */ +# define LPUART8_ASSIGNED 1 #endif /* Pick ttys4. This could be one of UART4-8. It can't be UART1-3 because @@ -220,21 +393,21 @@ * assigned to ttys0, 1, 3, or 4. */ -#if defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) -# define TTYS4_DEV g_uart4port /* LPUART4 is ttyS4 */ -# define UART4_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) -# define TTYS4_DEV g_uart5port /* LPUART5 is ttyS4 */ -# define UART5_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) -# define TTYS4_DEV g_uart6port /* LPUART6 is ttyS4 */ -# define UART6_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) -# define TTYS4_DEV g_uart7port /* LPUART7 is ttyS4 */ -# define UART7_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) -# define TTYS4_DEV g_uart8port /* LPUART8 is ttyS4 */ -# define UART8_ASSIGNED 1 +#if defined(CONFIG_IMXRT_LPUART4) && !defined(LPUART4_ASSIGNED) +# define TTYS4_DEV g_lpuart4priv /* LPUART4 is ttyS4 */ +# define LPUART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(LPUART5_ASSIGNED) +# define TTYS4_DEV g_lpuart5priv /* LPUART5 is ttyS4 */ +# define LPUART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(LPUART6_ASSIGNED) +# define TTYS4_DEV g_lpuart6priv /* LPUART6 is ttyS4 */ +# define LPUART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(LPUART7_ASSIGNED) +# define TTYS4_DEV g_lpuart7priv /* LPUART7 is ttyS4 */ +# define LPUART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(LPUART8_ASSIGNED) +# define TTYS4_DEV g_lpuart8priv /* LPUART8 is ttyS4 */ +# define LPUART8_ASSIGNED 1 #endif /* Pick ttys5. This could be one of UART5-8. It can't be UART1-4 because @@ -243,18 +416,18 @@ * assigned to ttys0, 1, 2, 3, or 4. */ -#if defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) -# define TTYS5_DEV g_uart5port /* LPUART5 is ttyS5 */ -# define UART5_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) -# define TTYS5_DEV g_uart6port /* LPUART6 is ttyS5 */ -# define UART6_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) -# define TTYS5_DEV g_uart7port /* LPUART7 is ttyS5 */ -# define UART7_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) -# define TTYS5_DEV g_uart8port /* LPUART8 is ttyS5 */ -# define UART8_ASSIGNED 1 +#if defined(CONFIG_IMXRT_LPUART5) && !defined(LPUART5_ASSIGNED) +# define TTYS5_DEV g_lpuart5priv /* LPUART5 is ttyS5 */ +# define LPUART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(LPUART6_ASSIGNED) +# define TTYS5_DEV g_lpuart6priv /* LPUART6 is ttyS5 */ +# define LPUART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(LPUART7_ASSIGNED) +# define TTYS5_DEV g_lpuart7priv /* LPUART7 is ttyS5 */ +# define LPUART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(LPUART8_ASSIGNED) +# define TTYS5_DEV g_lpuart8priv /* LPUART8 is ttyS5 */ +# define LPUART8_ASSIGNED 1 #endif /* Pick ttys6. This could be one of UART6-8. It can't be UART1-5 because @@ -263,15 +436,15 @@ * assigned to ttys0, 1, 2, 3, 4 or 5. */ -#if defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) -# define TTYS6_DEV g_uart6port /* LPUART6 is ttyS5 */ -# define UART6_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) -# define TTYS6_DEV g_uart7port /* LPUART7 is ttyS5 */ -# define UART7_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) -# define TTYS6_DEV g_uart8port /* LPUART8 is ttyS5 */ -# define UART8_ASSIGNED 1 +#if defined(CONFIG_IMXRT_LPUART6) && !defined(LPUART6_ASSIGNED) +# define TTYS6_DEV g_lpuart6priv /* LPUART6 is ttyS5 */ +# define LPUART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(LPUART7_ASSIGNED) +# define TTYS6_DEV g_lpuart7priv /* LPUART7 is ttyS5 */ +# define LPUART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(LPUART8_ASSIGNED) +# define TTYS6_DEV g_lpuart8priv /* LPUART8 is ttyS5 */ +# define LPUART8_ASSIGNED 1 #endif /* Pick ttys7. This could be one of UART7-8. It can't be UART1-6 because @@ -280,12 +453,12 @@ * assigned to ttys0, 1, 2, 3, 4, 5 or 6. */ -#if defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) -# define TTYS7_DEV g_uart7port /* LPUART7 is ttyS5 */ -# define UART7_ASSIGNED 1 -#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) -# define TTYS7_DEV g_uart8port /* LPUART8 is ttyS5 */ -# define UART8_ASSIGNED 1 +#if defined(CONFIG_IMXRT_LPUART7) && !defined(LPUART7_ASSIGNED) +# define TTYS7_DEV g_lpuart7priv /* LPUART7 is ttyS5 */ +# define LPUART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(LPUART8_ASSIGNED) +# define TTYS7_DEV g_lpuart8port /* LPUART8 is ttyS5 */ +# define LPUART8_ASSIGNED 1 #endif /* UART, if available, should have been assigned to ttyS0-7. */ @@ -302,6 +475,7 @@ struct imxrt_uart_s { + struct uart_dev_s dev; /* Generic UART device */ uint32_t uartbase; /* Base address of UART registers */ uint32_t baud; /* Configured baud */ uint32_t ie; /* Saved enabled interrupts */ @@ -310,10 +484,10 @@ struct imxrt_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_IMXRT_LPUART_SINGLEWIRE const uint32_t tx_gpio; /* TX GPIO pin configuration */ @@ -328,6 +502,23 @@ struct imxrt_uart_s #endif #ifdef CONFIG_SERIAL_RS485CONTROL uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */ +#endif + /* TX DMA state */ + +#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 */ +#endif + + /* RX DMA state */ + +#ifdef SERIAL_HAVE_RXDMA + const unsigned int dma_rxreqsrc; /* DMAMUX source of RX DMA request */ + 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 */ + char *const rxfifo; /* Receive DMA buffer */ #endif }; @@ -350,12 +541,48 @@ static int imxrt_attach(struct uart_dev_s *dev); static void imxrt_detach(struct uart_dev_s *dev); static int imxrt_interrupt(int irq, void *context, void *arg); static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg); +#if !defined(SERIAL_HAVE_ONLY_RXDMA) static int imxrt_receive(struct uart_dev_s *dev, unsigned int *status); static void imxrt_rxint(struct uart_dev_s *dev, bool enable); static bool imxrt_rxavailable(struct uart_dev_s *dev); -static void imxrt_send(struct uart_dev_s *dev, int ch); +#endif +#if !defined(SERIAL_HAVE_ONLY_TXDMA) static void imxrt_txint(struct uart_dev_s *dev, bool enable); +#endif + +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool imxrt_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper); +#endif +static void imxrt_send(struct uart_dev_s *dev, int ch); + static bool imxrt_txready(struct uart_dev_s *dev); + +#ifdef SERIAL_HAVE_TXDMA +static void imxrt_dma_send(struct uart_dev_s *dev); +static void imxrt_dma_txint(struct uart_dev_s *dev, bool enable); +static void imxrt_dma_txavailable(struct uart_dev_s *dev); +static void imxrt_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int imxrt_dma_setup(struct uart_dev_s *dev); +static void imxrt_dma_shutdown(struct uart_dev_s *dev); +#endif + +#ifdef SERIAL_HAVE_RXDMA +static int imxrt_dma_receive(struct uart_dev_s *dev, unsigned int *status); +#ifdef CONFIG_PM +static void imxrt_dma_reenable(struct imxrt_uart_s *priv); +#endif +static void imxrt_dma_rxint(struct uart_dev_s *dev, bool enable); +static bool imxrt_dma_rxavailable(struct uart_dev_s *dev); + +static void imxrt_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + static bool imxrt_txempty(struct uart_dev_s *dev); #ifdef CONFIG_PM @@ -371,7 +598,8 @@ static int up_pm_prepare(struct pm_callback_s *cb, int domain, /* Serial driver UART operations */ -static const struct uart_ops_s g_uart_ops = +#if !defined(SERIAL_HAVE_ONLY_TXDMA) && !defined(SERIAL_HAVE_ONLY_RXDMA) +static const struct uart_ops_s g_lpuart_ops = { .setup = imxrt_setup, .shutdown = imxrt_shutdown, @@ -382,61 +610,210 @@ static const struct uart_ops_s g_uart_ops = .rxint = imxrt_rxint, .rxavailable = imxrt_rxavailable, #ifdef CONFIG_SERIAL_IFLOWCONTROL - .rxflowcontrol = NULL, + .rxflowcontrol = imxrt_rxflowcontrol, #endif .send = imxrt_send, .txint = imxrt_txint, .txready = imxrt_txready, .txempty = imxrt_txempty, }; +#endif + +#if defined(SERIAL_HAVE_RXDMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_lpuart_rxtxdma_ops = +{ + .setup = imxrt_dma_setup, + .shutdown = imxrt_dma_shutdown, + .attach = imxrt_attach, + .detach = imxrt_detach, + .ioctl = imxrt_ioctl, + .receive = imxrt_dma_receive, + .rxint = imxrt_dma_rxint, + .rxavailable = imxrt_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = imxrt_rxflowcontrol, +#endif + .send = imxrt_send, + .txint = imxrt_dma_txint, + .txready = imxrt_txready, + .txempty = imxrt_txempty, + .dmatxavail = imxrt_dma_txavailable, + .dmasend = imxrt_dma_send, +}; +#endif +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA) +static const struct uart_ops_s g_lpuart_rxdma_ops = +{ + .setup = imxrt_dma_setup, + .shutdown = imxrt_dma_shutdown, + .attach = imxrt_attach, + .detach = imxrt_detach, + .ioctl = imxrt_ioctl, + .receive = imxrt_dma_receive, + .rxint = imxrt_dma_rxint, + .rxavailable = imxrt_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = imxrt_rxflowcontrol, +#endif + .send = imxrt_send, + .txint = imxrt_txint, + .txready = imxrt_txready, + .txempty = imxrt_txempty, +}; +#endif + +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_lpuart_txdma_ops = +{ + .setup = imxrt_dma_setup, + .shutdown = imxrt_dma_shutdown, + .attach = imxrt_attach, + .detach = imxrt_detach, + .ioctl = imxrt_ioctl, + .receive = imxrt_receive, + .rxint = imxrt_rxint, + .rxavailable = imxrt_rxavailable, + #ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = imxrt_rxflowcontrol, + #endif + .send = imxrt_send, + .txint = imxrt_dma_txint, + .txready = imxrt_txready, + .txempty = imxrt_txempty, + .dmatxavail = imxrt_dma_txavailable, + .dmasend = imxrt_dma_send, +}; +#endif + +/* Avoid unused warning */ +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA) +const struct uart_ops_s *g_o0 = &g_lpuart_rxdma_ops; +#endif +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA) +const struct uart_ops_s *g_o1 = &g_lpuart_txdma_ops; +#endif /* I/O buffers */ +#ifdef CONFIG_LPUART1_RXDMA +static char g_lpuart1rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +# ifdef CONFIG_LPUART2_RXDMA +static char g_lpuart2rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART3_RXDMA +static char g_lpuart3rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART4_RXDMA +static char g_lpuart4rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART5_RXDMA +static char g_lpuart5rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART6_RXDMA +static char g_lpuart6rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART7_RXDMA +static char g_lpuart7rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART8_RXDMA +static char g_lpuart8rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV7M_DCACHE_LINESIZE); +#endif + +/* Receive/Transmit buffers */ + #ifdef CONFIG_IMXRT_LPUART1 -static char g_uart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE]; -static char g_uart1txbuffer[CONFIG_LPUART1_TXBUFSIZE]; +static char g_lpuart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE]; +static char g_lpuart1txbuffer[LPUART1_TXBUFSIZE_ADJUSTED] \ + LPUART1_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_IMXRT_LPUART2 -static char g_uart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE]; -static char g_uart2txbuffer[CONFIG_LPUART2_TXBUFSIZE]; +static char g_lpuart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE]; +static char g_lpuart2txbuffer[LPUART2_TXBUFSIZE_ADJUSTED] \ + LPUART2_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_IMXRT_LPUART3 -static char g_uart3rxbuffer[CONFIG_LPUART3_RXBUFSIZE]; -static char g_uart3txbuffer[CONFIG_LPUART3_TXBUFSIZE]; +static char g_lpuart3rxbuffer[CONFIG_LPUART3_RXBUFSIZE]; +static char g_lpuart3txbuffer[LPUART3_TXBUFSIZE_ADJUSTED] \ + LPUART3_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_IMXRT_LPUART4 -static char g_uart4rxbuffer[CONFIG_LPUART4_RXBUFSIZE]; -static char g_uart4txbuffer[CONFIG_LPUART4_TXBUFSIZE]; +static char g_lpuart4rxbuffer[CONFIG_LPUART4_RXBUFSIZE]; +static char g_lpuart4txbuffer[LPUART4_TXBUFSIZE_ADJUSTED] \ + LPUART4_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_IMXRT_LPUART5 -static char g_uart5rxbuffer[CONFIG_LPUART5_RXBUFSIZE]; -static char g_uart5txbuffer[CONFIG_LPUART5_TXBUFSIZE]; +static char g_lpuart5rxbuffer[CONFIG_LPUART5_RXBUFSIZE]; +static char g_lpuart5txbuffer[LPUART5_TXBUFSIZE_ADJUSTED] \ + LPUART5_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_IMXRT_LPUART6 -static char g_uart6rxbuffer[CONFIG_LPUART6_RXBUFSIZE]; -static char g_uart6txbuffer[CONFIG_LPUART6_TXBUFSIZE]; +static char g_lpuart6rxbuffer[CONFIG_LPUART6_RXBUFSIZE]; +static char g_lpuart6txbuffer[LPUART6_TXBUFSIZE_ADJUSTED] \ + LPUART6_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_IMXRT_LPUART7 -static char g_uart7rxbuffer[CONFIG_LPUART7_RXBUFSIZE]; -static char g_uart7txbuffer[CONFIG_LPUART7_TXBUFSIZE]; +static char g_lpuart7rxbuffer[CONFIG_LPUART7_RXBUFSIZE]; +static char g_lpuart7txbuffer[LPUART7_TXBUFSIZE_ADJUSTED] \ + LPUART7_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_IMXRT_LPUART8 -static char g_uart8rxbuffer[CONFIG_LPUART8_RXBUFSIZE]; -static char g_uart8txbuffer[CONFIG_LPUART8_TXBUFSIZE]; +static char g_lpuart8rxbuffer[CONFIG_LPUART8_RXBUFSIZE]; +static char g_lpuart8txbuffer[LPUART8_TXBUFSIZE_ADJUSTED] \ + LPUART8_TXBUFSIZE_ALGN; #endif /* This describes the state of the IMXRT lpuart1 port. */ #ifdef CONFIG_IMXRT_LPUART1 -static struct imxrt_uart_s g_uart1priv = +static struct imxrt_uart_s g_lpuart1priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART1_RXBUFSIZE, + .buffer = g_lpuart1rxbuffer, + }, + .xmit = + { + .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, + }, + .uartbase = IMXRT_LPUART1_BASE, .baud = CONFIG_LPUART1_BAUD, .irq = IMXRT_IRQ_LPUART1, @@ -466,30 +843,46 @@ static struct imxrt_uart_s g_uart1priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart1port = -{ - .recv = - { - .size = CONFIG_LPUART1_RXBUFSIZE, - .buffer = g_uart1rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART1_TXBUFSIZE, - .buffer = g_uart1txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart1priv, +#ifdef CONFIG_LPUART1_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART1_TX, +#endif +#ifdef CONFIG_LPUART1_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART1_RX, + .rxfifo = g_lpuart1rxfifo, +#endif }; #endif /* This describes the state of the IMXRT lpuart2 port. */ #ifdef CONFIG_IMXRT_LPUART2 -static struct imxrt_uart_s g_uart2priv = +static struct imxrt_uart_s g_lpuart2priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART2_RXBUFSIZE, + .buffer = g_lpuart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART2_TXBUFSIZE, + .buffer = g_lpuart2txbuffer, + }, + #if defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART2_RXDMA) && !defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + .priv = &g_lpuart2priv, + }, + .uartbase = IMXRT_LPUART2_BASE, .baud = CONFIG_LPUART2_BAUD, .irq = IMXRT_IRQ_LPUART2, @@ -518,28 +911,44 @@ static struct imxrt_uart_s g_uart2priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart2port = -{ - .recv = - { - .size = CONFIG_LPUART2_RXBUFSIZE, - .buffer = g_uart2rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART2_TXBUFSIZE, - .buffer = g_uart2txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart2priv, +#ifdef CONFIG_LPUART2_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART2_TX, +#endif +#ifdef CONFIG_LPUART2_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART2_RX, + .rxfifo = g_lpuart2rxfifo, +#endif }; #endif #ifdef CONFIG_IMXRT_LPUART3 -static struct imxrt_uart_s g_uart3priv = +static struct imxrt_uart_s g_lpuart3priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART3_RXBUFSIZE, + .buffer = g_lpuart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART3_TXBUFSIZE, + .buffer = g_lpuart3txbuffer, + }, + #if defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART3_RXDMA) && !defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + .priv = &g_lpuart3priv, + }, + .uartbase = IMXRT_LPUART3_BASE, .baud = CONFIG_LPUART3_BAUD, .irq = IMXRT_IRQ_LPUART3, @@ -568,28 +977,44 @@ static struct imxrt_uart_s g_uart3priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart3port = -{ - .recv = - { - .size = CONFIG_LPUART3_RXBUFSIZE, - .buffer = g_uart3rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART3_TXBUFSIZE, - .buffer = g_uart3txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart3priv, +#ifdef CONFIG_LPUART3_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART3_TX, +#endif +#ifdef CONFIG_LPUART3_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART3_RX, + .rxfifo = g_lpuart3rxfifo, +#endif }; #endif #ifdef CONFIG_IMXRT_LPUART4 -static struct imxrt_uart_s g_uart4priv = +static struct imxrt_uart_s g_lpuart4priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART4_RXBUFSIZE, + .buffer = g_lpuart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART4_TXBUFSIZE, + .buffer = g_lpuart4txbuffer, + }, + #if defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART4_RXDMA) && !defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + .priv = &g_lpuart4priv, + }, + .uartbase = IMXRT_LPUART4_BASE, .baud = CONFIG_LPUART4_BAUD, .irq = IMXRT_IRQ_LPUART4, @@ -618,28 +1043,44 @@ static struct imxrt_uart_s g_uart4priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart4port = -{ - .recv = - { - .size = CONFIG_LPUART4_RXBUFSIZE, - .buffer = g_uart4rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART4_TXBUFSIZE, - .buffer = g_uart4txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart4priv, +#ifdef CONFIG_LPUART4_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART4_TX, +#endif +#ifdef CONFIG_LPUART4_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART4_RX, + .rxfifo = g_lpuart4rxfifo, +#endif }; #endif #ifdef CONFIG_IMXRT_LPUART5 -static struct imxrt_uart_s g_uart5priv = +static struct imxrt_uart_s g_lpuart5priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART5_RXBUFSIZE, + .buffer = g_lpuart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART5_TXBUFSIZE, + .buffer = g_lpuart5txbuffer, + }, + #if defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART5_RXDMA) && !defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + .priv = &g_lpuart5priv, + }, + .uartbase = IMXRT_LPUART5_BASE, .baud = CONFIG_LPUART5_BAUD, .irq = IMXRT_IRQ_LPUART5, @@ -668,28 +1109,44 @@ static struct imxrt_uart_s g_uart5priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart5port = -{ - .recv = - { - .size = CONFIG_LPUART5_RXBUFSIZE, - .buffer = g_uart5rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART5_TXBUFSIZE, - .buffer = g_uart5txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart5priv, +#ifdef CONFIG_LPUART5_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART5_TX, +#endif +#ifdef CONFIG_LPUART5_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART5_RX, + .rxfifo = g_lpuart5rxfifo, +#endif }; #endif #ifdef CONFIG_IMXRT_LPUART6 -static struct imxrt_uart_s g_uart6priv = +static struct imxrt_uart_s g_lpuart6priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART6_RXBUFSIZE, + .buffer = g_lpuart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART6_TXBUFSIZE, + .buffer = g_lpuart6txbuffer, + }, + #if defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART6_RXDMA) && !defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + .priv = &g_lpuart6priv, + }, + .uartbase = IMXRT_LPUART6_BASE, .baud = CONFIG_LPUART6_BAUD, .irq = IMXRT_IRQ_LPUART6, @@ -718,28 +1175,44 @@ static struct imxrt_uart_s g_uart6priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart6port = -{ - .recv = - { - .size = CONFIG_LPUART6_RXBUFSIZE, - .buffer = g_uart6rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART6_TXBUFSIZE, - .buffer = g_uart6txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart6priv, +#ifdef CONFIG_LPUART6_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART6_TX, +#endif +#ifdef CONFIG_LPUART6_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART6_RX, + .rxfifo = g_lpuart6rxfifo, +#endif }; #endif #ifdef CONFIG_IMXRT_LPUART7 -static struct imxrt_uart_s g_uart7priv = +static struct imxrt_uart_s g_lpuart7priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART7_RXBUFSIZE, + .buffer = g_lpuart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART7_TXBUFSIZE, + .buffer = g_lpuart7txbuffer, + }, + #if defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART7_RXDMA) && !defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + .priv = &g_lpuart7priv, + }, + .uartbase = IMXRT_LPUART7_BASE, .baud = CONFIG_LPUART7_BAUD, .irq = IMXRT_IRQ_LPUART7, @@ -768,28 +1241,44 @@ static struct imxrt_uart_s g_uart7priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart7port = -{ - .recv = - { - .size = CONFIG_LPUART7_RXBUFSIZE, - .buffer = g_uart7rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART7_TXBUFSIZE, - .buffer = g_uart7txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart7priv, +#ifdef CONFIG_LPUART7_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART7_TX, +#endif +#ifdef CONFIG_LPUART7_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART7_RX, + .rxfifo = g_lpuart7rxfifo, +#endif }; #endif #ifdef CONFIG_IMXRT_LPUART8 -static struct imxrt_uart_s g_uart8priv = +static struct imxrt_uart_s g_lpuart8priv = { + .dev = + { + .recv = + { + .size = CONFIG_LPUART8_RXBUFSIZE, + .buffer = g_lpuart8rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART8_TXBUFSIZE, + .buffer = g_lpuart8txbuffer, + }, + #if defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART8_RXDMA) && !defined(CONFIG_LPUART8_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + .priv = &g_lpuart8priv, + }, + .uartbase = IMXRT_LPUART8_BASE, .baud = CONFIG_LPUART8_BAUD, .irq = IMXRT_IRQ_LPUART8, @@ -818,22 +1307,14 @@ static struct imxrt_uart_s g_uart8priv = #if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL) .rs485mode = 1, #endif -}; -static struct uart_dev_s g_uart8port = -{ - .recv = - { - .size = CONFIG_LPUART8_RXBUFSIZE, - .buffer = g_uart8rxbuffer, - }, - .xmit = - { - .size = CONFIG_LPUART8_TXBUFSIZE, - .buffer = g_uart8txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart8priv, +#ifdef CONFIG_LPUART8_TXDMA + .dma_txreqsrc = IMXRT_DMACHAN_LPUART8_TX, +#endif +#ifdef CONFIG_LPUART8_RXDMA + .dma_rxreqsrc = IMXRT_DMACHAN_LPUART8_RX, + .rxfifo = g_lpuart8rxfifo, +#endif }; #endif @@ -869,6 +1350,24 @@ static inline void imxrt_serialout(struct imxrt_uart_s *priv, putreg32(value, priv->uartbase + offset); } +/**************************************************************************** + * Name: imxrt_dma_nextrx + * + * Description: + * Returns the index into the RX FIFO where the DMA will place the next + * byte that it receives. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int imxrt_dma_nextrx(struct imxrt_uart_s *priv) +{ + int dmaresidual = imxrt_dmach_getcount(priv->rxdma); + + return RXDMA_BUFFER_SIZE - dmaresidual; +} +#endif + /**************************************************************************** * Name: imxrt_disableuartint ****************************************************************************/ @@ -916,6 +1415,132 @@ static inline void imxrt_restoreuartint(struct imxrt_uart_s *priv, spin_unlock_irqrestore(NULL, flags); } +/**************************************************************************** + * Name: imxrt_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 imxrt_dma_setup(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; +#if defined(SERIAL_HAVE_RXDMA) + struct imxrt_edma_xfrconfig_s config; +#endif + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = imxrt_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 = imxrt_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 + IMXRT_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 = imxrt_dmach_alloc(priv->dma_rxreqsrc | + DMAMUX_CHCFG_ENBL, 0); + + if (priv->rxdma == NULL) + { + return -EBUSY; + } + } + else + { + imxrt_dmach_stop(priv->rxdma); + } + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + IMXRT_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 + + imxrt_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 + IMXRT_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_RDMAE); + + /* Enable itnerrupt on Idel and erros */ + + modifyreg32(priv->uartbase + IMXRT_LPUART_CTRL_OFFSET, 0, + LPUART_CTRL_PEIE | + LPUART_CTRL_FEIE | + LPUART_CTRL_NEIE | + LPUART_CTRL_ILIE); + + /* 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. + */ + + imxrt_dmach_start(priv->rxdma, imxrt_dma_rxcallback, (void *)priv); + } +#endif + + return OK; +} +#endif + /**************************************************************************** * Name: imxrt_setup * @@ -928,7 +1553,7 @@ static inline void imxrt_restoreuartint(struct imxrt_uart_s *priv, static int imxrt_setup(struct uart_dev_s *dev) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; #ifndef CONFIG_SUPPRESS_LPUART_CONFIG int ret; struct uart_config_s config = @@ -946,7 +1571,13 @@ static int imxrt_setup(struct uart_dev_s *dev) config.usects = priv->iflow; /* Flow control on inbound side */ #endif #ifdef CONFIG_SERIAL_OFLOWCONTROL - config.userts = priv->oflow; /* Flow control on outbound side */ + /* Flow control on outbound side if not GPIO based */ + + if ((priv->rts_gpio & GPIO_MODE_MASK) == GPIO_PERIPH) + { + config.userts = priv->oflow; + } + #endif #ifdef CONFIG_SERIAL_RS485CONTROL config.users485 = priv->rs485mode; /* Switch into RS485 mode */ @@ -979,13 +1610,62 @@ static int imxrt_setup(struct uart_dev_s *dev) static void imxrt_shutdown(struct uart_dev_s *dev) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; /* Disable the UART */ imxrt_serialout(priv, IMXRT_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST); } +/**************************************************************************** + * Name: imxrt_dma_shutdown + * + * Description: + * Disable the LPUART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static void imxrt_dma_shutdown(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; + + /* Perform the normal UART shutdown */ + + imxrt_shutdown(dev); + +#if defined(SERIAL_HAVE_RXDMA) + /* Stop the RX DMA channel */ + + if (priv->dma_rxreqsrc != 0) + { + imxrt_dmach_stop(priv->rxdma); + + /* Release the RX DMA channel */ + + imxrt_dmach_free(priv->rxdma); + priv->rxdma = NULL; + } +#endif + +#if defined(SERIAL_HAVE_TXDMA) + /* Stop the TX DMA channel */ + + if (priv->dma_txreqsrc != 0) + { + imxrt_dmach_stop(priv->txdma); + + /* Release the TX DMA channel */ + + imxrt_dmach_free(priv->txdma); + priv->txdma = NULL; + nxsem_destroy(&priv->txdmasem); + } +#endif +} +#endif + /**************************************************************************** * Name: imxrt_attach * @@ -1004,7 +1684,7 @@ static void imxrt_shutdown(struct uart_dev_s *dev) static int imxrt_attach(struct uart_dev_s *dev) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; int ret; /* Attach and enable the IRQ */ @@ -1034,7 +1714,7 @@ static int imxrt_attach(struct uart_dev_s *dev) static void imxrt_detach(struct uart_dev_s *dev) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; up_disable_irq(priv->irq); irq_detach(priv->irq); @@ -1052,14 +1732,12 @@ static void imxrt_detach(struct uart_dev_s *dev) static int imxrt_interrupt(int irq, void *context, void *arg) { - struct uart_dev_s *dev = (struct uart_dev_s *)arg; - struct imxrt_uart_s *priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)arg; uint32_t usr; int passes = 0; bool handled; - DEBUGASSERT(dev != NULL && dev->priv != NULL); - priv = (struct imxrt_uart_s *)dev->priv; + DEBUGASSERT(priv != NULL); #if defined(CONFIG_PM) && CONFIG_IMXRT_PM_SERIAL_ACTIVITY > 0 /* Report serial activity to the power management logic */ @@ -1082,26 +1760,54 @@ static int imxrt_interrupt(int irq, void *context, void *arg) usr = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR | - LPUART_STAT_FE); + LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF | + LPUART_STAT_IDLE); - /* Clear serial overrun and framing errors */ + /* Clear serial overrun, parity and framing errors */ if ((usr & LPUART_STAT_OR) != 0) { imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_OR); } + if ((usr & LPUART_STAT_PF) != 0) + { + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_NF); + } + + if ((usr & LPUART_STAT_PF) != 0) + { + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_PF); + } + if ((usr & LPUART_STAT_FE) != 0) { imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_FE); } + if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0) + { + /* Discard data */ + + imxrt_serialin(priv, IMXRT_LPUART_DATA_OFFSET); + } + +#ifdef SERIAL_HAVE_RXDMA + /* The line going to idle, deliver any fractions of RX data */ + + if ((usr & LPUART_STAT_IDLE) != 0) + { + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_IDLE); + imxrt_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE); + } +#endif + /* Handle incoming, receive bytes */ if ((usr & LPUART_STAT_RDRF) != 0 && (priv->ie & LPUART_CTRL_RIE) != 0) { - uart_recvchars(dev); + uart_recvchars(&priv->dev); handled = true; } @@ -1110,7 +1816,7 @@ static int imxrt_interrupt(int irq, void *context, void *arg) if ((usr & LPUART_STAT_TDRE) != 0 && (priv->ie & LPUART_CTRL_TIE) != 0) { - uart_xmitchars(dev); + uart_xmitchars(&priv->dev); handled = true; } } @@ -1157,7 +1863,7 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) case TCGETS: { struct termios *termiosp = (struct termios *)arg; - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; if (!termiosp) { @@ -1219,7 +1925,7 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) case TCSETS: { struct termios *termiosp = (struct termios *)arg; - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; uint32_t baud; uint32_t ie; uint8_t parity; @@ -1311,7 +2017,7 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) flags = spin_lock_irqsave(NULL); imxrt_disableuartint(priv, &ie); - ret = imxrt_setup(dev); + ret = dev->ops->setup(dev); /* Restore the interrupt state */ @@ -1328,7 +2034,7 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) { uint32_t regval; irqstate_t flags; - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; flags = spin_lock_irqsave(NULL); regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); @@ -1368,7 +2074,7 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) uint32_t stat; uint32_t regval; irqstate_t flags; - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; flags = spin_lock_irqsave(NULL); ctrl = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); @@ -1431,15 +2137,17 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) * ****************************************************************************/ +#ifndef SERIAL_HAVE_ONLY_RXDMA static int imxrt_receive(struct uart_dev_s *dev, unsigned int *status) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; uint32_t rxd; rxd = imxrt_serialin(priv, IMXRT_LPUART_DATA_OFFSET); *status = rxd >> LPUART_DATA_STATUS_SHIFT; return (rxd & LPUART_DATA_MASK) >> LPUART_DATA_SHIFT; } +#endif /**************************************************************************** * Name: imxrt_rxint @@ -1449,9 +2157,10 @@ static int imxrt_receive(struct uart_dev_s *dev, unsigned int *status) * ****************************************************************************/ +#ifndef SERIAL_HAVE_ONLY_RXDMA static void imxrt_rxint(struct uart_dev_s *dev, bool enable) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; irqstate_t flags; uint32_t regval; @@ -1475,6 +2184,7 @@ static void imxrt_rxint(struct uart_dev_s *dev, bool enable) imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); spin_unlock_irqrestore(NULL, flags); } +#endif /**************************************************************************** * Name: imxrt_rxavailable @@ -1484,9 +2194,10 @@ static void imxrt_rxint(struct uart_dev_s *dev, bool enable) * ****************************************************************************/ +#ifndef SERIAL_HAVE_ONLY_RXDMA static bool imxrt_rxavailable(struct uart_dev_s *dev) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; uint32_t regval; /* Return true is data is ready in the Rx FIFO */ @@ -1494,6 +2205,369 @@ static bool imxrt_rxavailable(struct uart_dev_s *dev) regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); return ((regval & LPUART_STAT_RDRF) != 0); } +#endif + +/**************************************************************************** + * Name: imxrt_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 imxrt_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; + bool use_swhs = false; + +#if defined(CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS) + use_swhs = (priv->rts_gpio & GPIO_MODE_MASK) == GPIO_OUTPUT; +#endif + + if (use_swhs && priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + imxrt_gpio_write(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: imxrt_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 imxrt_dma_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; + uint32_t nextrx = imxrt_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 imxrt_dma_rxavailable prior to calling this function to + * assure that this never happens. + */ + + return c; +} +#endif + +/**************************************************************************** + * Name: imxrt_dma_reenable + * + * Description: + * Call to re-enable RX DMA. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) +static void imxrt_dma_reenable(struct imxrt_uart_s *priv) +{ + struct imxrt_edma_xfrconfig_s config; + + /* Stop an reset the RX DMA */ + + imxrt_dmach_stop(priv->rxdma); + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + IMXRT_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 + + imxrt_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. + */ + + imxrt_dmach_start(priv->rxdma, imxrt_dma_rxcallback, (void *)priv); + + /* Clear DMA suspended flag. */ + + priv->rxdmasusp = false; +} +#endif + +/**************************************************************************** + * Name: imxrt_dma_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void imxrt_dma_rxint(struct uart_dev_s *dev, bool enable) +{ + struct imxrt_uart_s *priv = (struct imxrt_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: imxrt_dma_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static bool imxrt_dma_rxavailable(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_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 (imxrt_dma_nextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: imxrt_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 imxrt_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imxrt_uart_s *priv = (struct imxrt_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: imxrt_dma_txavailable + * + * Description: + * Informs DMA that Tx data is available and is ready for transfer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void imxrt_dma_txavailable(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; + + /* Only send when the DMA is idle */ + + nxsem_wait(&priv->txdmasem); + + uart_xmitchars_dma(dev); +} +#endif + +/**************************************************************************** + * Name: imxrt_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 imxrt_dma_send(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; + struct imxrt_edma_xfrconfig_s config; + + /* We need to stop DMA before reconfiguration */ + + imxrt_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 + IMXRT_LPUART_DATA_OFFSET; + config.soff = sizeof(dev->dmatx.buffer[0]); + config.doff = 0; +#ifdef CONFIG_IMXRT_EDMA_ELINK + 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 */ + + imxrt_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; + + /* 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); + + imxrt_dmach_xfrsetup(priv->txdma, &config); + } + + /* Start transmission with the callback on DMA completion */ + + imxrt_dmach_start(priv->txdma, imxrt_dma_txcallback, (void *)priv); +} +#endif /**************************************************************************** * Name: imxrt_send @@ -1505,10 +2579,32 @@ static bool imxrt_rxavailable(struct uart_dev_s *dev) static void imxrt_send(struct uart_dev_s *dev, int ch) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; imxrt_serialout(priv, IMXRT_LPUART_DATA_OFFSET, (uint32_t)ch); } +/**************************************************************************** + * Name: imxrt_dma_txint + * + * Description: + * Call to enable or disable TX interrupts from the UART. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void imxrt_dma_txint(struct uart_dev_s *dev, bool enable) +{ + /* Nothing to do. */ + + /* 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 imxrt_dma_txcallback() to handle stuff + * at half DMA transfer or after transfer completion (depending on the + * configuration). + */ +} +#endif + /**************************************************************************** * Name: imxrt_txint * @@ -1517,9 +2613,10 @@ static void imxrt_send(struct uart_dev_s *dev, int ch) * ****************************************************************************/ +#if !defined(SERIAL_HAVE_ONLY_TXDMA) static void imxrt_txint(struct uart_dev_s *dev, bool enable) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; irqstate_t flags; uint32_t regval; @@ -1543,6 +2640,7 @@ static void imxrt_txint(struct uart_dev_s *dev, bool enable) imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); spin_unlock_irqrestore(NULL, flags); } +#endif /**************************************************************************** * Name: imxrt_txready @@ -1554,7 +2652,7 @@ static void imxrt_txint(struct uart_dev_s *dev, bool enable) static bool imxrt_txready(struct uart_dev_s *dev) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; uint32_t regval; regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); @@ -1571,13 +2669,58 @@ static bool imxrt_txready(struct uart_dev_s *dev) static bool imxrt_txempty(struct uart_dev_s *dev) { - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev; uint32_t regval; regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); return ((regval & LPUART_STAT_TC) != 0); } +/**************************************************************************** + * Name: imxrt_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 imxrt_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)arg; + uint32_t sr; + + up_invalidate_dcache((uintptr_t)priv->rxfifo, + (uintptr_t)priv->rxfifo + RXDMA_BUFFER_SIZE); + + if (priv->rxenable && imxrt_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 = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); + + if ((sr & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE)) != 0) + { + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, + sr & (LPUART_STAT_OR | + LPUART_STAT_NF | + LPUART_STAT_FE)); + } +} +#endif + /**************************************************************************** * Name: up_pm_notify * @@ -1708,8 +2851,8 @@ void imxrt_earlyserialinit(void) */ #ifdef CONSOLE_DEV - CONSOLE_DEV.isconsole = true; - imxrt_setup(&CONSOLE_DEV); + CONSOLE_DEV.dev.isconsole = true; + imxrt_setup(&CONSOLE_DEV.dev); #endif } @@ -1735,32 +2878,35 @@ void arm_serialinit(void) #endif #ifdef CONSOLE_DEV - uart_register("/dev/console", &CONSOLE_DEV); + uart_register("/dev/console", &CONSOLE_DEV.dev); +#if defined(SERIAL_HAVE_CONSOLE_DMA) + imxrt_dma_setup(&CONSOLE_DEV.dev); +#endif #endif /* Register all UARTs */ - uart_register("/dev/ttyS0", &TTYS0_DEV); + uart_register("/dev/ttyS0", &TTYS0_DEV.dev); #ifdef TTYS1_DEV - uart_register("/dev/ttyS1", &TTYS1_DEV); + uart_register("/dev/ttyS1", &TTYS1_DEV.dev); #endif #ifdef TTYS2_DEV - uart_register("/dev/ttyS2", &TTYS2_DEV); + uart_register("/dev/ttyS2", &TTYS2_DEV.dev); #endif #ifdef TTYS3_DEV - uart_register("/dev/ttyS3", &TTYS3_DEV); + uart_register("/dev/ttyS3", &TTYS3_DEV.dev); #endif #ifdef TTYS4_DEV - uart_register("/dev/ttyS4", &TTYS4_DEV); + uart_register("/dev/ttyS4", &TTYS4_DEV.dev); #endif #ifdef TTYS5_DEV - uart_register("/dev/ttyS5", &TTYS5_DEV); + uart_register("/dev/ttyS5", &TTYS5_DEV.dev); #endif #ifdef TTYS6_DEV - uart_register("/dev/ttyS6", &TTYS6_DEV); + uart_register("/dev/ttyS6", &TTYS6_DEV.dev); #endif #ifdef TTYS7_DEV - uart_register("/dev/ttyS7", &TTYS7_DEV); + uart_register("/dev/ttyS7", &TTYS7_DEV.dev); #endif } @@ -1775,7 +2921,7 @@ void arm_serialinit(void) int up_putc(int ch) { #ifdef CONSOLE_DEV - struct imxrt_uart_s *priv = (struct imxrt_uart_s *)CONSOLE_DEV.priv; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)CONSOLE_DEV.dev.priv; uint32_t ie; imxrt_disableuartint(priv, &ie); diff --git a/arch/arm/src/imxrt/imxrt_serial.h b/arch/arm/src/imxrt/imxrt_serial.h index 102c5707023..7b608baafb0 100644 --- a/arch/arm/src/imxrt/imxrt_serial.h +++ b/arch/arm/src/imxrt/imxrt_serial.h @@ -34,6 +34,190 @@ * Pre-processor Definitions ****************************************************************************/ +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_IMXRT_LPUART1) || defined(CONFIG_IMXRT_LPUART2) || \ + defined(CONFIG_IMXRT_LPUART3) || defined(CONFIG_IMXRT_LPUART4) || \ + defined(CONFIG_IMXRT_LPUART5) || defined(CONFIG_IMXRT_LPUART6) || \ + defined(CONFIG_IMXRT_LPUART7) || defined(CONFIG_IMXRT_LPUART8) +# 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_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +# undef CONFIG_LPUART3_RXDMA +# undef CONFIG_LPUART3_TXDMA +# undef CONFIG_LPUART4_RXDMA +# undef CONFIG_LPUART4_TXDMA +# undef CONFIG_LPUART5_RXDMA +# undef CONFIG_LPUART5_TXDMA +# undef CONFIG_LPUART6_RXDMA +# undef CONFIG_LPUART6_TXDMA +# undef CONFIG_LPUART7_RXDMA +# undef CONFIG_LPUART7_TXDMA +# undef CONFIG_LPUART8_RXDMA +# undef CONFIG_LPUART8_TXDMA +#endif + +/* Disable the DMA configuration on all unused LPUARTs */ + +#ifndef CONFIG_IMXRT_LPUART1 +# undef CONFIG_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +#endif + +#ifndef CONFIG_IMXRT_LPUART2 +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +#endif + +#ifndef CONFIG_IMXRT_LPUART3 +# undef CONFIG_LPUART3_RXDMA +# undef CONFIG_LPUART3_TXDMA +#endif + +#ifndef CONFIG_IMXRT_LPUART4 +# undef CONFIG_LPUART4_RXDMA +# undef CONFIG_LPUART4_TXDMA +#endif + +#ifndef CONFIG_IMXRT_LPUART5 +# undef CONFIG_LPUART5_RXDMA +# undef CONFIG_LPUART5_TXDMA +#endif + +#ifndef CONFIG_IMXRT_LPUART6 +# undef CONFIG_LPUART6_RXDMA +# undef CONFIG_LPUART6_TXDMA +#endif + +#ifndef CONFIG_IMXRT_LPUART7 +# undef CONFIG_LPUART7_RXDMA +# undef CONFIG_LPUART7_TXDMA +#endif + +#ifndef CONFIG_IMXRT_LPUART8 +# undef CONFIG_LPUART8_RXDMA +# undef CONFIG_LPUART8_TXDMA +#endif + +/* Is RX DMA available on any (enabled) LPUART? */ + +#undef SERIAL_HAVE_RXDMA +#if defined(CONFIG_LPUART1_RXDMA) || defined(CONFIG_LPUART2_RXDMA) || \ + defined(CONFIG_LPUART3_RXDMA) || defined(CONFIG_LPUART4_RXDMA) || \ + defined(CONFIG_LPUART5_RXDMA) || defined(CONFIG_LPUART6_RXDMA) || \ + defined(CONFIG_LPUART7_RXDMA) || defined(CONFIG_LPUART8_RXDMA) +# define SERIAL_HAVE_RXDMA 1 +#endif + +/* Is TX DMA available on any (enabled) LPUART? */ +#undef SERIAL_HAVE_TXDMA +#if defined(CONFIG_LPUART1_TXDMA) || defined(CONFIG_LPUART2_TXDMA) || \ + defined(CONFIG_LPUART3_TXDMA) || defined(CONFIG_LPUART4_TXDMA) || \ + defined(CONFIG_LPUART5_TXDMA) || defined(CONFIG_LPUART6_TXDMA) || \ + defined(CONFIG_LPUART7_TXDMA) || defined(CONFIG_LPUART8_TXDMA) +# define SERIAL_HAVE_TXDMA 1 +#endif + +/* Is RX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_RXDMA 1 +#if defined(CONFIG_IMXRT_LPUART1) && !defined(CONFIG_LPUART1_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMXRT_LPUART2) && !defined(CONFIG_LPUART2_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMXRT_LPUART3) && !defined(CONFIG_LPUART3_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(CONFIG_LPUART4_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(CONFIG_LPUART5_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(CONFIG_LPUART6_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(CONFIG_LPUART7_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(CONFIG_LPUART8_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#endif + +/* Is TX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_TXDMA 1 +#if defined(CONFIG_IMXRT_LPUART1) && !defined(CONFIG_LPUART1_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMXRT_LPUART2) && !defined(CONFIG_LPUART2_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMXRT_LPUART3) && !defined(CONFIG_LPUART3_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(CONFIG_LPUART4_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(CONFIG_LPUART5_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(CONFIG_LPUART6_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(CONFIG_LPUART7_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(CONFIG_LPUART8_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_IMXRT_EDMA +# error IMXRT LPUART receive or transmit DMA requires CONFIG_IMXRT_EDMA +# endif +# endif + +#if defined(SERIAL_HAVE_RXDMA) +/* Currently RS-485 support cannot be enabled when RXDMA is in use due to + * lack of testing. + */ + +# if (defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_RS485)) || \ + (defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_RS485)) || \ + (defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_RS485)) || \ + (defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_RS485)) || \ + (defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_RS485)) || \ + (defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_RS485)) || \ + (defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_RS485)) || \ + (defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_RS485)) +# error "RXDMA and RS-485 cannot be enabled at the same time for the same LPUART" +# endif +#endif /* SERIAL_HAVE_RXDMA */ + +/* Currently RS-485 support cannot be enabled when TXDMA is in use due to + * lack of testing. + */ + +#if (defined(CONFIG_LPUART1_TXDMA) && defined(CONFIG_LPUART1_RS485)) || \ + (defined(CONFIG_LPUART2_TXDMA) && defined(CONFIG_LPUART2_RS485)) || \ + (defined(CONFIG_LPUART3_TXDMA) && defined(CONFIG_LPUART3_RS485)) || \ + (defined(CONFIG_LPUART4_TXDMA) && defined(CONFIG_LPUART4_RS485)) || \ + (defined(CONFIG_LPUART5_TXDMA) && defined(CONFIG_LPUART5_RS485)) || \ + (defined(CONFIG_LPUART6_TXDMA) && defined(CONFIG_LPUART6_RS485)) || \ + (defined(CONFIG_LPUART7_TXDMA) && defined(CONFIG_LPUART7_RS485)) || \ + (defined(CONFIG_LPUART8_TXDMA) && defined(CONFIG_LPUART8_RS485)) +# error "TXDMA and RS-485 cannot be enabled at the same time for the same LPUART" +#endif + /**************************************************************************** * Public Types ****************************************************************************/