diff --git a/arch/arm/src/imxrt/hardware/imxrt_edma.h b/arch/arm/src/imxrt/hardware/imxrt_edma.h index 660521636ae..712a47b5cdd 100644 --- a/arch/arm/src/imxrt/hardware/imxrt_edma.h +++ b/arch/arm/src/imxrt/hardware/imxrt_edma.h @@ -1117,7 +1117,7 @@ #define EDMA_TCD_ATTR_DSIZE_SHIFT (0) /* Bits 0-2: Destination data transfer size */ #define EDMA_TCD_ATTR_DSIZE_MASK (7 << EDMA_TCD_ATTR_DSIZE_SHIFT) -# define EDMA_TCD_ATTR_DSIZE(n) ((uint32_t)(n) << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 8-bit */ +# define EDMA_TCD_ATTR_DSIZE(n) ((uint32_t)(n) << EDMA_TCD_ATTR_DSIZE_SHIFT) # define EDMA_TCD_ATTR_DSIZE_8BIT (TCD_ATTR_SIZE_8BIT << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 8-bit */ # define EDMA_TCD_ATTR_DSIZE_16BIT (TCD_ATTR_SIZE_16BIT << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 16-bit */ # define EDMA_TCD_ATTR_DSIZE_32BIT (TCD_ATTR_SIZE_32BIT << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 32-bit */ @@ -1129,7 +1129,7 @@ # define EDMA_TCD_ATTR_DMOD(n) ((uint32_t)(n) << EDMA_TCD_ATTR_DMOD_SHIFT) #define EDMA_TCD_ATTR_SSIZE_SHIFT (8) /* Bits 8-10: Source data transfer size */ #define EDMA_TCD_ATTR_SSIZE_MASK (7 << EDMA_TCD_ATTR_SSIZE_SHIFT) -# define EDMA_TCD_ATTR_SSIZE(n) ((uint32_t)(n) << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 8-bit */ +# define EDMA_TCD_ATTR_SSIZE(n) ((uint32_t)(n) << EDMA_TCD_ATTR_SSIZE_SHIFT) # define EDMA_TCD_ATTR_SSIZE_8BIT (TCD_ATTR_SIZE_8BIT << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 8-bit */ # define EDMA_TCD_ATTR_SSIZE_16BIT (TCD_ATTR_SIZE_16BIT << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 16-bit */ # define EDMA_TCD_ATTR_SSIZE_32BIT (TCD_ATTR_SIZE_32BIT << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-bit */ @@ -1251,38 +1251,23 @@ * Public Types ****************************************************************************/ -/* In-memory representation of - * the 32-byte Transfer Control Descriptor (TCD) +/* Hardware representation of the 32-byte Transfer + * Control Descriptor (TCD) */ struct imxrt_edmatcd_s { - uint32_t saddr; /* Offset: 0x0000 TCD Source Address */ -#ifdef CONFIG_ENDIAN_BIG - uint16_t attr; /* Offset: 0x0004 TCD Transfer Attributes */ - uint16_t soff; /* Offset: 0x0006 TCD Signed Source Address Offset */ -#else - uint16_t soff; /* Offset: 0x0004 TCD Signed Source Address Offset */ - uint16_t attr; /* Offset: 0x0006 TCD Transfer Attributes */ -#endif - 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 */ -#ifdef CONFIG_ENDIAN_BIG - uint16_t citer; /* Offset: 0x0014 TCD Current Minor Loop Link, Major Loop Count */ - uint16_t doff; /* Offset: 0x0016 TCD Signed Destination Address Offset */ -#else - uint16_t doff; /* Offset: 0x0014 TCD Signed Destination Address Offset */ - uint16_t citer; /* Offset: 0x0016 TCD Current Minor Loop Link, Major Loop Count */ -#endif - uint32_t dlastsga; /* Offset: 0x0018 TCD Last Destination Address Adjustment/Scatter Gather Address */ -#ifdef CONFIG_ENDIAN_BIG - uint16_t biter; /* Offset: 0x001c TCD Beginning Minor Loop Link, Major Loop Count */ - uint16_t csr; /* Offset: 0x001e TCD Control and Status */ -#else - uint16_t csr; /* Offset: 0x001c TCD Control and Status */ - uint16_t biter; /* Offset: 0x001e TCD Beginning Minor Loop Link, Major Loop Count */ -#endif + 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 */ }; #endif /* __ARCH_ARM_SRC_IMXRT_HARDWARE_IMXRT_EDMA_H */ diff --git a/arch/arm/src/imxrt/imxrt_edma.c b/arch/arm/src/imxrt/imxrt_edma.c index 3ee1fe8a8cd..d8b82e90d6b 100644 --- a/arch/arm/src/imxrt/imxrt_edma.c +++ b/arch/arm/src/imxrt/imxrt_edma.c @@ -86,22 +86,16 @@ */ #ifdef CONFIG_ARMV7M_DCACHE -/* Align to the cache line size which we assume is >= 8 */ - -# 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) - +# define EDMA_ALIGN ARMV7M_DCACHE_LINESIZE #else -/* Special alignment is not required in this case, - * but we will align to 8-bytes - */ +/* 32 byte alignment for TCDs is required for scatter gather */ -# define EDMA_ALIGN 8 -# define EDMA_ALIGN_MASK 7 -# define EDMA_ALIGN_UP(n) (((n) + 7) & ~7) +#define EDMA_ALIGN 32 #endif +#define EDMA_ALIGN_MASK (EDMA_ALIGN - 1) +#define EDMA_ALIGN_UP(n) (((n) + EDMA_ALIGN_MASK) & ~EDMA_ALIGN_MASK) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -119,10 +113,10 @@ enum imxrt_dmastate_e struct imxrt_dmach_s { - uint8_t chan; /* DMA channel number (0-IMXRT_EDMA_NCHANNELS) */ - bool inuse; /* true: The DMA channel is in use */ - uint8_t ttype; /* Transfer type: M2M, M2P, P2M, or P2P */ - uint8_t state; /* Channel state. See enum imxrt_dmastate_e */ + uint8_t chan; /* DMA channel number (0-IMXRT_EDMA_NCHANNELS) */ + bool inuse; /* true: The DMA channel is in use */ + uint8_t state; /* Channel state. See enum imxrt_dmastate_e */ + uint32_t dmamux; /* The DMAMUX channel selection */ uint32_t flags; /* DMA channel flags */ edma_callback_t callback; /* Callback invoked when the DMA completes */ void *arg; /* Argument passed to callback function */ @@ -338,17 +332,13 @@ static inline void imxrt_tcd_chanlink(uint8_t flags, if (linkch == NULL || flags == EDMA_CONFIG_LINKTYPE_LINKNONE) { -#if 0 /* Already done */ /* No link or no link channel provided */ - /* Disable minor links */ - tcd->citer &= ~EDMA_TCD_CITER_ELINK; - tcd->biter &= ~EDMA_TCD_BITER_ELINK; + /* Disable minor links is done in imxrt_tcd_configure */ /* Disable major link */ tcd->csr &= ~EDMA_TCD_CSR_MAJORELINK; -#endif } else if (flags == EDMA_CONFIG_LINKTYPE_MINORLINK) /* Minor link config */ { @@ -404,13 +394,16 @@ static inline void imxrt_tcd_configure(struct imxrt_edmatcd_s *tcd, tcd->attr = EDMA_TCD_ATTR_SSIZE(config->ssize) | /* Transfer Attributes */ EDMA_TCD_ATTR_DSIZE(config->dsize); tcd->nbytes = config->nbytes; - tcd->slast = tcd->slast; + tcd->slast = config->flags & EDMA_CONFIG_LOOPSRC ? -config->iter : 0; tcd->daddr = config->daddr; tcd->doff = config->doff; tcd->citer = config->iter & EDMA_TCD_CITER_CITER_MASK; tcd->biter = config->iter & EDMA_TCD_BITER_BITER_MASK; - tcd->csr = EDMA_TCD_CSR_DREQ; /* Assume last transfer */ - tcd->dlastsga = 0; + 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 : 0; /* And special case flags */ @@ -438,6 +431,10 @@ static void imxrt_tcd_instantiate(struct imxrt_dmach_s *dmach, /* 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); @@ -448,9 +445,6 @@ static void imxrt_tcd_instantiate(struct imxrt_dmach_s *dmach, putreg16(tcd->citer, base + IMXRT_EDMA_TCD_CITER_ELINK_OFFSET); putreg32(tcd->dlastsga, base + IMXRT_EDMA_TCD_DLASTSGA_OFFSET); - /* Clear DONE bit first, otherwise ESG cannot be set */ - - putreg16(0, base + IMXRT_EDMA_TCD_CSR_OFFSET); putreg16(tcd->csr, base + IMXRT_EDMA_TCD_CSR_OFFSET); putreg16(tcd->biter, base + IMXRT_EDMA_TCD_BITER_ELINK_OFFSET); @@ -486,40 +480,33 @@ static void imxrt_dmaterminate(struct imxrt_dmach_s *dmach, int result) regval8 = EDMA_CERQ(chan); putreg8(regval8, IMXRT_EDMA_CERQ); - /* 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. - */ - regaddr = IMXRT_EDMA_TCD_CSR(chan); putreg16(0, regaddr); /* Cancel next TCD transfer. */ regaddr = IMXRT_EDMA_TCD_DLASTSGA(chan); - putreg16(0, regaddr); + putreg32(0, regaddr); #if CONFIG_IMXRT_EDMA_NTCD > 0 /* Return all allocated TCDs to the free list */ for (tcd = dmach->head; tcd != NULL; tcd = next) { - next = (struct imxrt_edmatcd_s *)tcd->dlastsga; - imxrt_tcd_free(tcd); + /* 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 *)tcd->dlastsga; + + imxrt_tcd_free(tcd); } dmach->head = NULL; dmach->tail = NULL; #endif - /* Check for an Rx (memory-to-peripheral/memory-to-memory) DMA transfer */ - - if (dmach->ttype == EDMA_MEM2MEM || dmach->ttype == EDMA_PERIPH2MEM) - { - /* Invalidate the cache to force reloads from memory. */ -#warning Missing logic - } - /* Perform the DMA complete callback */ if (dmach->callback) @@ -549,18 +536,19 @@ static void imxrt_dmaterminate(struct imxrt_dmach_s *dmach, int result) * ****************************************************************************/ -static void imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) +static int imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) { uintptr_t regaddr; - uint32_t regval32; - uint16_t regval16; - uint8_t regval8; - uint8_t chan; - int result; + uint32_t regval32; + uint16_t regval16; + uint8_t regval8; + uint8_t chan; + int result; /* Check for an eDMA pending interrupt on this channel */ chan = dmach->chan; + regval32 = getreg32(IMXRT_EDMA_INT); if ((regval32 & EDMA_INT(chan)) != 0) @@ -574,7 +562,7 @@ static void imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) /* Clear the pending eDMA channel interrupt */ regval8 = EDMA_CINT(chan); - putreg32(regval8, IMXRT_EDMA_CINT); + putreg8(regval8, IMXRT_EDMA_CINT); /* Get the eDMA TCD Control and Status register value. */ @@ -594,7 +582,7 @@ static void imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) else { #if CONFIG_IMXRT_EDMA_NTCD > 0 - /* Perform the end-of-major-cycle DMA callback */ + /* Perform the half or end-of-major-cycle DMA callback */ if (dmach->callback != NULL) { @@ -602,7 +590,7 @@ static void imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) false, OK); } - return; + return OK; #else /* Otherwise the interrupt was not expected! */ @@ -613,8 +601,18 @@ static void imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) /* Terminate the transfer when it is done. */ - imxrt_dmaterminate(dmach, result); + 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; } /**************************************************************************** @@ -690,7 +688,7 @@ static int imxrt_error_interrupt(int irq, void *context, void *arg) /* Clear the pending error interrupt status. */ regval8 = EDMA_CERR(chan); - putreg32(regval8, IMXRT_EDMA_CERR); + putreg8(regval8, IMXRT_EDMA_CERR); /* Remove the bit from the sample ERR register so that perhaps we * can exit this loop early. @@ -788,22 +786,11 @@ void weak_function arm_dma_initialize(void) * NOTE that there are only 16 vectors for 32 DMA channels. */ - irq_attach(IMXRT_IRQ_EDMA0_16, imxrt_edma_interrupt, &g_edma.dmach[0]); - irq_attach(IMXRT_IRQ_EDMA1_17, imxrt_edma_interrupt, &g_edma.dmach[1]); - irq_attach(IMXRT_IRQ_EDMA2_18, imxrt_edma_interrupt, &g_edma.dmach[2]); - irq_attach(IMXRT_IRQ_EDMA3_19, imxrt_edma_interrupt, &g_edma.dmach[3]); - irq_attach(IMXRT_IRQ_EDMA4_20, imxrt_edma_interrupt, &g_edma.dmach[4]); - irq_attach(IMXRT_IRQ_EDMA5_21, imxrt_edma_interrupt, &g_edma.dmach[5]); - irq_attach(IMXRT_IRQ_EDMA6_22, imxrt_edma_interrupt, &g_edma.dmach[6]); - irq_attach(IMXRT_IRQ_EDMA7_23, imxrt_edma_interrupt, &g_edma.dmach[7]); - irq_attach(IMXRT_IRQ_EDMA8_24, imxrt_edma_interrupt, &g_edma.dmach[8]); - irq_attach(IMXRT_IRQ_EDMA9_25, imxrt_edma_interrupt, &g_edma.dmach[9]); - irq_attach(IMXRT_IRQ_EDMA10_26, imxrt_edma_interrupt, &g_edma.dmach[10]); - irq_attach(IMXRT_IRQ_EDMA11_27, imxrt_edma_interrupt, &g_edma.dmach[11]); - irq_attach(IMXRT_IRQ_EDMA12_28, imxrt_edma_interrupt, &g_edma.dmach[12]); - irq_attach(IMXRT_IRQ_EDMA13_29, imxrt_edma_interrupt, &g_edma.dmach[13]); - irq_attach(IMXRT_IRQ_EDMA14_30, imxrt_edma_interrupt, &g_edma.dmach[14]); - irq_attach(IMXRT_IRQ_EDMA15_31, imxrt_edma_interrupt, &g_edma.dmach[15]); + for (i = 0; i < IMXRT_EDMA_NCHANNELS / 2; i++) + { + irq_attach(IMXRT_IRQ_EDMA0_16 + i, + imxrt_edma_interrupt, &g_edma.dmach[i]); + } /* Attach the DMA error interrupt vector */ @@ -822,6 +809,14 @@ void weak_function arm_dma_initialize(void) regaddr = IMXRT_EDMA_TCD_CSR(i); putreg16(0, regaddr); + + /* Set all TCD entries to 0 so that biter and citer + * will be 0 when DONE is not set so that imxrt_dmach_getcount + * reports 0. + */ + + memset((void *)IMXRT_EDMA_TCD_BASE(i), 0, + sizeof(struct imxrt_edmatcd_s)); } /* Clear all pending DMA channel interrupts */ @@ -832,22 +827,10 @@ void weak_function arm_dma_initialize(void) * controller). */ - up_enable_irq(IMXRT_IRQ_EDMA0_16); - up_enable_irq(IMXRT_IRQ_EDMA1_17); - up_enable_irq(IMXRT_IRQ_EDMA2_18); - up_enable_irq(IMXRT_IRQ_EDMA3_19); - up_enable_irq(IMXRT_IRQ_EDMA4_20); - up_enable_irq(IMXRT_IRQ_EDMA5_21); - up_enable_irq(IMXRT_IRQ_EDMA6_22); - up_enable_irq(IMXRT_IRQ_EDMA7_23); - up_enable_irq(IMXRT_IRQ_EDMA8_24); - up_enable_irq(IMXRT_IRQ_EDMA9_25); - up_enable_irq(IMXRT_IRQ_EDMA10_26); - up_enable_irq(IMXRT_IRQ_EDMA11_27); - up_enable_irq(IMXRT_IRQ_EDMA12_28); - up_enable_irq(IMXRT_IRQ_EDMA13_29); - up_enable_irq(IMXRT_IRQ_EDMA14_30); - up_enable_irq(IMXRT_IRQ_EDMA15_31); + for (i = 0; i < IMXRT_EDMA_NCHANNELS / 2; i++) + { + up_enable_irq(IMXRT_IRQ_EDMA0_16 + i); + } /* Enable the DMA error interrupt */ @@ -914,6 +897,7 @@ DMACH_HANDLE imxrt_dmach_alloc(uint32_t dmamux, uint8_t dchpri) dmach = candidate; dmach->inuse = true; dmach->state = IMXRT_DMA_IDLE; + dmach->dmamux = dmamux; /* Clear any pending interrupts on the channel */ @@ -926,10 +910,9 @@ DMACH_HANDLE imxrt_dmach_alloc(uint32_t dmamux, uint8_t dchpri) regval8 = EDMA_CERQ(chndx); putreg8(regval8, IMXRT_EDMA_CERQ); - /* Set the DMAMUX register associated with this channel */ + /* Disable the associated DMAMUX for now */ - regaddr = IMXRT_DMAMUX_CHCFG(chndx); - putreg32(dmamux, regaddr); + putreg32(0, IMXRT_DMAMUX_CHCFG(chndx)); break; } } @@ -966,7 +949,6 @@ DMACH_HANDLE imxrt_dmach_alloc(uint32_t dmamux, uint8_t dchpri) void imxrt_dmach_free(DMACH_HANDLE handle) { struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; - uintptr_t regaddr; uint8_t regval8; dmainfo("dmach: %p\n", dmach); @@ -988,8 +970,7 @@ void imxrt_dmach_free(DMACH_HANDLE handle) /* Disable the associated DMAMUX */ - regaddr = IMXRT_DMAMUX_CHCFG(dmach->chan); - putreg32(0, regaddr); + putreg32(0, IMXRT_DMAMUX_CHCFG(dmach->chan)); } /**************************************************************************** @@ -1018,19 +999,23 @@ void imxrt_dmach_free(DMACH_HANDLE handle) * ****************************************************************************/ -int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, +int imxrt_dmach_xfrsetup(DMACH_HANDLE handle, const struct imxrt_edma_xfrconfig_s *config) { struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; #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; #endif uintptr_t regaddr; uint16_t regval16; DEBUGASSERT(dmach != NULL); - dmainfo("dmach%u: %p config: %p\n", dmach, config); + 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 */ @@ -1059,7 +1044,6 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, dmach->head = tcd; dmach->tail = tcd; - dmach->ttype = config->ttype; /* And instantiate the first TCD in the DMA channel TCD registers. */ @@ -1067,11 +1051,9 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, } else { - /* Cannot mix transfer types (only because of cache-related operations. - * this restriction could be removed with some effort). - */ + /* Cannot mix transfer types */ - if (dmach->ttype != config->ttype) + if (dmach->flags & EDMA_CONFIG_LOOP_MASK) { imxrt_tcd_free(tcd); return -EINVAL; @@ -1083,8 +1065,9 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, prev = dmach->tail; regval16 = prev->csr; - regval16 &= ~EDMA_TCD_CSR_DREQ; + regval16 &= ~(EDMA_TCD_CSR_DREQ | mask); regval16 |= EDMA_TCD_CSR_ESG; + prev->csr = regval16; prev->dlastsga = (uint32_t)tcd; @@ -1106,7 +1089,7 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, regaddr = IMXRT_EDMA_TCD_CSR(dmach->chan); regval16 = getreg16(regaddr); - regval16 &= ~EDMA_TCD_CSR_DREQ; + regval16 &= ~(EDMA_TCD_CSR_DREQ | mask); regval16 |= EDMA_TCD_CSR_ESG; putreg16(regval16, regaddr); @@ -1145,34 +1128,9 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, modifyreg16(regaddr, 0, EDMA_TCD_CSR_INTMAJOR); #endif - /* Check for an Rx (memory-to-peripheral/memory-to-memory) DMA transfer */ + /* Set the DMAMUX source and enable and optional trigger */ - if (dmach->ttype == EDMA_MEM2MEM || dmach->ttype == EDMA_PERIPH2MEM) - { - /* Invalidate caches associated with the destination DMA memory. - * REVISIT: nbytes is the number of bytes transferred on each - * minor loop. The following is only valid when the major loop - * is one. - */ - - up_invalidate_dcache((uintptr_t)config->daddr, - (uintptr_t)config->daddr + config->nbytes); - } - - /* Check for an Tx (peripheral-to-memory/memory-to-memory) DMA transfer */ - - if (dmach->ttype == EDMA_MEM2MEM || dmach->ttype == EDMA_MEM2PERIPH) - { - /* Clean caches associated with the source DMA memory. - * REVISIT: nbytes is the number of bytes transferred on each - * minor loop. The following is only valid when the major loop - * is one. - */ -#warning Missing logic - - up_clean_dcache((uintptr_t)config->saddr, - (uintptr_t)config->saddr + config->nbytes); - } + putreg32(dmach->dmamux, IMXRT_DMAMUX_CHCFG(dmach->chan)); dmach->state = IMXRT_DMA_CONFIGURED; return OK; @@ -1185,10 +1143,10 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, * 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, multiple interrupts will be - * generated with the final being the DONE interrupt. + * 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 @@ -1221,14 +1179,13 @@ int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, DEBUGASSERT(dmach != NULL && dmach->state == IMXRT_DMA_CONFIGURED); chan = dmach->chan; - dmainfo("dmach%u: %p callback: %p arg: %p\n", dmach, chan, callback, arg); + 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(NULL); dmach->callback = callback; dmach->arg = arg; - dmach->state = IMXRT_DMA_ACTIVE; #if CONFIG_IMXRT_EDMA_NTCD > 0 /* Although it is not recommended, it might be possible to call this @@ -1238,6 +1195,8 @@ int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, if (dmach->state != IMXRT_DMA_ACTIVE) #endif { + dmach->state = IMXRT_DMA_ACTIVE; + /* Enable channel ERROR interrupts */ regval8 = EDMA_SEEI(chan); @@ -1246,7 +1205,7 @@ int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, /* Enable the DMA request for this channel */ regval8 = EDMA_SERQ(chan); - putreg8(regval8, IMXRT_EDMA_SERQ_OFFSET); + putreg8(regval8, IMXRT_EDMA_SERQ); } spin_unlock_irqrestore(NULL, flags); @@ -1315,7 +1274,7 @@ void imxrt_dmach_stop(DMACH_HANDLE handle) * ****************************************************************************/ -unsigned int imxrt_dmach_getcount(DMACH_HANDLE *handle) +unsigned int imxrt_dmach_getcount(DMACH_HANDLE handle) { struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; unsigned int remaining = 0; diff --git a/arch/arm/src/imxrt/imxrt_edma.h b/arch/arm/src/imxrt/imxrt_edma.h index 04e5fce1f82..39d89895a5e 100644 --- a/arch/arm/src/imxrt/imxrt_edma.h +++ b/arch/arm/src/imxrt/imxrt_edma.h @@ -121,6 +121,18 @@ # define EDMA_CONFIG_LINKTYPE_MINORLINK (1 << EDMA_CONFIG_LINKTYPE_SHIFT) /* Channel link after each minor loop */ # define EDMA_CONFIG_LINKTYPE_MAJORLINK (2 << EDMA_CONFIG_LINKTYPE_SHIFT) /* Channel link when major loop count exhausted */ +#define EDMA_CONFIG_LOOP_SHIFT (2) /* Bits 2-3: Loop type */ +#define EDMA_CONFIG_LOOP_MASK (3 << EDMA_CONFIG_LOOP_SHIFT) +# define EDMA_CONFIG_LOOPNONE (0 << EDMA_CONFIG_LOOP_SHIFT) /* No looping */ +# define EDMA_CONFIG_LOOPSRC (1 << EDMA_CONFIG_LOOP_SHIFT) /* Source looping */ +# define EDMA_CONFIG_LOOPDEST (2 << EDMA_CONFIG_LOOP_SHIFT) /* Dest looping */ + +#define EDMA_CONFIG_INTHALF (1 << 4) /* Bits 4: Int on HALF */ +#define EDMA_CONFIG_INTMAJOR (1 << 5) /* Bits 5: Int on all Major completion + * Default is only on last completion + * if using scatter gather + */ + /**************************************************************************** * Public Types ****************************************************************************/ @@ -129,13 +141,13 @@ typedef void *DMACH_HANDLE; typedef void (*edma_callback_t)(DMACH_HANDLE handle, void *arg, bool done, int result); -/* eDMA transfer type */ +/* eDMA transfer sizes */ -enum imxrt_edma_xfrtype_e +enum kinetis_edma_sizes_e { - EDMA_MEM2MEM = 0, /* Transfer from memory to memory */ - EDMA_PERIPH2MEM, /* Transfer from peripheral to memory */ - EDMA_MEM2PERIPH, /* Transfer from memory to peripheral */ + EDMA_8BIT = 0, /* Transfer data size 8 */ + EDMA_16BIT = 1, /* Transfer data size 16 */ + EDMA_32BIT = 2, /* Transfer data size 32 */ }; /* This structure holds the source/destination transfer attribute @@ -150,9 +162,8 @@ struct imxrt_edma_xfrconfig_s int16_t doff; /* Sign-extended offset for current destination address. */ uint16_t iter; /* Major loop iteration count. */ uint8_t flags; /* See EDMA_CONFIG_* definitions */ - uint8_t ssize; /* Source data transfer size (see TCD_ATTR_SIZE_* definitions in rdware/. */ + uint8_t ssize; /* Source data transfer size (see TCD_ATTR_SIZE_* definitions in hardware/. */ uint8_t dsize; /* Destination data transfer size. */ - uint8_t ttype; /* Transfer type (see enum imxrt_edma_xfrtype_e). */ #ifdef CONFIG_IMXRT_EDMA_EMLIM uint16_t nbytes; /* Bytes to transfer in a minor loop */ #else @@ -306,7 +317,7 @@ void imxrt_dmach_free(DMACH_HANDLE handle); * ****************************************************************************/ -int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle, +int imxrt_dmach_xfrsetup(DMACH_HANDLE handle, const struct imxrt_edma_xfrconfig_s *config); /**************************************************************************** @@ -398,7 +409,7 @@ void imxrt_dmach_stop(DMACH_HANDLE handle); * ****************************************************************************/ -unsigned int imxrt_dmach_getcount(DMACH_HANDLE *handle); +unsigned int imxrt_dmach_getcount(DMACH_HANDLE handle); /**************************************************************************** * Name: imxrt_dmasample