diff --git a/arch/arm/src/imxrt/CMakeLists.txt b/arch/arm/src/imxrt/CMakeLists.txt index aeb4e487941..f16722d8def 100644 --- a/arch/arm/src/imxrt/CMakeLists.txt +++ b/arch/arm/src/imxrt/CMakeLists.txt @@ -96,7 +96,11 @@ if(CONFIG_BUILD_PROTECTED) endif() if(CONFIG_IMXRT_EDMA) - list(APPEND SRCS imxrt_edma.c) + if(CONFIG_IMXRT_EDMA_VER2) + list(APPEND SRCS imxrt_edma_ver2.c) + else() + list(APPEND SRCS imxrt_edma.c) + endif() endif() if(CONFIG_IMXRT_USDHC) diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index 072575db570..384e6affb6c 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -237,6 +237,7 @@ config ARCH_FAMILY_IMXRT118x select IMXRT_CLOCKCONFIG_VER3 select IMXRT_IOMUX_VER3 select IMXRT_RGPIO + select IMXRT_EDMA_VER2 ---help--- i.MX RT1180 dual-core Crossover Processors (Cortex-M33 + Cortex-M7). @@ -432,6 +433,13 @@ config IMXRT_RGPIO Selects the RGPIO driver (arch/arm/src/imxrt/imxrt_rgpio.c) that targets the RGPIO IP block used on RT118x. +config IMXRT_EDMA_VER2 + bool + default n + ---help--- + Selects the RT118x eDMA driver variant + (arch/arm/src/imxrt/imxrt_edma_ver2.c) used by RT118x. + config IMXRT_TRDC bool default n diff --git a/arch/arm/src/imxrt/Make.defs b/arch/arm/src/imxrt/Make.defs index 84d74cd4b23..67d7aff3a3f 100644 --- a/arch/arm/src/imxrt/Make.defs +++ b/arch/arm/src/imxrt/Make.defs @@ -92,8 +92,12 @@ CHIP_CSRCS += imxrt_userspace.c endif ifeq ($(CONFIG_IMXRT_EDMA),y) +ifeq ($(CONFIG_IMXRT_EDMA_VER2),y) +CHIP_CSRCS += imxrt_edma_ver2.c +else CHIP_CSRCS += imxrt_edma.c endif +endif ifdef CONFIG_IMXRT_USDHC CHIP_CSRCS += imxrt_usdhc.c diff --git a/arch/arm/src/imxrt/hardware/imxrt_dmamux.h b/arch/arm/src/imxrt/hardware/imxrt_dmamux.h index 70742bcd236..03b43b154b5 100644 --- a/arch/arm/src/imxrt/hardware/imxrt_dmamux.h +++ b/arch/arm/src/imxrt/hardware/imxrt_dmamux.h @@ -39,6 +39,8 @@ #elif defined(CONFIG_ARCH_FAMILY_IMXRT117x) # include "hardware/rt117x/imxrt117x_dmamux.h" #define IMXRT_DMAMUX_BASE IMXRT_DMAMUX0_BASE +#elif defined(CONFIG_ARCH_FAMILY_IMXRT118x) +# include "hardware/rt118x/imxrt118x_dmamux.h" #else # error Unrecognized i.MX RT architecture #endif diff --git a/arch/arm/src/imxrt/hardware/rt118x/imxrt118x_dmamux.h b/arch/arm/src/imxrt/hardware/rt118x/imxrt118x_dmamux.h new file mode 100644 index 00000000000..3dc5519ba40 --- /dev/null +++ b/arch/arm/src/imxrt/hardware/rt118x/imxrt118x_dmamux.h @@ -0,0 +1,329 @@ +/**************************************************************************** + * arch/arm/src/imxrt/hardware/rt118x/imxrt118x_dmamux.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_HARDWARE_RT118X_IMXRT118X_DMAMUX_H +#define __ARCH_ARM_SRC_IMXRT_HARDWARE_RT118X_IMXRT118X_DMAMUX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "hardware/imxrt_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* eDMA3/eDMA4 request source constants (IMXRT1180RM Ch. 5) */ + +#define IMXRT_DMA_ENGINE_EDMA3 (0) +#define IMXRT_DMA_ENGINE_EDMA4 (1) + +#define IMXRT_DMA_SRC_ENGINE_SHIFT (8) +#define IMXRT_DMA_SRC_ENGINE_MASK (0xff << IMXRT_DMA_SRC_ENGINE_SHIFT) +#define IMXRT_DMA_SRC_MUX_SHIFT (0) +#define IMXRT_DMA_SRC_MUX_MASK (0xff << IMXRT_DMA_SRC_MUX_SHIFT) +#define EDMA_MUX_MASK IMXRT_DMA_SRC_MUX_MASK + +#define IMXRT_DMA_SRC(_engine, _mux) \ + (((_engine) << IMXRT_DMA_SRC_ENGINE_SHIFT) | \ + ((_mux) << IMXRT_DMA_SRC_MUX_SHIFT)) + +#define IMXRT_DMA_SRC_ENGINE(_v) \ + (((_v) & IMXRT_DMA_SRC_ENGINE_MASK) >> IMXRT_DMA_SRC_ENGINE_SHIFT) +#define IMXRT_DMA_SRC_MUX(_v) \ + (((_v) & IMXRT_DMA_SRC_MUX_MASK) >> IMXRT_DMA_SRC_MUX_SHIFT) + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +static inline uintptr_t imxrt_dmamux_get_dmabase(uint16_t dmamux) +{ + return (IMXRT_DMA_SRC_ENGINE(dmamux) == IMXRT_DMA_ENGINE_EDMA3) ? + IMXRT_DMA3_BASE : IMXRT_DMA4_BASE; +} + +#endif /* __ASSEMBLY__ */ + +/* eDMA3 (AONMIX) request sources */ + +#define IMXRT_DMACHAN_CAN1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 1) +#define IMXRT_DMACHAN_GPIO1_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 3) +#define IMXRT_DMACHAN_GPIO1_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 4) +#define IMXRT_DMACHAN_I3_C1_TO_BUS_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 5) +#define IMXRT_DMACHAN_I3_C1_FROM_BUS_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 6) +#define IMXRT_DMACHAN_LPI2_C1_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 7) +#define IMXRT_DMACHAN_LPI2_C1_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 8) +#define IMXRT_DMACHAN_LPI2_C2_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 9) +#define IMXRT_DMACHAN_LPI2_C2_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 10) +#define IMXRT_DMACHAN_LPSPI1_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 11) +#define IMXRT_DMACHAN_LPSPI1_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 12) +#define IMXRT_DMACHAN_LPSPI2_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 13) +#define IMXRT_DMACHAN_LPSPI2_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 14) +#define IMXRT_DMACHAN_LPTMR1_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 15) +#define IMXRT_DMACHAN_LPUART1_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 16) +#define IMXRT_DMACHAN_LPUART1_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 17) +#define IMXRT_DMACHAN_LPUART2_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 18) +#define IMXRT_DMACHAN_LPUART2_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 19) +#define IMXRT_DMACHAN_EDGELOCK_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 20) +#define IMXRT_DMACHAN_SAI1_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 21) +#define IMXRT_DMACHAN_SAI1_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 22) +#define IMXRT_DMACHAN_TPM1_REQUEST0_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 23) +#define IMXRT_DMACHAN_TPM1_REQUEST1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 24) +#define IMXRT_DMACHAN_TPM1_OVERFLOW_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 25) +#define IMXRT_DMACHAN_TPM2_REQUEST0_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 26) +#define IMXRT_DMACHAN_TPM2_REQUEST1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 27) +#define IMXRT_DMACHAN_TPM2_OVERFLOW_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 28) +#define IMXRT_DMACHAN_LPUART7_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 29) +#define IMXRT_DMACHAN_LPUART7_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 30) +#define IMXRT_DMACHAN_FLEX_SPI2_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 33) +#define IMXRT_DMACHAN_FLEX_SPI2_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 34) +#define IMXRT_DMACHAN_CAN3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 38) +#define IMXRT_DMACHAN_LPUART12_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 31) +#define IMXRT_DMACHAN_LPUART12_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA3, 32) + +/* eDMA4 (WAKEUPMIX / MEGAMIX) request sources */ + +#define IMXRT_DMACHAN_GPIO2_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 2) +#define IMXRT_DMACHAN_GPIO2_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 3) +#define IMXRT_DMACHAN_GPIO3_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 4) +#define IMXRT_DMACHAN_GPIO3_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 5) +#define IMXRT_DMACHAN_I3_C2_TO_BUS_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 6) +#define IMXRT_DMACHAN_I3_C2_FROM_BUS_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 7) +#define IMXRT_DMACHAN_LPI2_C3_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 8) +#define IMXRT_DMACHAN_LPI2_C3_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 9) +#define IMXRT_DMACHAN_LPI2_C4_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 10) +#define IMXRT_DMACHAN_LPI2_C4_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 11) +#define IMXRT_DMACHAN_LPSPI3_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 12) +#define IMXRT_DMACHAN_LPSPI3_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 13) +#define IMXRT_DMACHAN_LPSPI4_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 14) +#define IMXRT_DMACHAN_LPSPI4_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 15) +#define IMXRT_DMACHAN_LPUART3_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 17) +#define IMXRT_DMACHAN_LPUART3_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 18) +#define IMXRT_DMACHAN_LPUART4_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 19) +#define IMXRT_DMACHAN_LPUART4_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 20) +#define IMXRT_DMACHAN_LPUART5_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 21) +#define IMXRT_DMACHAN_LPUART5_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 22) +#define IMXRT_DMACHAN_LPUART6_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 23) +#define IMXRT_DMACHAN_LPUART6_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 24) +#define IMXRT_DMACHAN_TPM3_REQUEST0_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 25) +#define IMXRT_DMACHAN_TPM3_REQUEST1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 26) +#define IMXRT_DMACHAN_TPM3_OVERFLOW_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 27) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 37) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 38) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 39) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 40) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST4 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 41) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST5 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 42) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST6 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 43) +#define IMXRT_DMACHAN_FLEX_IO1_REQUEST7 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 44) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 45) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 46) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 47) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 48) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST4 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 49) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST5 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 50) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST6 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 51) +#define IMXRT_DMACHAN_FLEX_IO2_REQUEST7 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 52) +#define IMXRT_DMACHAN_FLEX_SPI1_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 53) +#define IMXRT_DMACHAN_FLEX_SPI1_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 54) +#define IMXRT_DMACHAN_ADC1_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 57) +#define IMXRT_DMACHAN_FLEX_PWM3_CAPTURE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 74) +#define IMXRT_DMACHAN_FLEX_PWM3_CAPTURE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 75) +#define IMXRT_DMACHAN_FLEX_PWM3_CAPTURE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 76) +#define IMXRT_DMACHAN_FLEX_PWM3_CAPTURE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 77) +#define IMXRT_DMACHAN_FLEX_PWM3_VALUE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 78) +#define IMXRT_DMACHAN_FLEX_PWM3_VALUE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 79) +#define IMXRT_DMACHAN_FLEX_PWM3_VALUE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 80) +#define IMXRT_DMACHAN_FLEX_PWM3_VALUE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 81) +#define IMXRT_DMACHAN_FLEX_PWM4_CAPTURE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 82) +#define IMXRT_DMACHAN_FLEX_PWM4_CAPTURE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 83) +#define IMXRT_DMACHAN_FLEX_PWM4_CAPTURE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 84) +#define IMXRT_DMACHAN_FLEX_PWM4_CAPTURE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 85) +#define IMXRT_DMACHAN_FLEX_PWM4_VALUE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 86) +#define IMXRT_DMACHAN_FLEX_PWM4_VALUE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 87) +#define IMXRT_DMACHAN_FLEX_PWM4_VALUE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 88) +#define IMXRT_DMACHAN_FLEX_PWM4_VALUE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 89) +#define IMXRT_DMACHAN_QTIMER1_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 90) +#define IMXRT_DMACHAN_QTIMER1_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 91) +#define IMXRT_DMACHAN_QTIMER1_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 92) +#define IMXRT_DMACHAN_QTIMER1_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 93) +#define IMXRT_DMACHAN_QTIMER1_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 94) +#define IMXRT_DMACHAN_QTIMER1_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 95) +#define IMXRT_DMACHAN_QTIMER1_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 96) +#define IMXRT_DMACHAN_QTIMER1_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 97) +#define IMXRT_DMACHAN_QTIMER2_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 98) +#define IMXRT_DMACHAN_QTIMER2_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 99) +#define IMXRT_DMACHAN_QTIMER2_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 100) +#define IMXRT_DMACHAN_QTIMER2_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 101) +#define IMXRT_DMACHAN_QTIMER2_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 102) +#define IMXRT_DMACHAN_QTIMER2_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 103) +#define IMXRT_DMACHAN_QTIMER2_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 104) +#define IMXRT_DMACHAN_QTIMER2_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 105) +#define IMXRT_DMACHAN_QTIMER3_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 106) +#define IMXRT_DMACHAN_QTIMER3_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 107) +#define IMXRT_DMACHAN_QTIMER3_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 108) +#define IMXRT_DMACHAN_QTIMER3_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 109) +#define IMXRT_DMACHAN_QTIMER3_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 110) +#define IMXRT_DMACHAN_QTIMER3_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 111) +#define IMXRT_DMACHAN_QTIMER3_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 112) +#define IMXRT_DMACHAN_QTIMER3_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 113) +#define IMXRT_DMACHAN_QTIMER4_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 114) +#define IMXRT_DMACHAN_QTIMER4_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 115) +#define IMXRT_DMACHAN_QTIMER4_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 116) +#define IMXRT_DMACHAN_QTIMER4_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 117) +#define IMXRT_DMACHAN_QTIMER4_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 118) +#define IMXRT_DMACHAN_QTIMER4_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 119) +#define IMXRT_DMACHAN_QTIMER4_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 120) +#define IMXRT_DMACHAN_QTIMER4_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 121) +#define IMXRT_DMACHAN_XBAR1_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 154) +#define IMXRT_DMACHAN_XBAR1_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 155) +#define IMXRT_DMACHAN_XBAR1_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 156) +#define IMXRT_DMACHAN_XBAR1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 157) +#define IMXRT_DMACHAN_ADC2_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 158) +#define IMXRT_DMACHAN_EQDC1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 159) +#define IMXRT_DMACHAN_EQDC2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 160) +#define IMXRT_DMACHAN_EQDC3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 161) +#define IMXRT_DMACHAN_EQDC4 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 162) +#define IMXRT_DMACHAN_LPI2_C5_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 163) +#define IMXRT_DMACHAN_LPI2_C5_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 164) +#define IMXRT_DMACHAN_LPSPI5_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 167) +#define IMXRT_DMACHAN_LPSPI5_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 168) +#define IMXRT_DMACHAN_LPSPI6_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 169) +#define IMXRT_DMACHAN_LPSPI6_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 170) +#define IMXRT_DMACHAN_LPUART8_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 178) +#define IMXRT_DMACHAN_LPUART8_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 179) +#define IMXRT_DMACHAN_DAC IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 186) +#define IMXRT_DMACHAN_CMP3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 189) +#define IMXRT_DMACHAN_ASRC_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 191) +#define IMXRT_DMACHAN_ASRC_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 192) +#define IMXRT_DMACHAN_ASRC_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 193) +#define IMXRT_DMACHAN_ASRC_REQUEST4 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 194) +#define IMXRT_DMACHAN_ASRC_REQUEST5 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 195) +#define IMXRT_DMACHAN_ASRC_REQUEST6 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 196) +#define IMXRT_DMACHAN_SPDIF_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 197) +#define IMXRT_DMACHAN_SPDIF_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 198) +#define IMXRT_DMACHAN_PDM_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 199) +#define IMXRT_DMACHAN_GPIO4_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 200) +#define IMXRT_DMACHAN_GPIO4_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 201) +#define IMXRT_DMACHAN_GPIO5_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 202) +#define IMXRT_DMACHAN_GPIO5_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 203) +#define IMXRT_DMACHAN_GPIO6_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 204) +#define IMXRT_DMACHAN_GPIO6_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 205) +#define IMXRT_DMACHAN_SINC3_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 216) +#define IMXRT_DMACHAN_SINC3_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 217) +#define IMXRT_DMACHAN_SINC3_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 218) +#define IMXRT_DMACHAN_SINC3_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 219) +#define IMXRT_DMACHAN_ADC1_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 220) +#define IMXRT_DMACHAN_ADC2_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 221) +#define IMXRT_DMACHAN_LPTMR2_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 16) +#define IMXRT_DMACHAN_TPM4_REQUEST0_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 28) +#define IMXRT_DMACHAN_TPM4_REQUEST1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 29) +#define IMXRT_DMACHAN_TPM4_OVERFLOW_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 30) +#define IMXRT_DMACHAN_FLEX_PWM1_CAPTURE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 58) +#define IMXRT_DMACHAN_FLEX_PWM1_CAPTURE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 59) +#define IMXRT_DMACHAN_FLEX_PWM1_CAPTURE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 60) +#define IMXRT_DMACHAN_FLEX_PWM1_CAPTURE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 61) +#define IMXRT_DMACHAN_FLEX_PWM1_VALUE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 62) +#define IMXRT_DMACHAN_FLEX_PWM1_VALUE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 63) +#define IMXRT_DMACHAN_FLEX_PWM1_VALUE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 64) +#define IMXRT_DMACHAN_FLEX_PWM1_VALUE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 65) +#define IMXRT_DMACHAN_FLEX_PWM2_CAPTURE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 66) +#define IMXRT_DMACHAN_FLEX_PWM2_CAPTURE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 67) +#define IMXRT_DMACHAN_FLEX_PWM2_CAPTURE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 68) +#define IMXRT_DMACHAN_FLEX_PWM2_CAPTURE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 69) +#define IMXRT_DMACHAN_FLEX_PWM2_VALUE_SUB0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 70) +#define IMXRT_DMACHAN_FLEX_PWM2_VALUE_SUB1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 71) +#define IMXRT_DMACHAN_FLEX_PWM2_VALUE_SUB2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 72) +#define IMXRT_DMACHAN_FLEX_PWM2_VALUE_SUB3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 73) +#define IMXRT_DMACHAN_QTIMER5_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 122) +#define IMXRT_DMACHAN_QTIMER5_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 123) +#define IMXRT_DMACHAN_QTIMER5_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 124) +#define IMXRT_DMACHAN_QTIMER5_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 125) +#define IMXRT_DMACHAN_QTIMER5_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 126) +#define IMXRT_DMACHAN_QTIMER5_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 127) +#define IMXRT_DMACHAN_QTIMER5_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 128) +#define IMXRT_DMACHAN_QTIMER5_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 129) +#define IMXRT_DMACHAN_QTIMER6_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 130) +#define IMXRT_DMACHAN_QTIMER6_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 131) +#define IMXRT_DMACHAN_QTIMER6_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 132) +#define IMXRT_DMACHAN_QTIMER6_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 133) +#define IMXRT_DMACHAN_QTIMER6_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 134) +#define IMXRT_DMACHAN_QTIMER6_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 135) +#define IMXRT_DMACHAN_QTIMER6_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 136) +#define IMXRT_DMACHAN_QTIMER6_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 137) +#define IMXRT_DMACHAN_QTIMER7_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 138) +#define IMXRT_DMACHAN_QTIMER7_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 139) +#define IMXRT_DMACHAN_QTIMER7_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 140) +#define IMXRT_DMACHAN_QTIMER7_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 141) +#define IMXRT_DMACHAN_QTIMER7_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 142) +#define IMXRT_DMACHAN_QTIMER7_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 143) +#define IMXRT_DMACHAN_QTIMER7_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 144) +#define IMXRT_DMACHAN_QTIMER7_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 145) +#define IMXRT_DMACHAN_QTIMER8_CAPT_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 146) +#define IMXRT_DMACHAN_QTIMER8_CAPT_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 147) +#define IMXRT_DMACHAN_QTIMER8_CAPT_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 148) +#define IMXRT_DMACHAN_QTIMER8_CAPT_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 149) +#define IMXRT_DMACHAN_QTIMER8_CMPLD1_TIMER0_CMPLD2_TIMER1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 150) +#define IMXRT_DMACHAN_QTIMER8_CMPLD1_TIMER1_CMPLD2_TIMER0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 151) +#define IMXRT_DMACHAN_QTIMER8_CMPLD1_TIMER2_CMPLD2_TIMER3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 152) +#define IMXRT_DMACHAN_QTIMER8_CMPLD1_TIMER3_CMPLD2_TIMER2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 153) +#define IMXRT_DMACHAN_LPI2_C6_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 165) +#define IMXRT_DMACHAN_LPI2_C6_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 166) +#define IMXRT_DMACHAN_LPTMR3_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 171) +#define IMXRT_DMACHAN_SAI2_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 180) +#define IMXRT_DMACHAN_SAI2_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 181) +#define IMXRT_DMACHAN_SAI4_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 184) +#define IMXRT_DMACHAN_SAI4_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 185) +#define IMXRT_DMACHAN_SINC1_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 208) +#define IMXRT_DMACHAN_SINC1_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 209) +#define IMXRT_DMACHAN_SINC1_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 210) +#define IMXRT_DMACHAN_SINC1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 211) +#define IMXRT_DMACHAN_SINC2_REQUEST0 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 212) +#define IMXRT_DMACHAN_SINC2_REQUEST1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 213) +#define IMXRT_DMACHAN_SINC2_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 214) +#define IMXRT_DMACHAN_SINC2_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 215) +#define IMXRT_DMACHAN_CAN2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 1) +#define IMXRT_DMACHAN_TPM5_REQUEST0_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 31) +#define IMXRT_DMACHAN_TPM5_REQUEST1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 32) +#define IMXRT_DMACHAN_TPM5_OVERFLOW_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 33) +#define IMXRT_DMACHAN_TPM6_REQUEST0_REQUEST2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 34) +#define IMXRT_DMACHAN_TPM6_REQUEST1_REQUEST3 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 35) +#define IMXRT_DMACHAN_TPM6_OVERFLOW_REQUEST IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 36) +#define IMXRT_DMACHAN_LPUART9_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 172) +#define IMXRT_DMACHAN_LPUART9_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 173) +#define IMXRT_DMACHAN_LPUART10_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 174) +#define IMXRT_DMACHAN_LPUART10_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 175) +#define IMXRT_DMACHAN_LPUART11_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 176) +#define IMXRT_DMACHAN_LPUART11_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 177) +#define IMXRT_DMACHAN_SAI3_TX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 182) +#define IMXRT_DMACHAN_SAI3_RX IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 183) +#define IMXRT_DMACHAN_CMP1 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 187) +#define IMXRT_DMACHAN_CMP2 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 188) +#define IMXRT_DMACHAN_CMP4 IMXRT_DMA_SRC(IMXRT_DMA_ENGINE_EDMA4, 190) + +#endif /* __ARCH_ARM_SRC_IMXRT_HARDWARE_RT118X_IMXRT118X_DMAMUX_H */ diff --git a/arch/arm/src/imxrt/hardware/rt118x/imxrt118x_edma.h b/arch/arm/src/imxrt/hardware/rt118x/imxrt118x_edma.h new file mode 100644 index 00000000000..32b94afb8e0 --- /dev/null +++ b/arch/arm/src/imxrt/hardware/rt118x/imxrt118x_edma.h @@ -0,0 +1,444 @@ +/**************************************************************************** + * arch/arm/src/imxrt/hardware/rt118x/imxrt118x_edma.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_HARDWARE_RT118X_IMXRT118X_EDMA_H +#define __ARCH_ARM_SRC_IMXRT_HARDWARE_RT118X_IMXRT118X_EDMA_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "hardware/imxrt_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define EDMA_CONFIG_SWSTART (1 << 6) /* Start by software trigger */ + +/* eDMA3 / eDMA4 Register Offsets */ + +#define IMXRT_EDMA_CSR_OFFSET (0x000000) /* Management Page Control Register (CSR) */ +#define IMXRT_EDMA_ES_OFFSET (0x000004) /* Management Page Error Status Register (ES) */ +#define IMXRT_EDMA_CH_GRPRI_OFFSET(n) (0x000100 + ((n) << 2)) /* Channel n Arbitration Group Register (CHn_GRPRI) */ + +/* eDMA3 only */ + +#define IMXRT_EDMA_INT_OFFSET (0x000008) /* Management Page Interrupt Request Status Register (INT) */ +#define IMXRT_EDMA_HRS_OFFSET (0x00000c) /* Management Page Hardware Request Status Register (HRS) */ + +/* eDMA4 only */ + +#define IMXRT_EDMA_INT_LOW_OFFSET (0x000008) /* Management Page Interrupt Request Status Register (INT_LOW) */ +#define IMXRT_EDMA_INT_HIGH_OFFSET (0x00000c) /* Management Page Interrupt Request Status Register (INT_HIGH) */ +#define IMXRT_EDMA_HRS_LOW_OFFSET (0x000010) /* Management Page Hardware Request Status Register (HRS_LOW) */ +#define IMXRT_EDMA_HRS_HIGH_OFFSET (0x000014) /* Management Page Hardware Request Status Register (HRS_HIGH) */ + +/* eDMA3 / eDMA4 Register Addresses */ + +#define IMXRT_EDMA_CSR(n) ((n) + IMXRT_EDMA_CSR_OFFSET) +#define IMXRT_EDMA_ES(n) ((n) + IMXRT_EDMA_ES_OFFSET) +#define IMXRT_EDMA_CH_GRPRI(n,c) ((n) + IMXRT_EDMA_CH_GRPRI_OFFSET(c)) + +/* eDMA3 only */ + +#define IMXRT_EDMA_INT (IMXRT_DMA3_BASE + IMXRT_EDMA_INT_OFFSET) +#define IMXRT_EDMA_HRS (IMXRT_DMA3_BASE + IMXRT_EDMA_HRS_OFFSET) + +/* eDMA4 only */ + +#define IMXRT_EDMA_INT_LOW (IMXRT_DMA4_BASE + IMXRT_EDMA_INT_LOW_OFFSET) +#define IMXRT_EDMA_INT_HIGH (IMXRT_DMA4_BASE + IMXRT_EDMA_INT_HIGH_OFFSET) +#define IMXRT_EDMA_HRS_LOW (IMXRT_DMA4_BASE + IMXRT_EDMA_HRS_LOW_OFFSET) +#define IMXRT_EDMA_HRS_HIGH (IMXRT_DMA4_BASE + IMXRT_EDMA_HRS_HIGH_OFFSET) + +/* eDMA Transfer Control Descriptor (TCD) Register Offsets */ + +#define IMXRT_EDMA_CH_CSR_OFFSET (0x000000) /* Channel Control and Status Register (CH0_CSR) */ +#define IMXRT_EDMA_CH_ES_OFFSET (0x000004) /* Channel Error Status Register (CH0_ES) */ +#define IMXRT_EDMA_CH_INT_OFFSET (0x000008) /* Channel Interrupt Status Register (CH0_INT) */ +#define IMXRT_EDMA_CH_SBR_OFFSET (0x00000c) /* Channel System Bus Register (CH0_SBR) */ +#define IMXRT_EDMA_CH_PRI_OFFSET (0x000010) /* Channel Priority Register (CH0_PRI) */ +#define IMXRT_EDMA_CH_MUX_OFFSET (0x000014) /* Channel Multiplexor Configuration (CH0_MUX) (eDMA4 only) */ +#define IMXRT_EDMA_CH_MATTR_OFFSET (0x000018) /* Memory Attributes Register (CH0_MATTR) (eDMA4 only) */ +#define IMXRT_EDMA_TCD_SADDR_OFFSET (0x000020) /* TCD Source Address Register (TCD0_SADDR) */ +#define IMXRT_EDMA_TCD_SOFF_OFFSET (0x000024) /* TCD Signed Source Address Offset Register (TCD0_SOFF) */ +#define IMXRT_EDMA_TCD_ATTR_OFFSET (0x000026) /* TCD Transfer Attributes (TCD0_ATTR) */ +#define IMXRT_EDMA_TCD_NBYTES_OFFSET (0x000028) /* TCD Transfer Size (TCD0_NBYTES) */ +#define IMXRT_EDMA_TCD_SLAST_SDA_OFFSET (0x00002c) /* TCD Last Source Address Adjustment / Store DADDR Address Register (TCD0_SLAST_SDA) */ +#define IMXRT_EDMA_TCD_DADDR_OFFSET (0x000030) /* TCD Destination Address Register (TCD0_DADDR) */ +#define IMXRT_EDMA_TCD_DOFF_OFFSET (0x000034) /* TCD Signed Destination Address Offset Register (TCD0_DOFF) */ +#define IMXRT_EDMA_TCD_CITER_OFFSET (0x000036) /* TCD Current Major Loop Count Register (TCD0_CITER) */ +#define IMXRT_EDMA_TCD_DLAST_SGA_OFFSET (0x000038) /* TCD Last Destination Address Adjustment / Scatter Gather Address Register (TCD0_DLAST_SGA)*/ +#define IMXRT_EDMA_TCD_CSR_OFFSET (0x00003c) /* TCD Control and Status Register (TCD0_CSR) */ +#define IMXRT_EDMA_TCD_BITER_OFFSET (0x00003e) /* TCD Beginning Major Loop Count Register (TCD0_BITER) */ + +/* eDMA 3 and eDMA 4 have TCD instance offsets, but same base offset */ + +#define IMXRT_EDMA_TCD_BASE_OFFSET (0x10000) /* Offset to TCD for both eDMA3/4 */ +#define IMXRT_EDMA3_TCD_INST_OFFSET (0x10000) /* Per instance TCD offset for eDMA3 */ +#define IMXRT_EDMA4_TCD_INST_OFFSET (0x8000) /* Per instance TCD offset for eDMA4 */ +#define IMXRT_EDMA_TCD_BASE(n) ((n) + IMXRT_EDMA_TCD_BASE_OFFSET) +#define IMXRT_EDMA_TCD_INST_OFFSET(n) ((n) == IMXRT_DMA3_BASE ? IMXRT_EDMA3_TCD_INST_OFFSET : IMXRT_EDMA4_TCD_INST_OFFSET) +#define IMXRT_EDMA_TCD(n,t) (IMXRT_EDMA_TCD_BASE(n) + (t) * IMXRT_EDMA_TCD_INST_OFFSET(n)) + +/* eDMA Transfer Control Descriptor (TCD) Register Addresses ****************/ + +#define IMXRT_EDMA_CH_CSR(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_CH_CSR_OFFSET) +#define IMXRT_EDMA_CH_ES(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_CH_ES_OFFSET) +#define IMXRT_EDMA_CH_INT(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_CH_INT_OFFSET) +#define IMXRT_EDMA_CH_SBR(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_CH_SBR_OFFSET) +#define IMXRT_EDMA_CH_PRI(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_CH_PRI_OFFSET) +#define IMXRT_EDMA_CH_MUX(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_CH_MUX_OFFSET) +#define IMXRT_EDMA_TCD_SADDR(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_SADDR_OFFSET) +#define IMXRT_EDMA_TCD_SOFF(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_SOFF_OFFSET) +#define IMXRT_EDMA_TCD_ATTR(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_ATTR_OFFSET) +#define IMXRT_EDMA_TCD_NBYTES(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_NBYTES_OFFSET) +#define IMXRT_EDMA_TCD_SLAST_SDA(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_SLAST_SDA_OFFSET) +#define IMXRT_EDMA_TCD_DADDR(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_DADDR_OFFSET) +#define IMXRT_EDMA_TCD_DOFF(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_DOFF_OFFSET) +#define IMXRT_EDMA_TCD_CITER(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_CITER_OFFSET) +#define IMXRT_EDMA_TCD_DLAST_SGA(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_DLAST_SGA_OFFSET) +#define IMXRT_EDMA_TCD_CSR(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_CSR_OFFSET) +#define IMXRT_EDMA_TCD_BITER(n,t) (IMXRT_EDMA_TCD(n,t) + IMXRT_EDMA_TCD_BITER_OFFSET) + +/* eDMA Register Bitfield Definitions ***************************************/ + +/* Management Page Control Register (CSR) */ + + /* Bit 0: Reserved */ +#define EDMA_CSR_EDBG (1 << 1) /* Bit 1: Enable Debug (EDBG) */ +#define EDMA_CSR_ERCA (1 << 2) /* Bit 2: Enable Round Robin Channel Arbitration (ERCA) */ + /* Bit 3: Reserved */ +#define EDMA_CSR_HAE (1 << 4) /* Bit 4: Halt After Error (HAE) */ +#define EDMA_CSR_HALT (1 << 5) /* Bit 5: Halt DMA Operations (HALT) */ +#define EDMA_CSR_GCLC (1 << 6) /* Bit 6: Global Channel Linking Control (GCLC) */ +#define EDMA_CSR_GMRC (1 << 7) /* Bit 7: Global Master ID Replication Control (GMRC) */ +#define EDMA_CSR_ECX (1 << 8) /* Bit 8: Cancel Transfer With Error (ECX) */ +#define EDMA_CSR_CX (1 << 9) /* Bit 9: Cancel Transfer (CX) */ + /* Bits 10-23: Reserved */ +#define EDMA_CSR_ACTIVE_ID_SHIFT (24) /* Bits 24-28: Active Channel ID (ACTIVE_ID) */ +#define EDMA_CSR_ACTIVE_ID_MASK (0x1f << EDMA_CSR_ACTIVE_ID_SHIFT) + /* Bits 29-30: Reserved */ +#define EDMA_CSR_ACTIVE (1 << 31) /* Bit 31: DMA Active Status (ACTIVE) */ + +/* Management Page Error Status Register (ES) */ + +#define EDMA_ES_DBE (1 << 0) /* Bit 0: Destination Bus Error (DBE) */ +#define EDMA_ES_SBE (1 << 1) /* Bit 1: Source Bus Error (SBE) */ +#define EDMA_ES_SGE (1 << 2) /* Bit 2: Scatter/Gather Configuration Error (SGE) */ +#define EDMA_ES_NCE (1 << 3) /* Bit 3: NBYTES/CITER Configuration Error (NCE) */ +#define EDMA_ES_DOE (1 << 4) /* Bit 4: Destination Offset Error (DOE) */ +#define EDMA_ES_DAE (1 << 5) /* Bit 5: Destination Address Error (DAE) */ +#define EDMA_ES_SOE (1 << 6) /* Bit 6: Source Offset Error (SOE) */ +#define EDMA_ES_SAE (1 << 7) /* Bit 7: Source Address Error (SAE) */ +#define EDMA_ES_ECX (1 << 8) /* Bit 8: Transfer Canceled (ECX) */ + /* Bits 9-23: Reserved */ +#define EDMA_ES_ERRCHN_SHIFT (24) /* Bits 24-28: Error Channel Number or Canceled Channel Number (ERRCHN) */ +#define EDMA_ES_ERRCHN_MASK (0x1f << EDMA_ES_ERRCHN_SHIFT) + /* Bits 29-30: Reserved */ +#define EDMA_ES_VLD (1 << 31) /* Bit 31: Logical OR of all ERR status fields (VALID) */ + +/* Management Page Interrupt Request Status Register (INT) */ + +#define EDMA_INT(n) (1 << (n)) /* Bit n: Interrupt Request Status (INT) */ + +/* Management Page Hardware Request Status Register (HRS) */ + +#define EDMA_HRS(n) (1 << (n)) /* Bit n: Hardware Request Status (HRS) */ + +/* Channel n Arbitration Group Register (CHn_GRPRI) */ + +#define EDMA_CH_GRPRI_SHIFT (0) /* Bits 0-4: Arbitration Group For Channel n (GRPRI) */ +#define EDMA_CH_GRPRI_MASK (0x1f << EDMA_CH_GRPRI_SHIFT) + /* Bits 5-31: Reserved */ + +/* eDMA Transfer Control Descriptor (TCD) Bitfield Definitions **************/ + +/* Channel n Control and Status Register (CHn_CSR) */ + +#define EDMA_CH_CSR_ERQ (1 << 0) /* Bit 0: Enable DMA Request (ERQ) */ +#define EDMA_CH_CSR_EARQ (1 << 1) /* Bit 1: Enable Asynchronous DMA Request in Stop Mode for Channel (EARQ) */ +#define EDMA_CH_CSR_EEI (1 << 2) /* Bit 2: Enable Error Interrupt (EEI) */ +#define EDMA_CH_CSR_EBW (1 << 3) /* Bit 3: Enable Buffered Writes (EBW) */ + /* Bit 4-29: Reserved */ +#define EDMA_CH_CSR_DONE (1 << 30) /* Bit 30: Channel Done (DONE) */ +#define EDMA_CH_CSR_ACTIVE (1 << 31) /* Bit 31: CHannel Active (ACTIVE) */ + +/* Channel n Error Status Register (CHn_ES) */ + +#define EDMA_CH_ES_DBE (1 << 0) /* Bit 0: Destination Bus Error (DBE) */ +#define EDMA_CH_ES_SBE (1 << 1) /* Bit 1: Source Bus Error (SBE) */ +#define EDMA_CH_ES_SGE (1 << 2) /* Bit 2: Scatter/Gather Configuration Error (SGE) */ +#define EDMA_CH_ES_NCE (1 << 3) /* Bit 3: NBYTES/CITER Configuration Error (NCE) */ +#define EDMA_CH_ES_DOE (1 << 4) /* Bit 4: Destination Offset Error (DOE) */ +#define EDMA_CH_ES_DAE (1 << 5) /* Bit 5: Destination Address Error (DAE) */ +#define EDMA_CH_ES_SOE (1 << 6) /* Bit 6: Source Offset Error (SOE) */ +#define EDMA_CH_ES_SAE (1 << 7) /* Bit 7: Source Address Error (SAE) */ + /* Bit 8-30: Reserved */ +#define EDMA_CH_ES_ERR (1 << 31) /* Bit 31: Error in this channel (ERR) */ + +/* Channel n Interrupt Status Register (CHn_INT) */ + +#define EDMA_CH_INT (1 << 0) /* Bit 0: Interrupt Request (INT) */ + /* Bits 1-31: Reserved */ + +/* Channel n System Bus Register (CHn_SBR) */ + +#define EDMA_CH_SBR_MID_SHIFT (0) /* Bits 0-3: Master ID (MID) */ +#define EDMA_CH_SBR_MID_MASK (0x0f << EDMA_CH_SBR_MID_SHIFT) + /* Bits 4-13: Reserved */ +#define EDMA_CH_SBR_SEC (1 << 14) /* Bit 14: Security Level (SEC) */ +#define EDMA_CH_SBR_PAL (1 << 15) /* Bit 15: Privileged Access Level (PAL) */ +#define EDMA_CH_SBR_EMI (1 << 16) /* Bit 16: Enable Master ID Replication (EMI) */ +#define EDMA_CH_SBR_ATTR_SHIFT (17) /* Bits 17-19: Attribute Output (ATTR) */ +#define EDMA_CH_SBR_ATTR_MASK (0x07 << EDMA_CH_SBR_ATTR_SHIFT) + /* Bits 20-31: Reserved */ + +/* Channel n Priority Register (CHn_PRI) */ + +#define EDMA_CH_PRI_APL_SHIFT (0) /* Bits 0-2: Arbitration Priority Level (APL) */ +#define EDMA_CH_PRI_APL_MASK (0x07 << EDMA_CH_PRI_APL_SHIFT) + /* Bits 3-29: Reserved */ +#define EDMA_CH_PRI_DPA (1 << 30) /* Bit 30: Disable Preempt Ability (DPA) */ +#define EDMA_CH_PRI_ECP (1 << 31) /* Bit 31: Enable Channel Preemption (ECP) */ + +/* Channel Multiplexor Configuration (CHn_MUX). On RT1180 the mux source + * ID field is 8-bit for eDMA4 (up to 256 sources) and 6-bit for eDMA3. + * Using the wider mask is safe since unused high bits are reserved. + */ + +#define EDMA_CH_SRC_SHIFT (0) /* Bits 0-7: Service Request Source */ +#define EDMA_CH_SRC_MASK (0xff << EDMA_CH_SRC_SHIFT) + +/* TCDn Source Address Register (TCDn_SADDR) */ + +#define EDMA_TCD_SADDR_SHIFT (0) /* Bits 0-31: Source Address (SADDR) */ +#define EDMA_TCD_SADDR_MASK (0xffffffff << EDMA_TCD_SADDR_SHIFT) + +/* TCDn Signed Source Address Offset Register (TCDn_SOFF) */ + +#define EDMA_TCD_SOFF_SHIFT (0) /* Bits 0-31: Source Address Signed Offset (SOFF) */ +#define EDMA_TCD_SOFF_MASK (0xffffffff << EDMA_TCD_SOFF_SHIFT) + +/* TCDn Transfer Attributes (TCDn_ATTR) */ + +#define EDMA_TCD_ATTR_DSIZE_SHIFT (0) /* Bits 0-2: Destination Data Transfer Size (DSIZE) */ +#define EDMA_TCD_ATTR_DSIZE_MASK (0x07 << EDMA_TCD_ATTR_DSIZE_SHIFT) +#define EDMA_TCD_ATTR_DSIZE(n) (((n) << EDMA_TCD_ATTR_DSIZE_SHIFT) & EDMA_TCD_ATTR_DSIZE_MASK) +#define EDMA_TCD_ATTR_DMOD_SHIFT (3) /* Bits 3-7: Destination Address Modulo (DMOD) */ +#define EDMA_TCD_ATTR_DMOD_MASK (0x1f << EDMA_TCD_ATTR_DMOD_SHIFT) +#define EDMA_TCD_ATTR_DMOD(n) (((n) << EDMA_TCD_ATTR_DMOD_SHIFT) & EDMA_TCD_ATTR_DMOD_MASK) +#define EDMA_TCD_ATTR_SSIZE_SHIFT (8) /* Bits 8-10: Source Data Transfer Size (SSIZE) */ +#define EDMA_TCD_ATTR_SSIZE_MASK (0x07 << EDMA_TCD_ATTR_SSIZE_SHIFT) +#define EDMA_TCD_ATTR_SSIZE(n) (((n) << EDMA_TCD_ATTR_SSIZE_SHIFT) & EDMA_TCD_ATTR_SSIZE_MASK) +# define EDMA_TCD_ATTR_SSIZE_8BIT (0x00 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 8-bit */ +# define EDMA_TCD_ATTR_SSIZE_16BIT (0x01 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 16-bit */ +# define EDMA_TCD_ATTR_SSIZE_32BIT (0x02 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-bit */ +# define EDMA_TCD_ATTR_SSIZE_64BIT (0x03 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 64-bit */ +# define EDMA_TCD_ATTR_SSIZE_16BYTE (0x04 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 16-byte */ +# define EDMA_TCD_ATTR_SSIZE_32BYTE (0x05 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-byte */ +# define EDMA_TCD_ATTR_SSIZE_64BYTE (0x06 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 64-byte */ + +#define EDMA_TCD_ATTR_SMOD_SHIFT (11) /* Bits 11-15: Source Address Modulo (SMOD) */ +#define EDMA_TCD_ATTR_SMOD_MASK (0x1f << EDMA_TCD_ATTR_SMOD_SHIFT) +#define EDMA_TCD_ATTR_SMOD(n) (((n) << EDMA_TCD_ATTR_SMOD_SHIFT) & EDMA_TCD_ATTR_SMOD_MASK) + +/* TCDn Transfer Size (TCDn_NBYTES) */ + +#define EDMA_TCD_NBYTES_SHIFT (0) /* Bits 0-29: Number of Bytes to Transfer per Service Request (NBYTES) */ +#define EDMA_TCD_NBYTES_MASK (0x3fffffff << EDMA_TCD_NBYTES_SHIFT) +#define EDMA_TCD_NBYTES_MASK_MLOFF (0x03ff << EDMA_TCD_NBYTES_SHIFT) +#define EDMA_TCD_NBYTES_MLOFF_SHIFT (10) /* Bits 10-29: Minor Loop Offset (MLOFF) */ +#define EDMA_TCD_NBYTES_MLOFF_MASK (0x0fffff << EDMA_TCD_NBYTES_MLOFF_SHIFT) +#define EDMA_TCD_NBYTES_DMLOE (1 << 30) /* Bit 30: Destination Minor Loop Offset Enable (DMLOE) */ +#define EDMA_TCD_NBYTES_SMLOE (1 << 31) /* Bit 31: Source Minor Loop Offset Enable (SMLOE) */ + +/* TCDn Last Source Address Adjustment / Store DADDR Address Register + * (TCDn_SLAST_SDA) + */ + +#define EDMA_TCD_SLAST_SDA_SHIFT (0) /* Bits 0-31: Last Source Address Adjustment / Store DADDR Address (SLAST_SDA) */ +#define EDMA_TCD_SLAST_SDA_MASK (0xffffffff << EDMA_TCD_SLAST_SDA_SHIFT) + +/* TCDn Destination Address Register (TCDn_DADDR) */ + +#define EDMA_TCD_DADDR_SHIFT (0) /* Bits 0-31: Destination Address (DADDR) */ +#define EDMA_TCD_DADDR_MASK (0xffffffff << EDMA_TCD_DADDR_SHIFT) + +/* TCDn Signed Destination Address Offset Register (TCDn_DOFF) */ + +#define EDMA_TCD_DOFF_SHIFT (0) /* Bits 0-15: Destination Address Signed Offset (DOFF) */ +#define EDMA_TCD_DOFF_MASK (0xffff << EDMA_TCD_DOFF_SHIFT) + +/* TCDn Current Major Loop Count Register (TCDn_CITER) */ + +#define EDMA_TCD_CITER_SHIFT (0) /* Bits 0-14: Current Major Iteration Count (CITER) */ +#define EDMA_TCD_CITER_MASK (0x7fff << EDMA_TCD_CITER_SHIFT) +#define EDMA_TCD_CITER_MASK_ELINK (0x01ff << EDMA_TCD_CITER_SHIFT) +#define EDMA_TCD_CITER_LINKCH_SHIFT (9) /* Bits 9-13: Minor Loop Link Channel Number (LINKCH) */ +#define EDMA_TCD_CITER_LINKCH_MASK (0x1f << EDMA_TCD_CITER_LINKCH_SHIFT) +#define EDMA_TCD_CITER_LINKCH(n) (((n) << EDMA_TCD_CITER_LINKCH_SHIFT) & EDMA_TCD_CITER_LINKCH_SHIFT) +#define EDMA_TCD_CITER_ELINK (1 << 15) /* Bit 15: Enable Link (ELINK) */ + +/* TCDn Last Destination Address Adjustment / Scatter Gather Address Register + * (TCDn_DLAST_SGA) + */ + +#define EDMA_TCD_DLAST_SGA_SHIFT (0) /* Bits 0-31: Last Destination Address Adjustment / Scatter Gather Address (DLAST_SGA) */ +#define EDMA_TCD_DLAST_SGA_MASK (0xffffffff << EDMA_TCD_DLAST_SGA_SHIFT) + +/* TCDn Control and Status Register (TCDn_CSR) */ + +#define EDMA_TCD_CSR_START (1 << 0) /* Bit 0: Channel Start (START) */ +#define EDMA_TCD_CSR_INTMAJOR (1 << 1) /* Bit 1: Enable Interrupt if Major count complete (INTMAJOR) */ +#define EDMA_TCD_CSR_INTHALF (1 << 2) /* Bit 2: Enable Interrupt if Major Count Half-complete (INTHALF) */ +#define EDMA_TCD_CSR_DREQ (1 << 3) /* Bit 3: Disable Request (DREQ) */ +#define EDMA_TCD_CSR_ESG (1 << 4) /* Bit 4: Enable Scatter/Gather Processing (ESG) */ +#define EDMA_TCD_CSR_MAJORELINK (1 << 5) /* Bit 5: Enable Link When Major Loop Complete (MAJORELINK) */ +#define EDMA_TCD_CSR_EEOP (1 << 6) /* Bit 6: Enable End-Of-Packet Processing (EEOP) */ +#define EDMA_TCD_CSR_ESDA (1 << 7) /* Bit 7: Enable Store Destination Address (ESDA) */ +#define EDMA_TCD_CSR_MAJORLINKCH_SHIFT (8) /* Bits 8-12: Major Loop Link Channel Number (MAJORLINKCH) */ +#define EDMA_TCD_CSR_MAJORLINKCH_MASK (0x1f << EDMA_TCD_CSR_MAJORLINKCH_SHIFT) +#define EDMA_TCD_CSR_MAJORLINKCH(n) (((n) << EDMA_TCD_CSR_MAJORLINKCH_SHIFT) & EDMA_TCD_CSR_MAJORLINKCH_MASK) + /* Bit 13: Reserved */ +#define EDMA_TCD_CSR_BWC_SHIFT (14) /* Bits 14-15: Bandwidth Control (BWC) */ +#define EDMA_TCD_CSR_BWC_MASK (0x03 << EDMA_TCD_CSR_BWC_SHIFT) +# define EDMA_TCD_CSR_BWC_NOSTALL (0x00 << EDMA_TCD_CSR_BWC_SHIFT) /* No eDMA engine stalls */ +# define EDMA_TCD_CSR_BWC_HPE (0x01 << EDMA_TCD_CSR_BWC_SHIFT) /* Enable eDMA master high-priority elevation (HPE) mode */ +# define EDMA_TCD_CSR_BWC_4CYCLES (0x02 << EDMA_TCD_CSR_BWC_SHIFT) /* eDMA engine stalls for 4 cycles after each R/W */ +# define EDMA_TCD_CSR_BWC_8CYCLES (0x03 << EDMA_TCD_CSR_BWC_SHIFT) /* eDMA engine stalls for 8 cycles after each R/W */ + +/* TCDn Beginning Major Loop Count Register (TCDn_BITER) */ + +#define EDMA_TCD_BITER_SHIFT (0) /* Bits 0-14: Starting Major Iteration Count (BITER) */ +#define EDMA_TCD_BITER_MASK (0x7fff << EDMA_TCD_BITER_SHIFT) +#define EDMA_TCD_BITER_MASK_ELINK (0x01ff << EDMA_TCD_BITER_SHIFT) +#define EDMA_TCD_BITER_LINKCH_SHIFT (9) /* Bits 9-13: Link Channel Number (LINKCH) */ +#define EDMA_TCD_BITER_LINKCH_MASK (0x1f << EDMA_TCD_BITER_LINKCH_SHIFT) +#define EDMA_TCD_BITER_LINKCH(n) (((n) << EDMA_TCD_BITER_LINKCH_SHIFT) & EDMA_TCD_BITER_LINKCH_MASK) +#define EDMA_TCD_BITER_ELINK (1 << 15) /* Bit 15: Enable Link (ELINK) */ + +/* Amount of channels */ + +#define DMA3_CHANNEL_COUNT (32) +#define DMA4_CHANNEL_COUNT (64) +#define IMXRT_EDMA_NCHANNELS (DMA3_CHANNEL_COUNT + DMA4_CHANNEL_COUNT) + +/* Amount of interrupt sources */ + +#define DMA3_IRQ_COUNT (32) /* Error interrupt not counted */ +#define DMA4_IRQ_COUNT (16) /* Error interrupt not counted; + * 4 channels share one IRQ */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* In-memory representation of the 32-byte Transfer Control Descriptor + * (TCD) + */ + +struct imxrt_edmatcd_s +{ + uint32_t saddr; /* Offset: 0x0000 TCD Source Address */ + uint16_t soff; /* Offset: 0x0004 TCD Signed Source Address Offset */ + uint16_t attr; /* Offset: 0x0006 TCD Transfer Attributes */ + uint32_t nbytes; /* Offset: 0x0008 TCD Signed Minor Loop Offset / Byte Count */ + uint32_t slast; /* Offset: 0x000c TCD Last Source Address Adjustment */ + uint32_t daddr; /* Offset: 0x0010 TCD Destination Address */ + uint16_t doff; /* Offset: 0x0014 TCD Signed Destination Address Offset */ + uint16_t citer; /* Offset: 0x0016 TCD Current Minor Loop Link, Major Loop Count */ + uint32_t dlastsga; /* Offset: 0x0018 TCD Last Destination Address Adjustment/Scatter Gather Address */ + uint16_t csr; /* Offset: 0x001c TCD Control and Status */ + uint16_t biter; /* Offset: 0x001e TCD Beginning Minor Loop Link, Major Loop Count */ +}; + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_edma_tcdhasmux + * + * Description: + * Check if DMA TCD has TCD.MUX register. + * + * Input Parameters: + * dmabase - The eDMA base. + * + * Returned Value: + * true if TCD.MUX exists; false if not. + * + ****************************************************************************/ + +static inline bool imxrt_edma_tcdhasmux(uintptr_t dmabase) +{ + /* On RT1180 both eDMA3 and eDMA4 have per-channel CH_MUX registers. */ + + return true; +} + +/**************************************************************************** + * Name: imxrt_edma_choffset + * + * Description: + * Channel offset in global channel list for dma base. + * + * Input Parameters: + * base - The eDMA base. + * + * Returned Value: + * Channel offset. + * + ****************************************************************************/ + +static inline uint32_t imxrt_edma_choffset(uintptr_t base) +{ + return base == IMXRT_DMA3_BASE ? 0 : DMA3_CHANNEL_COUNT; +} + +/**************************************************************************** + * Name: imxrt_edma_chmax + * + * Description: + * Max channel in global channel list for dma base. + * + * Input Parameters: + * base - The eDMA base. + * + * Returned Value: + * Channel max. + * + ****************************************************************************/ + +static inline uint32_t imxrt_edma_chmax(uintptr_t base) +{ + return base == IMXRT_DMA3_BASE ? DMA3_CHANNEL_COUNT : IMXRT_EDMA_NCHANNELS; +} + +#endif /* __ARCH_ARM_SRC_IMXRT_HARDWARE_RT118X_IMXRT118X_EDMA_H */ diff --git a/arch/arm/src/imxrt/imxrt_edma.h b/arch/arm/src/imxrt/imxrt_edma.h index 8bca05b09bc..a24c5429207 100644 --- a/arch/arm/src/imxrt/imxrt_edma.h +++ b/arch/arm/src/imxrt/imxrt_edma.h @@ -99,7 +99,12 @@ #include #include -#include "hardware/imxrt_edma.h" + +#ifdef CONFIG_IMXRT_EDMA_VER2 +# include "hardware/rt118x/imxrt118x_edma.h" +#else +# include "hardware/imxrt_edma.h" +#endif /**************************************************************************** * Pre-processor Definitions @@ -138,13 +143,26 @@ typedef void *DMACH_HANDLE; typedef void (*edma_callback_t)(DMACH_HANDLE handle, void *arg, bool done, int result); -/* eDMA transfer sizes */ +/* eDMA transfer type */ -enum kinetis_edma_sizes_e +enum imxrt_edma_xfrtype_e +{ + EDMA_MEM2MEM = 0, /* Transfer from memory to memory */ + EDMA_PERIPH2MEM, /* Transfer from peripheral to memory */ + EDMA_MEM2PERIPH, /* Transfer from memory to peripheral */ +}; + +/* eDMA transfer sises */ + +enum imxrt_edma_sizes_e { EDMA_8BIT = 0, /* Transfer data size 8 */ EDMA_16BIT = 1, /* Transfer data size 16 */ EDMA_32BIT = 2, /* Transfer data size 32 */ + EDMA_64BIT = 3, /* Transfer data size 64 */ + EDMA_16BYTE = 4, /* Transfer data size 16-byte */ + EDMA_32BYTE = 5, /* Transfer data size 32-byte */ + EDMA_64BYTE = 6, /* Transfer data size 64-byte */ }; /* This structure holds the source/destination transfer attribute @@ -166,6 +184,11 @@ struct imxrt_edma_xfrconfig_s #else uint32_t nbytes; /* Bytes to transfer in a minor loop */ #endif +#ifdef CONFIG_IMXRT_EDMA_VER2 + uint8_t smod; + uint8_t dmod; + uint8_t bwc; +#endif #ifdef CONFIG_IMXRT_EDMA_ELINK DMACH_HANDLE linkch; /* Link channel (With EDMA_CONFIG_LINKTYPE_* flags) */ #endif diff --git a/arch/arm/src/imxrt/imxrt_edma_ver2.c b/arch/arm/src/imxrt/imxrt_edma_ver2.c new file mode 100644 index 00000000000..1be42a936ec --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_edma_ver2.c @@ -0,0 +1,1529 @@ +/**************************************************************************** + * arch/arm/src/imxrt/imxrt_edma_ver2.c + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: 2019, 2021, 2023 Gregory Nutt. + * SPDX-FileCopyrightText: 2022 NXP + * SPDX-FileCopyrightText: 2016-2017 NXP + * SPDX-FileCopyrightText: 2015, Freescale Semiconductor, Inc. + * SPDX-FileContributor: Gregory Nutt + * SPDX-FileContributor: David Sidrane + * SPDX-FileContributor: Peter van der Perk + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "sched/sched.h" + +#include "chip.h" +#include "imxrt_edma.h" +#include "imxrt_clockconfig.h" + +#include "hardware/imxrt_ccm.h" +#include "hardware/rt118x/imxrt118x_edma.h" +#include "hardware/imxrt_dmamux.h" + +#ifdef CONFIG_IMXRT_EDMA + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* TCD Alignment. + * + * eDMA TCDs must be aligned with the D-Cache line boundaries to facilitate + * cache operations on the TCDs when the D-Cache is enabled. + * + * NOTE: The TCDs are 32-bytes in length. We implicitly assume that the + * D-Cache line size is also 32-bits. Otherwise, padding would be required + * at the ends of the TCDS and buffers to protect data after the end of from + * invalidation. + */ + +#define EDMA_ALIGN ARMV7M_DCACHE_LINESIZE +#define EDMA_ALIGN_MASK (EDMA_ALIGN - 1) +#define EDMA_ALIGN_UP(n) (((n) + EDMA_ALIGN_MASK) & ~EDMA_ALIGN_MASK) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* State of a DMA channel */ + +enum imxrt_dmastate_e +{ + IMXRT_DMA_IDLE = 0, /* No DMA in progress */ + IMXRT_DMA_CONFIGURED, /* DMA configured, but not yet started */ + IMXRT_DMA_ACTIVE /* DMA has been started and is in progress */ +}; + +/* This structure describes one DMA channel */ + +struct imxrt_dmach_s +{ + uintptr_t base; /* DMA engine base address */ + uint32_t flags; /* DMA channel flags */ + bool inuse; /* true: The DMA channel is in use */ + uint8_t dmamux; /* DMAMUX channel number */ + uint8_t chan; /* DMA channel number (either eDMA3 or eDMA4) */ + uint8_t state; /* Channel state. See enum imxrt_dmastate_e */ + edma_callback_t callback; /* Callback invoked when the DMA completes */ + void *arg; /* Argument passed to callback function */ +#if CONFIG_IMXRT_EDMA_NTCD > 0 + /* That TCD list is linked through the DLAST SGA field. The first transfer + * to be performed is at the head of the list. Subsequent TCDs are added + * at the tail of the list. + */ + + struct imxrt_edmatcd_s *head; /* First TCD in the list */ + struct imxrt_edmatcd_s *tail; /* Last TCD in the list */ +#endif +}; + +/* This structure describes the state of the eDMA controller */ + +struct imxrt_edma_s +{ + /* These mutex protect the DMA channel and descriptor tables */ + + mutex_t chlock; /* Protects channel table */ +#if CONFIG_IMXRT_EDMA_NTCD > 0 + sem_t dsem; /* Supports wait for free descriptors */ +#endif + + /* This array describes each DMA channel */ + + struct imxrt_dmach_s dmach[IMXRT_EDMA_NCHANNELS]; + spinlock_t lock; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The state of the eDMA */ + +static struct imxrt_edma_s g_edma = +{ + .chlock = NXMUTEX_INITIALIZER, +#if CONFIG_IMXRT_EDMA_NTCD > 0 + .dsem = SEM_INITIALIZER(CONFIG_IMXRT_EDMA_NTCD), +#endif + .lock = SP_UNLOCKED +}; + +#if CONFIG_IMXRT_EDMA_NTCD > 0 +/* This is a singly-linked list of free TCDs */ + +static sq_queue_t g_tcd_free; + +/* This is a pool of pre-allocated TCDs */ + +static struct imxrt_edmatcd_s g_tcd_pool[CONFIG_IMXRT_EDMA_NTCD] + aligned_data(EDMA_ALIGN); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_tcd_alloc + * + * Description: + * Allocate an in-memory, TCD + * + ****************************************************************************/ + +#if CONFIG_IMXRT_EDMA_NTCD > 0 +static struct imxrt_edmatcd_s *imxrt_tcd_alloc(void) +{ + struct imxrt_edmatcd_s *tcd; + irqstate_t flags; + + /* Take the 'dsem'. When we hold the the 'dsem', then we know that one + * TCD is reserved for us in the free list. + * + * NOTE: We use a critical section here because we may block waiting for + * the 'dsem'. The critical section will be suspended while we are + * waiting. + */ + + nxsem_wait_uninterruptible(&g_edma.dsem); + + /* Now there should be a TCD in the free list reserved just for us */ + + flags = spin_lock_irqsave(&g_edma.lock); + tcd = (struct imxrt_edmatcd_s *)sq_remfirst(&g_tcd_free); + DEBUGASSERT(tcd != NULL); + + spin_unlock_irqrestore(&g_edma.lock, flags); + return tcd; +} +#endif + +/**************************************************************************** + * Name: imxrt_tcd_free + * + * Description: + * Free an in-memory, TCD + * + ****************************************************************************/ + +#if CONFIG_IMXRT_EDMA_NTCD > 0 +static void imxrt_tcd_free_nolock(struct imxrt_edmatcd_s *tcd) +{ + /* Add the the TCD to the end of the free list and post the 'dsem', + * possibly waking up another thread that might be waiting for + * a TCD. + */ + + sq_addlast((sq_entry_t *)tcd, &g_tcd_free); + nxsem_post(&g_edma.dsem); +} + +static void imxrt_tcd_free(struct imxrt_edmatcd_s *tcd) +{ + irqstate_t flags; + + /* Add the TCD to the end of the free list and post the 'dsem', + * possibly waking up another thread that might be waiting for + * a TCD. + */ + + flags = spin_lock_irqsave_nopreempt(&g_edma.lock); + imxrt_tcd_free_nolock(tcd); + spin_unlock_irqrestore_nopreempt(&g_edma.lock, flags); +} +#endif + +/**************************************************************************** + * Name: imxrt_tcd_initialize() + * + * Description: + * Initialize the TCD free list from the pool of pre-allocated TCDs. + * + * Assumptions: + * Called early in the initialization sequence so no special protection is + * necessary. + * + ****************************************************************************/ + +#if CONFIG_IMXRT_EDMA_NTCD > 0 +static inline void imxrt_tcd_initialize(void) +{ + sq_entry_t *tcd; + int i; + + /* Add each pre-allocated TCD to the tail of the TCD free list */ + + sq_init(&g_tcd_free); + for (i = 0; i < CONFIG_IMXRT_EDMA_NTCD; i++) + { + tcd = (sq_entry_t *)&g_tcd_pool[i]; + sq_addlast(tcd, &g_tcd_free); + } +} +#endif + +/**************************************************************************** + * Name: imxrt_tcd_chanlink + * + * Description: + * This function configures either a minor link or a major link. The minor + * link means the channel link is triggered every time CITER decreases by 1 + * The major link means that the channel link is triggered when the CITER + * is exhausted. + * + * NOTE: Users should ensure that DONE flag is cleared before calling this + * interface, or the configuration is invalid. + * + * Input Parameters: + * tcd - Point to the TCD structure. + * type - Channel link type. + * chan - The linked channel number. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_IMXRT_EDMA_ELINK +static inline void imxrt_tcd_chanlink(uint8_t flags, + struct imxrt_dmach_s *linkch, + struct imxrt_edmatcd_s *tcd) +{ + uint16_t regval16; + + flags &= EDMA_CONFIG_LINKTYPE_MASK; + + if (linkch == NULL || flags == EDMA_CONFIG_LINKTYPE_LINKNONE) + { + /* No link or no link channel provided */ + + /* Disable minor links */ + + /* Disable major link */ + + tcd->csr &= ~EDMA_TCD_CSR_MAJORELINK; + } + else if (flags == EDMA_CONFIG_LINKTYPE_MINORLINK) /* Minor link config */ + { + /* Enable minor link */ + + tcd->citer |= EDMA_TCD_CITER_ELINK; + tcd->biter |= EDMA_TCD_BITER_ELINK; + + /* Set linked channel */ + + regval16 = tcd->citer; + regval16 &= ~EDMA_TCD_CITER_LINKCH_MASK; + regval16 |= EDMA_TCD_CITER_LINKCH(linkch->chan); + tcd->citer = regval16; + + regval16 = tcd->biter; + regval16 &= ~EDMA_TCD_BITER_LINKCH_MASK; + regval16 |= EDMA_TCD_BITER_LINKCH(linkch->chan); + tcd->biter = regval16; + } + else /* if (flags == EDMA_CONFIG_LINKTYPE_MAJORLINK) Major link config */ + { + /* Enable major link */ + + regval16 = tcd->csr; + regval16 |= EDMA_TCD_CSR_MAJORELINK; + tcd->csr = regval16; + + /* Set major linked channel */ + + regval16 &= ~EDMA_TCD_CSR_MAJORLINKCH_MASK; + regval16 |= EDMA_TCD_CSR_MAJORLINKCH(linkch->chan); + tcd->csr = regval16; + } +} +#endif + +/**************************************************************************** + * Name: imxrt_tcd_configure + * + * Description: + * Configure all TCD registers to the specified values. 'tcd' is an + * 'overlay' that may refer either to either the TCD register set or to an + * in-memory TCD structure. + * + ****************************************************************************/ + +static inline void imxrt_tcd_configure(struct imxrt_edmatcd_s *tcd, + const struct imxrt_edma_xfrconfig_s *config) +{ + tcd->saddr = config->saddr; + tcd->soff = config->soff; + tcd->attr = EDMA_TCD_ATTR_SSIZE(config->ssize) | /* Transfer Attributes */ + EDMA_TCD_ATTR_DSIZE(config->dsize); +#ifdef CONFIG_IMXRT_EDMA_MOD + tcd->attr |= EDMA_TCD_ATTR_SMOD(config->smod) | /* Transfer Attributes */ + EDMA_TCD_ATTR_DMOD(config->dmod); +#endif + tcd->nbytes = config->nbytes; + tcd->slast = config->flags & EDMA_CONFIG_LOOPSRC ? + -(config->iter * config->nbytes) : 0; + + tcd->daddr = config->daddr; + tcd->doff = config->doff; + tcd->citer = config->iter & EDMA_TCD_CITER_MASK; + tcd->biter = config->iter & EDMA_TCD_BITER_MASK; + tcd->csr = config->flags & EDMA_CONFIG_LOOP_MASK ? + 0 : EDMA_TCD_CSR_DREQ; + tcd->csr |= config->flags & EDMA_CONFIG_INTHALF ? + EDMA_TCD_CSR_INTHALF : 0; + tcd->dlastsga = config->flags & EDMA_CONFIG_LOOPDEST ? + -(config->iter * config->nbytes) : 0; + + /* And special case flags */ + +#ifdef CONFIG_IMXRT_EDMA_ELINK + /* Configure major/minor link mapping */ + + imxrt_tcd_chanlink(config->flags, (struct imxrt_dmach_s *)config->linkch, + tcd); +#endif +} + +/**************************************************************************** + * Name: imxrt_tcd_instantiate + * + * Description: + * Copy an in-memory TCD into eDMA channel TCD registers + * + ****************************************************************************/ + +#if CONFIG_IMXRT_EDMA_NTCD > 0 +static void imxrt_tcd_instantiate(struct imxrt_dmach_s *dmach, + const struct imxrt_edmatcd_s *tcd) +{ + uintptr_t base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); + + /* Push tcd into hardware TCD register */ + + /* Clear DONE bit first, otherwise ESG cannot be set */ + + putreg16(0, base + IMXRT_EDMA_TCD_CSR_OFFSET); + + putreg32(tcd->saddr, base + IMXRT_EDMA_TCD_SADDR_OFFSET); + putreg16(tcd->soff, base + IMXRT_EDMA_TCD_SOFF_OFFSET); + putreg16(tcd->attr, base + IMXRT_EDMA_TCD_ATTR_OFFSET); + putreg32(tcd->nbytes, base + IMXRT_EDMA_TCD_NBYTES_OFFSET); + putreg32(tcd->slast, base + IMXRT_EDMA_TCD_SLAST_SDA_OFFSET); + putreg32(tcd->daddr, base + IMXRT_EDMA_TCD_DADDR_OFFSET); + putreg16(tcd->doff, base + IMXRT_EDMA_TCD_DOFF_OFFSET); + putreg16(tcd->citer, base + IMXRT_EDMA_TCD_CITER_OFFSET); + putreg32(tcd->dlastsga, base + IMXRT_EDMA_TCD_DLAST_SGA_OFFSET); + + putreg16(tcd->csr, base + IMXRT_EDMA_TCD_CSR_OFFSET); + + putreg16(tcd->biter, base + IMXRT_EDMA_TCD_BITER_OFFSET); +} +#endif + +/**************************************************************************** + * Name: imxrt_dmaterminate + * + * Description: + * Terminate the DMA transfer and disable the DMA channel + * + ****************************************************************************/ + +static void imxrt_dmaterminate(struct imxrt_dmach_s *dmach, int result) +{ + uintptr_t base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); +#if CONFIG_IMXRT_EDMA_NTCD > 0 + struct imxrt_edmatcd_s *tcd; + struct imxrt_edmatcd_s *next; +#endif + edma_callback_t callback; + void *arg; + + irqstate_t flags; + + flags = spin_lock_irqsave_nopreempt(&g_edma.lock); + + /* Disable channel IRQ requests */ + + putreg32(EDMA_CH_INT, base + IMXRT_EDMA_CH_INT_OFFSET); + + /* Clear CSR to disable channel. Because if the given channel started, + * transfer CSR will be not zero. Because if it is the last transfer, DREQ + * will be set. If not, ESG will be set. + */ + + putreg32(0, base + IMXRT_EDMA_CH_CSR_OFFSET); + + putreg16(0, base + IMXRT_EDMA_TCD_CSR_OFFSET); + + /* Cancel next TCD transfer. */ + + putreg32(0, base + IMXRT_EDMA_TCD_DLAST_SGA_OFFSET); + +#if CONFIG_IMXRT_EDMA_NTCD > 0 + /* Return all allocated TCDs to the free list */ + + for (tcd = dmach->head; tcd != NULL; tcd = next) + { + /* If channel looped to itself we are done + * if not continue to free tcds in chain + */ + + next = dmach->flags & EDMA_CONFIG_LOOPDEST ? + NULL : (struct imxrt_edmatcd_s *)((uintptr_t)tcd->dlastsga); + + imxrt_tcd_free_nolock(tcd); + } + + dmach->head = NULL; + dmach->tail = NULL; +#endif + + /* Perform the DMA complete callback */ + + callback = dmach->callback; + arg = dmach->arg; + + dmach->callback = NULL; + dmach->arg = NULL; + dmach->state = IMXRT_DMA_IDLE; + + spin_unlock_irqrestore_nopreempt(&g_edma.lock, flags); + + if (callback) + { + callback((DMACH_HANDLE)dmach, arg, true, result); + } +} + +/**************************************************************************** + * Name: imxrt_edma_intstatus + * + * Description: + * DMA interrupt status per eDMA engine and channel. + * + ****************************************************************************/ + +static inline uint32_t imxrt_edma_intstatus(uintptr_t base, uint8_t chan) +{ + /* The status register varies depending on eDMA instance and channel */ + +#ifdef IMXRT_DMA3_BASE + /* eDMA3 uses the normal INT register */ + + if (base == IMXRT_DMA3_BASE) + { + return getreg32(IMXRT_EDMA_INT); + } +#endif + +#ifdef IMXRT_DMA4_BASE + /* eDMA4 has two INT status registers, holding 32 statuses each */ + + if (chan > 31) + { + return getreg32(IMXRT_EDMA_INT_HIGH); + } + + return getreg32(IMXRT_EDMA_INT_LOW); +#endif +} + +/**************************************************************************** + * Name: imxrt_edma_isr + * + * Description: + * DMA interrupt service routine. The vector handler calls this with the + * appropriate parameters. + * + ****************************************************************************/ + +static int imxrt_edma_isr(int irq, void *context, void *arg) +{ + struct imxrt_dmach_s *dmach; + uintptr_t base; + uint32_t regval32; + uint32_t errval32; + uint8_t chan; + int result; + + /* 'arg' should the DMA channel instance. */ + + dmach = (struct imxrt_dmach_s *)arg; + DEBUGASSERT(dmach != NULL); + + chan = dmach->chan; + base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); + + /* Get the eDMA Error Status register value. */ + + errval32 = getreg32(base + IMXRT_EDMA_CH_ES_OFFSET); + + if (errval32 & EDMA_CH_ES_ERR) + { + DEBUGASSERT(dmach->state == IMXRT_DMA_ACTIVE); + + /* Clear the error */ + + putreg32(EDMA_CH_ES_ERR, base + IMXRT_EDMA_CH_ES_OFFSET); + + /* Clear the pending eDMA channel interrupt */ + + putreg32(EDMA_CH_INT, base + IMXRT_EDMA_CH_INT_OFFSET); + + imxrt_dmaterminate(dmach, -EIO); + return OK; + } + + /* Check for an eDMA pending interrupt on this channel */ + + regval32 = imxrt_edma_intstatus(dmach->base, dmach->chan); + if ((regval32 & EDMA_INT(chan & 31)) != 0) + { + /* An interrupt is pending. + * This should only happen if the channel is active. + */ + + DEBUGASSERT(dmach->state == IMXRT_DMA_ACTIVE); + + /* Clear the pending eDMA channel interrupt */ + + putreg32(EDMA_CH_INT, base + IMXRT_EDMA_CH_INT_OFFSET); + + /* Get the eDMA TCD Control and Status register value. */ + + regval32 = getreg32(base + IMXRT_EDMA_CH_CSR_OFFSET); + + /* Check if transfer has finished. */ + + if ((regval32 & EDMA_CH_CSR_DONE) != 0) + { + /* Clear the pending DONE interrupt status. */ + + regval32 |= EDMA_CH_CSR_DONE; + putreg32(regval32, base + IMXRT_EDMA_CH_CSR_OFFSET); + result = OK; + } + else + { + /* Perform the half or end-of-major-cycle DMA callback */ + + if (dmach->callback != NULL) + { + dmach->callback((DMACH_HANDLE)dmach, dmach->arg, false, OK); + } + + return OK; + } + + /* Terminate the transfer when it is done. */ + + if ((dmach->flags & EDMA_CONFIG_LOOP_MASK) == 0) + { + imxrt_dmaterminate(dmach, result); + } + else if (dmach->callback != NULL) + { + dmach->callback((DMACH_HANDLE)dmach, dmach->arg, true, result); + } + } + + return OK; +} + +/**************************************************************************** + * Name: imxrt_edma_interrupt + * + * Description: + * DMA interrupt handler. This function clears the channel major + * interrupt flag and calls the callback function if it is not NULL. + * + * NOTE: For the case using TCD queue, when the major iteration count is + * exhausted, additional operations are performed. These include the + * final address adjustments and reloading of the BITER field into the + * CITER. Assertion of an optional interrupt request also occurs at this + * time, as does a possible fetch of a new TCD from memory using the + * scatter/gather address pointer included in the descriptor (if scatter/ + * gather is enabled). + * + ****************************************************************************/ + +static int imxrt_edma_interrupt(int irq, void *context, void *arg) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)arg; + +#ifdef IMXRT_DMA3_BASE + if ((irq >= IMXRT_IRQ_DMA3_CH0) && (irq <= IMXRT_IRQ_DMA3_CH31)) + { + /* eDMA3 interrupt has a single source */ + + imxrt_edma_isr(irq, context, dmach); + } +#endif + +#ifdef IMXRT_DMA4_BASE + if ((irq >= IMXRT_IRQ_DMA4_CH0_CH1_CH32_CH33) && + (irq <= IMXRT_IRQ_DMA4_CH30_CH31_CH62_CH63)) + { + /* eDMA4 interrupt has four sources on iMXRT8x */ + + imxrt_edma_isr(irq, context, dmach); + imxrt_edma_isr(irq, context, dmach + 1); + imxrt_edma_isr(irq, context, dmach + 32); + imxrt_edma_isr(irq, context, dmach + 33); + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: imxrt_edma_configure + * + * Description: + * Configure eDMA instance. + * + ****************************************************************************/ + +static void imxrt_edma_configure(uintptr_t base) +{ + uint32_t regval; + + /* Configure the eDMA controllers */ + + regval = getreg32(IMXRT_EDMA_CSR(base)); + regval &= ~(EDMA_CSR_EDBG | EDMA_CSR_ERCA | EDMA_CSR_HAE | EDMA_CSR_GCLC | + EDMA_CSR_GMRC); + +#ifdef CONFIG_IMXRT_EDMA_EDBG + regval |= EDMA_CSR_EDBG; /* Enable Debug */ +#endif +#ifdef CONFIG_IMXRT_EDMA_ERCA + regval |= EDMA_CSR_ERCA; /* Enable Round Robin Channel Arbitration */ +#endif +#ifdef CONFIG_IMXRT_EDMA_ERGA + regval |= EDMA_CSR_ERGA; /* Enable Round Robin Group Arbitration */ +#endif +#ifdef CONFIG_IMXRT_EDMA_HOE + regval |= EDMA_CSR_HAE; /* Halt On Error */ +#endif +#ifdef CONFIG_IMXRT_EDMA_CLM + regval |= EDMA_CSR_GCLC; /* Continuous Link Mode */ +#endif + + putreg32(regval, IMXRT_EDMA_CSR(base)); +} + +/**************************************************************************** + * Name: imxrt_find_free_ch + * + * Description: + * Configure eDMA instance. + * + ****************************************************************************/ + +static struct imxrt_dmach_s * imxrt_find_free_ch(uint16_t dmamux) +{ + struct imxrt_dmach_s *candidate; + uintptr_t base; + unsigned int chndx; + unsigned int offset; + unsigned int max; + + /* eDMA base for MUX */ + + base = imxrt_dmamux_get_dmabase(dmamux); + + /* On RT118x both eDMA3 and eDMA4 have per-channel CH_MUX registers so + * any free channel of the correct engine can be used. + */ + + offset = imxrt_edma_choffset(base); + max = imxrt_edma_chmax(base); + + for (chndx = offset; chndx < max; chndx++) + { + candidate = &g_edma.dmach[chndx]; + if (!candidate->inuse) + { + return candidate; + } + } + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_dma_initialize + * + * Description: + * Initialize the DMA subsystem + * + * Returned Value: + * None + * + ****************************************************************************/ + +void weak_function arm_dma_initialize(void) +{ + struct imxrt_dmach_s *dmach; + uintptr_t base; + int chan; + int i; + + dmainfo("Initialize eDMA\n"); + + /* Configure the instances. */ + + dmach = &g_edma.dmach[0]; + +#ifdef IMXRT_DMA3_BASE + /* Configure eDMA3's LPCG29 (m33_clk_root). That root is already configured + * by the M33 boot ROM so we only need to enable the LPCG. + */ + + imxrt_ccm_gate_on(CCM_LPCG_EDMA3, true); + + imxrt_edma_configure(IMXRT_DMA3_BASE); + + /* Initialize the channel */ + + for (i = 0; i < DMA3_CHANNEL_COUNT; i++, dmach++) + { + dmach->base = IMXRT_DMA3_BASE; + dmach->chan = i; + + irq_attach(IMXRT_IRQ_DMA3_CH0 + i, imxrt_edma_interrupt, dmach); + } +#endif + +#ifdef IMXRT_DMA4_BASE + /* Configure eDMA4's clock root and enable its LPCG. + * + * wakeup_axi_clk_root = SYS_PLL3_OUT (480 MHz) / 2 = 240 MHz. + */ + + imxrt_ccm_configure_root_clock(CCM_CR_WAKEUP_AXI, SYS_PLL3_OUT, 2); + + /* Enable peripheral clock (eDMA4: wakeup_axi_clk_root, LPCG30) */ + + imxrt_ccm_gate_on(CCM_LPCG_EDMA4, true); + + imxrt_edma_configure(IMXRT_DMA4_BASE); + + /* Initialize the channel */ + + for (i = 0; i < DMA4_CHANNEL_COUNT; i++, dmach++) + { + dmach->base = IMXRT_DMA4_BASE; + dmach->chan = i; + + /* Each eDMA4 interrupt is shared by four channels: n, n+1, n+32 and + * n+33. So IRQ (DMA4_CH0_CH1_CH32_CH33 + k) serves the channels + * 2k, 2k+1, 2k+32 and 2k+33, and the 64 channels are covered by the + * 32 lowest channel handles only. Attach every second channel of + * the lower half and pass that channel's handle as the argument. + */ + + if (i < (DMA4_CHANNEL_COUNT / 2) && (i & 0x01) == 0) + { + irq_attach(IMXRT_IRQ_DMA4_CH0_CH1_CH32_CH33 + (i >> 1), + imxrt_edma_interrupt, dmach); + } + } +#endif + +#if CONFIG_IMXRT_EDMA_NTCD > 0 + /* Initialize the list of free TCDs from the pool of pre-allocated TCDs. */ + + imxrt_tcd_initialize(); +#endif + + /* Disable all DMA channel interrupts at the eDMA controller */ + + for (i = 0; i < IMXRT_EDMA_NCHANNELS; i++) + { + /* DMA engine base and TCD channel */ + + base = g_edma.dmach[i].base; + chan = g_edma.dmach[i].chan; + + /* Disable all DMA channels and DMA channel interrupts */ + + putreg32(0, IMXRT_EDMA_TCD(base, chan) + IMXRT_EDMA_CH_CSR_OFFSET); + + /* Clear interrupt if any */ + + putreg32(1, IMXRT_EDMA_TCD(base, chan) + IMXRT_EDMA_CH_INT_OFFSET); + + /* Set all TCD CSR, biter and citer entries to 0 so that + * will be 0 when DONE is not set so that imxrt_dmach_getcount + * reports 0. + */ + + putreg16(0, IMXRT_EDMA_TCD(base, chan) + IMXRT_EDMA_TCD_CSR_OFFSET); + putreg16(0, IMXRT_EDMA_TCD(base, chan) + IMXRT_EDMA_TCD_CITER_OFFSET); + putreg16(0, IMXRT_EDMA_TCD(base, chan) + IMXRT_EDMA_TCD_BITER_OFFSET); + } + +#ifdef IMXRT_DMA3_BASE + /* Clear all pending DMA channel interrupts */ + + putreg32(0xffffffff, IMXRT_EDMA_INT); + + /* Enable the channel interrupts at the NVIC (still disabled at the eDMA + * controller). + */ + + for (i = 0; i < DMA3_IRQ_COUNT; i++) + { + up_enable_irq(IMXRT_IRQ_DMA3_CH0 + i); + } +#endif + +#ifdef IMXRT_DMA4_BASE + /* Clear all pending DMA channel interrupts */ + + putreg32(0xffffffff, IMXRT_EDMA_INT_LOW); + putreg32(0xffffffff, IMXRT_EDMA_INT_HIGH); + + /* Enable the channel interrupts at the NVIC (still disabled at the eDMA + * controller). + */ + + for (i = 0; i < DMA4_IRQ_COUNT; i++) + { + up_enable_irq(IMXRT_IRQ_DMA4_CH0_CH1_CH32_CH33 + i); + } +#endif +} + +/**************************************************************************** + * Name: imxrt_dmach_alloc + * + * Allocate a DMA channel. This function sets aside a DMA channel, + * initializes the DMAMUX for the channel, then gives the caller exclusive + * access to the DMA channel. + * + * Input Parameters: + * + * dmamux - DMAMUX configuration see DMAMUX channel configuration register + * bit-field definitions in hardware/imxrt_dmamux.h. + * Settings include: + * + * DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required) + * DMAMUX_CHCFG_TRIG DMA Channel Trigger Enable (optional) + * DMAMUX_CHCFG_ENBL DMA Mux Channel Enable (required) + * + * A value of zero will disable the DMAMUX channel. + * dchpri - DCHPRI channel priority configuration. See DCHPRI channel + * configuration register bit-field definitions in + * hardware/imxrt_edma.h. Meaningful settings include: + * + * EDMA_DCHPRI_CHPRI Channel Arbitration Priority + * DCHPRI_DPA Disable Preempt Ability + * DCHPRI_ECP Enable Channel Preemption + * + * The power-on default, 0x05, is a reasonable choice. + * + * Returned Value: + * If a DMA channel is available, this function returns a non-NULL, void* + * DMA channel handle. NULL is returned on any failure. + * + ****************************************************************************/ + +DMACH_HANDLE imxrt_dmach_alloc(uint32_t dmamux, uint8_t dchpri) +{ + struct imxrt_dmach_s *dmach; + uintptr_t base; + uint32_t regval; + int ret; + + /* Search for an available DMA channel */ + + dmach = NULL; + ret = nxmutex_lock(&g_edma.chlock); + if (ret < 0) + { + return NULL; + } + + /* Find channel for this DMA MUX */ + + dmach = imxrt_find_free_ch(dmamux); + if (dmach) + { + dmach->inuse = true; + dmach->state = IMXRT_DMA_IDLE; + dmach->dmamux = dmamux & EDMA_MUX_MASK; + + /* TCD register base */ + + base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); + + /* Clear any pending interrupts on the channel */ + + putreg32(0, base + IMXRT_EDMA_CH_CSR_OFFSET); + + /* Make sure that the channel is disabled. */ + + putreg32(EDMA_CH_INT, base + IMXRT_EDMA_CH_INT_OFFSET); + + regval = getreg32(base + IMXRT_EDMA_CH_SBR_OFFSET); + regval |= EDMA_CH_SBR_EMI | EDMA_CH_SBR_SEC | EDMA_CH_SBR_PAL; + putreg32(regval, base + IMXRT_EDMA_CH_SBR_OFFSET); + + /* Set the DMAMUX source */ + + if (imxrt_edma_tcdhasmux(dmach->base)) + { + /* Set reset value first to CH MUX */ + + putreg8(0, base + IMXRT_EDMA_CH_MUX_OFFSET); + dmainfo("CH%d: MUX:%u->%p\n", dmach->chan, dmach->dmamux, + (void *)(base + IMXRT_EDMA_CH_MUX_OFFSET)); + putreg8(dmach->dmamux, base + IMXRT_EDMA_CH_MUX_OFFSET); + } + } + + nxmutex_unlock(&g_edma.chlock); + + /* Show the result of the allocation */ + + if (dmach != NULL) + { + dmainfo("CH%d: returning dmach: %p\n", dmach->chan, dmach); + } + else + { + dmaerr("ERROR: Failed allocate eDMA channel\n"); + } + + return (DMACH_HANDLE)dmach; +} + +/**************************************************************************** + * Name: imxrt_dmach_free + * + * Description: + * Release a DMA channel. NOTE: The 'handle' used in this argument must + * NEVER be used again until imxrt_dmach_alloc() is called again to + * re-gain a valid handle. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imxrt_dmach_free(DMACH_HANDLE handle) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + uintptr_t base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); + + dmainfo("dmach: %p\n", dmach); + DEBUGASSERT(dmach != NULL && dmach->inuse && + dmach->state != IMXRT_DMA_ACTIVE); + + /* Mark the channel no longer in use. Clearing the inuse flag is an atomic + * operation and so should be safe. + */ + + dmach->flags = 0; + dmach->inuse = false; /* No longer in use */ + dmach->state = IMXRT_DMA_IDLE; /* Better not be active! */ + + /* Make sure that the channel is disabled. */ + + putreg32(EDMA_CH_INT, base + IMXRT_EDMA_CH_INT_OFFSET); + + /* Disable the associated DMAMUX */ + + if (imxrt_edma_tcdhasmux(dmach->base)) + { + putreg8(0, base + IMXRT_EDMA_CH_MUX_OFFSET); + } +} + +/**************************************************************************** + * Name: imxrt_dmach_xfrsetup + * + * Description: + * This function adds the eDMA transfer to the DMA sequence. The request + * is setup according to the content of the transfer configuration + * structure. For "normal" DMA, imxrt_dmach_xfrsetup is called only once. + * Scatter/gather DMA is accomplished by calling this function repeatedly, + * once for each transfer in the sequence. Scatter/gather DMA processing + * is enabled automatically when the second transfer configuration is + * received. + * + * This function may be called multiple times to handle multiple, + * discontinuous transfers (scatter-gather) + * + * Input Parameters: + * handle - DMA channel handle created by imxrt_dmach_alloc() + * config - A DMA transfer configuration instance, populated by the + * The content of 'config' describes the transfer + * + * Returned Value + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int imxrt_dmach_xfrsetup(DMACH_HANDLE handle, + const struct imxrt_edma_xfrconfig_s *config) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + uintptr_t base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); +#if CONFIG_IMXRT_EDMA_NTCD > 0 + struct imxrt_edmatcd_s *tcd; + struct imxrt_edmatcd_s *prev; + uint16_t mask = config->flags & EDMA_CONFIG_INTMAJOR ? 0 : + EDMA_TCD_CSR_INTMAJOR; + uint16_t regval16; +#else + uint32_t regval32; +#endif + + DEBUGASSERT(dmach != NULL); + dmainfo("dmach%u: %p config: %p\n", dmach->chan, dmach, config); + + dmach->flags = config->flags; + +#if CONFIG_IMXRT_EDMA_NTCD > 0 + /* Scatter/gather DMA is supported */ + + /* Allocate a TCD, waiting if necessary */ + + tcd = imxrt_tcd_alloc(); + + /* Configure current TCD block transfer. */ + + imxrt_tcd_configure(tcd, config); + + /* Enable the interrupt when the major iteration count completes for this + * TCD. For "normal" DMAs, this will correspond to the DMA DONE + * interrupt; for scatter gather DMAs, multiple interrupts will be + * generated with the final being the DONE interrupt. + */ + + tcd->csr |= EDMA_TCD_CSR_INTMAJOR; + + /* Is this the first descriptor in the list? */ + + if (dmach->head == NULL) + { + /* Yes.. add it to the list */ + + dmach->head = tcd; + dmach->tail = tcd; + + /* And instantiate the first TCD in the DMA channel TCD registers. */ + + imxrt_tcd_instantiate(dmach, tcd); + } + else + { + /* Cannot mix transfer types */ + + if (dmach->flags & EDMA_CONFIG_LOOP_MASK) + { + imxrt_tcd_free(tcd); + return -EINVAL; + } + + /* Chain from previous descriptor in the list. */ + + /* Enable scatter/gather feature in the previous TCD. */ + + prev = dmach->tail; + regval16 = prev->csr; + regval16 &= ~(EDMA_TCD_CSR_DREQ | mask); + regval16 |= EDMA_TCD_CSR_ESG; + prev->csr = regval16; + + prev->dlastsga = (uint32_t)((uintptr_t)tcd); + dmach->tail = tcd; + + /* Clean cache associated with the previous TCD memory */ + + up_clean_dcache((uintptr_t)prev, + (uintptr_t)prev + sizeof(struct imxrt_edmatcd_s)); + + /* Check if the TCD block in the DMA channel registers is the same as + * the previous previous TCD. This can happen if the previous TCD was + * the first TCD and has already be loaded into the TCD registers. + */ + + if (dmach->head == prev) + { + /* Enable scatter/gather also in the TCD registers. */ + + regval16 = getreg16(base + IMXRT_EDMA_TCD_CSR_OFFSET); + regval16 &= ~(EDMA_TCD_CSR_DREQ | mask); + regval16 |= EDMA_TCD_CSR_ESG; + putreg16(regval16, base + IMXRT_EDMA_TCD_CSR_OFFSET); + + putreg32((uint32_t)((uintptr_t)tcd), + base + IMXRT_EDMA_TCD_DLAST_SGA_OFFSET); + } + } + + /* Clean cache associated with the TCD memory */ + + up_clean_dcache((uintptr_t)tcd, + (uintptr_t)tcd + sizeof(struct imxrt_edmatcd_s)); +#else + + /* Scatter/gather DMA is NOT supported */ + + /* Check if eDMA is busy: if the channel has started transfer, CSR will be + * non-zero. + */ + + regval32 = getreg32(base + IMXRT_EDMA_CH_CSR_OFFSET); + + if (regval32 != 0 && (regval32 & EDMA_CH_CSR_DONE) == 0) + { + return -EBUSY; + } + + /* Configure channel TCD registers to the values specified in config. */ + + imxrt_tcd_configure((struct imxrt_edmatcd_s *) + (base + IMXRT_EDMA_TCD_SADDR_OFFSET), config); + + /* Enable the DONE interrupt when the major iteration count completes. */ + + modifyreg16(base + IMXRT_EDMA_TCD_CSR_OFFSET, 0, EDMA_TCD_CSR_INTMAJOR); +#endif + + dmach->state = IMXRT_DMA_CONFIGURED; + return OK; +} + +/**************************************************************************** + * Name: imxrt_dmach_start + * + * Description: + * Start the DMA transfer. This function should be called after the final + * call to imxrt_dmach_xfrsetup() in order to avoid race conditions. + * + * At the conclusion of each major DMA loop, a callback to the user + * provided function is made: |For "normal" DMAs, this will correspond to + * the DMA DONE interrupt; for scatter gather DMAs, + * this will be generated with the final TCD. + * + * At the conclusion of the DMA, the DMA channel is reset, all TCDs are + * freed, and the callback function is called with the the success/fail + * result of the DMA. + * + * NOTE: On Rx DMAs (peripheral-to-memory or memory-to-memory), it is + * necessary to invalidate the destination memory. That is not done + * automatically by the DMA module. Invalidation of the destination memory + * regions is the responsibility of the caller. + * + * Input Parameters: + * handle - DMA channel handle created by imxrt_dmach_alloc() + * callback - The callback to be invoked when the DMA is completes or is + * aborted. + * arg - An argument that accompanies the callback + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, + void *arg) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + uintptr_t base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); + irqstate_t flags; + uint32_t regval; + uint8_t chan; + + DEBUGASSERT(dmach != NULL && dmach->state == IMXRT_DMA_CONFIGURED); + chan = dmach->chan; + dmainfo("dmach%u: %p callback: %p arg: %p\n", chan, dmach, callback, arg); + + /* Save the callback info. This will be invoked when the DMA completes */ + + flags = spin_lock_irqsave(&g_edma.lock); + dmach->callback = callback; + dmach->arg = arg; + +#if CONFIG_IMXRT_EDMA_NTCD > 0 + /* Although it is not recommended, it might be possible to call this + * function multiple times while adding TCDs on the fly. + */ + + if (dmach->state != IMXRT_DMA_ACTIVE) +#endif + { + dmach->state = IMXRT_DMA_ACTIVE; + + regval = getreg32(base + IMXRT_EDMA_CH_CSR_OFFSET); + regval |= EDMA_CH_CSR_ERQ | EDMA_CH_CSR_EEI; + putreg32(regval, base + IMXRT_EDMA_CH_CSR_OFFSET); + + if ((dmach->flags & EDMA_CONFIG_SWSTART) != 0) + { + putreg16(getreg16(base + IMXRT_EDMA_TCD_CSR_OFFSET) | + EDMA_TCD_CSR_START, + base + IMXRT_EDMA_TCD_CSR_OFFSET); + } + } + + spin_unlock_irqrestore(&g_edma.lock, flags); + return OK; +} + +/**************************************************************************** + * Name: imxrt_dmach_stop + * + * Description: + * Cancel the DMA. After imxrt_dmach_stop() is called, the DMA channel + * is reset, all TCDs are freed, and imxrt_dmarx/txsetup() must be called + * before imxrt_dmach_start() can be called again. + * + * Input Parameters: + * handle - DMA channel handle created by imxrt_dmach_alloc() + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void imxrt_dmach_stop(DMACH_HANDLE handle) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + + dmainfo("dmach: %p\n", dmach); + DEBUGASSERT(dmach != NULL); + + imxrt_dmaterminate(dmach, -EINTR); +} + +/**************************************************************************** + * Name: imxrt_dmach_getcount + * + * Description: + * This function checks the TCD (Task Control Descriptor) status for a + * specified eDMA channel and returns the the number of major loop counts + * that have not finished. + * + * NOTES: + * 1. This function can only be used to get unfinished major loop count of + * transfer without the next TCD, or it might be inaccuracy. + * 2. The unfinished/remaining transfer bytes cannot be obtained directly + * from registers while the channel is running. + * + * Because to calculate the remaining bytes, the initial NBYTES configured + * in DMA_TCDn_NBYTES_MLNO register is needed while the eDMA IP does not + * support getting it while a channel is active. In another words, the + * NBYTES value reading is always the actual (decrementing) NBYTES value + * the dma_engine is working with while a channel is running. + * Consequently, to get the remaining transfer bytes, a software-saved + * initial value of NBYTES (for example copied before enabling the channel) + * is needed. The formula to calculate it is shown below: + * + * RemainingBytes = RemainingMajorLoopCount * + * NBYTES(initially configured) + * + * Input Parameters: + * handle - DMA channel handle created by imxrt_dmach_alloc() + * + * Returned Value: + * Major loop count which has not been transferred yet for the current TCD. + * + ****************************************************************************/ + +unsigned int imxrt_dmach_getcount(DMACH_HANDLE handle) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + uintptr_t base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); + unsigned int remaining = 0; + uintptr_t regval32; + uint16_t regval16; + + DEBUGASSERT(dmach != NULL); + + /* If the DMA is done, then the remaining count is zero */ + + regval32 = getreg32(base + IMXRT_EDMA_CH_CSR_OFFSET); + + if ((regval32 & EDMA_CH_CSR_DONE) == 0) + { + /* Calculate the unfinished bytes */ + + regval16 = getreg16(base + IMXRT_EDMA_TCD_CITER_OFFSET); + + if ((regval16 & EDMA_TCD_CITER_ELINK) != 0) + { + remaining = (regval16 & EDMA_TCD_CITER_MASK_ELINK) >> + EDMA_TCD_CITER_SHIFT; + } + else + { + remaining = (regval16 & EDMA_TCD_CITER_MASK) >> + EDMA_TCD_CITER_SHIFT; + } + } + + return remaining; +} + +/**************************************************************************** + * Name: imxrt_dmach_idle + * + * Description: + * This function checks if the dma is idle + * + * Returned Value: + * 0 - if idle + * !0 - not + * + ****************************************************************************/ + +unsigned int imxrt_dmach_idle(DMACH_HANDLE handle) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + + return dmach->state == IMXRT_DMA_IDLE ? 0 : -1; +} + +/**************************************************************************** + * Name: imxrt_dmasample + * + * Description: + * Sample DMA register contents + * + * Assumptions: + * - DMA handle allocated by imxrt_dmach_alloc() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imxrt_dmasample(DMACH_HANDLE handle, struct imxrt_dmaregs_s *regs) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + unsigned int chan; + irqstate_t flags; + uintptr_t base = IMXRT_EDMA_TCD(dmach->base, dmach->chan); + + DEBUGASSERT(dmach != NULL && regs != NULL); + chan = dmach->chan; + regs->chan = chan; + + /* eDMA Global Registers */ + + flags = spin_lock_irqsave(&g_edma.lock); + + /* REVISIT: eDMA4 does not show INT_HIGH / HRS_HIGH values correctly */ + + regs->cr = getreg32(IMXRT_EDMA_CSR(base)); /* Control */ + regs->es = getreg32(IMXRT_EDMA_ES(base)); /* Error Status */ + regs->req = getreg32(IMXRT_EDMA_INT); /* Interrupt Request */ + regs->hrs = getreg32(IMXRT_EDMA_HRS); /* Hardware Request Status */ + + /* eDMA TCD */ + + regs->saddr = getreg32(base + IMXRT_EDMA_TCD_SADDR_OFFSET); + regs->soff = getreg16(base + IMXRT_EDMA_TCD_SOFF_OFFSET); + regs->attr = getreg16(base + IMXRT_EDMA_TCD_ATTR_OFFSET); + regs->nbml = getreg32(base + IMXRT_EDMA_TCD_NBYTES_OFFSET); + regs->slast = getreg32(base + IMXRT_EDMA_TCD_SLAST_SDA_OFFSET); + regs->daddr = getreg32(base + IMXRT_EDMA_TCD_DADDR_OFFSET); + regs->doff = getreg16(base + IMXRT_EDMA_TCD_DOFF_OFFSET); + regs->citer = getreg16(base + IMXRT_EDMA_TCD_CITER_OFFSET); + regs->dlastsga = getreg32(base + IMXRT_EDMA_TCD_DLAST_SGA_OFFSET); + regs->csr = getreg16(base + IMXRT_EDMA_TCD_CSR_OFFSET); + regs->biter = getreg16(base + IMXRT_EDMA_TCD_BITER_OFFSET); + + /* DMAMUX registers */ + + if (imxrt_edma_tcdhasmux(dmach->base)) + { + regs->dmamux = getreg32(base + IMXRT_EDMA_CH_MUX_OFFSET); + } + else + { + regs->dmamux = 0; + } + + spin_unlock_irqrestore(&g_edma.lock, flags); +} +#endif /* CONFIG_DEBUG_DMA */ + +/**************************************************************************** + * Name: imxrt_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + * Assumptions: + * - DMA handle allocated by imxrt_dmach_alloc() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imxrt_dmadump(const struct imxrt_dmaregs_s *regs, const char *msg) +{ + unsigned int chan; + + DEBUGASSERT(regs != NULL && msg != NULL); + + chan = regs->chan; + DEBUGASSERT(chan < IMXRT_EDMA_NCHANNELS); + + dmainfo("%s\n", msg); + dmainfo(" eDMA Global Registers:\n"); + dmainfo(" CR: %08x\n", (unsigned int)regs->cr); + dmainfo(" ES: %08x\n", (unsigned int)regs->es); + dmainfo(" INT: %08x\n", (unsigned int)regs->req); + dmainfo(" EARS: %08x\n", (unsigned int)regs->hrs); + + /* eDMA Channel registers */ + + dmainfo(" eDMA Channel %u Registers:\n", chan); + dmainfo(" DCHPRI: %02x\n", regs->dchpri); + + /* eDMA TCD */ + + dmainfo(" eDMA Channel %u TCD Registers:\n", chan); + dmainfo(" SADDR: %08x\n", (unsigned int)regs->saddr); + dmainfo(" SOFF: %04x\n", (unsigned int)regs->soff); + dmainfo(" ATTR: %04x\n", (unsigned int)regs->attr); + dmainfo(" NBML: %05x\n", (unsigned int)regs->nbml); + dmainfo(" SLAST: %05x\n", (unsigned int)regs->slast); + dmainfo(" DADDR: %05x\n", (unsigned int)regs->daddr); + dmainfo(" DOFF: %04x\n", (unsigned int)regs->doff); + dmainfo(" CITER: %04x\n", (unsigned int)regs->citer); + dmainfo(" DLASTSGA: %08x\n", (unsigned int)regs->dlastsga); + dmainfo(" CSR: %04x\n", (unsigned int)regs->csr); + dmainfo(" BITER: %04x\n", (unsigned int)regs->biter); + + /* DMAMUX registers */ + + dmainfo(" DMAMUX Channel %u Registers:\n", chan); + dmainfo(" DMAMUX: %08x\n", (unsigned int)regs->dmamux); +} +#endif /* CONFIG_DEBUG_DMA */ +#endif /* CONFIG_IMXRT_EDMA */