diff --git a/arch/arm/src/imxrt/chip/imxrt_edma.h b/arch/arm/src/imxrt/chip/imxrt_edma.h index c5119f11f9f..a7b57023680 100644 --- a/arch/arm/src/imxrt/chip/imxrt_edma.h +++ b/arch/arm/src/imxrt/chip/imxrt_edma.h @@ -1117,25 +1117,29 @@ /* TCD Transfer Attributes */ +#define TCD_ATTR_SIZE_8BIT (0) /* 8-bit */ +#define TCD_ATTR_SIZE_16BIT (1) /* 16-bit */ +#define TCD_ATTR_SIZE_32BIT (2) /* 32-bit */ +#define TCD_ATTR_SIZE_64BIT (3) /* 64-bit */ +#define TCD_ATTR_SIZE_256BIT (5) /* 32-byte burst (4 beats of 64 bits) */ + #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_8BIT (0 << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 8-bit */ -# define EDMA_TCD_ATTR_DSIZE_16BIT (1 << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 16-bit */ -# define EDMA_TCD_ATTR_DSIZE_32BIT (2 << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 32-bit */ -# define EDMA_TCD_ATTR_DSIZE_64BIT (3 << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 64-bit */ -# define EDMA_TCD_ATTR_DSIZE_4x64BIT (5 << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 32-byte burst (4 - * beats of 64 bits) */ +# 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 */ +# define EDMA_TCD_ATTR_DSIZE_64BIT (TCD_ATTR_SIZE_64BIT << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 64-bit */ +# define EDMA_TCD_ATTR_DSIZE_256BIT (TCD_ATTR_SIZE_256BIT << EDMA_TCD_ATTR_DSIZE_SHIFT) /* 32-byte burst */ #define EDMA_TCD_ATTR_DMOD_SHIFT (3) /* Bits 3-7: Destination Address Modulo */ #define EDMA_TCD_ATTR_DMOD_MASK (31 << EDMA_TCD_ATTR_DMOD_SHIFT) # 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_8BIT (0 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 8-bit */ -# define EDMA_TCD_ATTR_SSIZE_16BIT (1 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 16-bit */ -# define EDMA_TCD_ATTR_SSIZE_32BIT (2 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-bit */ -# define EDMA_TCD_ATTR_SSIZE_64BIT (3 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 64-bit */ -# define EDMA_TCD_ATTR_SSIZE_4x64BIT (5 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-byte burst (4 - * beats of 64 bits) */ +# 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 */ +# define EDMA_TCD_ATTR_SSIZE_64BIT (TCD_ATTR_SIZE_64BIT << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 64-bit */ +# define EDMA_TCD_ATTR_SSIZE_256BIT (TCD_ATTR_SIZE_256BIT << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-byte burst */ #define EDMA_TCD_ATTR_SMOD_SHIFT (11) /* Bits 11-15: Source Address Modulo */ #define EDMA_TCD_ATTR_SMOD_MASK (31 << EDMA_TCD_ATTR_SMOD_SHIFT) # define EDMA_TCD_ATTR_SMOD(n) ((uint32_t)(n) << EDMA_TCD_ATTR_SMOD_SHIFT) @@ -1164,7 +1168,7 @@ #define EDMA_TCD_NBYTES_MLOFF_DMLOE (1 << 30) /* Bit 30: Destination Minor Loop Offset enable */ #define EDMA_TCD_NBYTES_MLOFF_SMLOE (1 << 31) /* Bit 31: Source Minor Loop Offset Enable */ -/* TCD Last Source Address Adjustment (32-bit address adjustment */ +/* TCD Last Source Address Adjustment (32-bit address adjustment) */ /* TCD Destination Address (32-bit address) */ /* TCD Signed Destination Address Offset (32-bit signed address offset) */ diff --git a/arch/arm/src/imxrt/imxrt_edma.c b/arch/arm/src/imxrt/imxrt_edma.c index a136427037f..1e38301ef01 100644 --- a/arch/arm/src/imxrt/imxrt_edma.c +++ b/arch/arm/src/imxrt/imxrt_edma.c @@ -56,6 +56,7 @@ #include "chip.h" #include "chip/imxrt_edma.h" +#include "chip/imxrt_dmamux.h" #include "imxrt_edma.h" #ifdef CONFIG_IMXRT_EDMA @@ -73,10 +74,10 @@ struct imxrt_dmach_s { uint8_t chan; /* DMA channel number (0-IMXRT_EDMA_NCHANNELS) */ - bool inuse; /* TRUE: The DMA channel is in use */ - bool rx; /* TRUE: Peripheral to memory transfer */ + bool inuse; /* true: The DMA channel is in use */ + bool active; /* true: DMA has been started */ + bool rx; /* true: Peripheral to memory transfer */ uint32_t flags; /* DMA channel flags */ - uint32_t cfg; /* Pre-calculated CFG register for transfer */ dma_callback_t callback; /* Callback invoked when the DMA completes */ void *arg; /* Argument passed to callback function */ uint32_t rxaddr; /* RX memory address */ @@ -235,6 +236,7 @@ static void imxrt_dmaterminate(struct imxrt_dmach_s *dmach, int result) dmach->callback = NULL; dmach->arg = NULL; + dmach->active = false; } /**************************************************************************** @@ -253,6 +255,8 @@ static void imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) */ /* Check if the any transfer has completed or any errors have occurred. */ + + imxrt_dmaterminate(dmach); } /**************************************************************************** @@ -282,14 +286,21 @@ static int imxrt_edma_interrupt(int irq, void *context, FAR void *arg) /* Check for an interrupt on the lower numbered DMA channel */ - imxrt_dmach_interrupt(dmach); + if (dmach->active) + { + imxrt_dmach_interrupt(dmach); + } /* Check for an interrupt on the lower numbered DMA channel */ chan += 16; DEBUGASSERT(chan < IMXRT_EDMA_NCHANNELS); dmach = &g_edma.dmach[chan]; - imxrt_dmach_interrupt(dmach); + + if (dmach->active) + { + imxrt_dmach_interrupt(dmach); + } return OK; } @@ -411,6 +422,7 @@ DMA_HANDLE imxrt_dmachannel(void) { dmach = candidate; dmach->inuse = true; + dmach->active = false; /* Clear any pending interrupts on the channel */ @@ -454,7 +466,7 @@ void imxrt_dmafree(DMA_HANDLE handle) struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; dmainfo("dmach: %p\n", dmach); - DEBUGASSERT((dmach != NULL) && (dmach->inuse)); + DEBUGASSERT(dmach != NULL && dmach->inuse && !dmach->active); /* Mark the channel no longer in use. Clearing the inuse flag is an atomic * operation and so should be safe. @@ -462,6 +474,7 @@ void imxrt_dmafree(DMA_HANDLE handle) dmach->flags = 0; dmach->inuse = false; /* No longer in use */ + dmach->inuse = active; /* Better not be active */ } /**************************************************************************** @@ -491,7 +504,8 @@ int imxrt_dmatxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, * that this was not an RX transfer. */ - dmach->rx = false; + dmach->rx = false; + dmach->active = true; /* Clean caches associated with the DMA memory */ @@ -531,6 +545,7 @@ int imxrt_dmarxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, dmach->rx = true; dmach->rxaddr = maddr; dmach->rxsize = nbytes; + dmach->active = true; /* Clean caches associated with the DMA memory */ @@ -606,15 +621,50 @@ void imxrt_dmastop(DMA_HANDLE handle) void imxrt_dmasample(DMA_HANDLE handle, struct imxrt_dmaregs_s *regs) { struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + uintptr_t regaddr; + unsigned int chan; irqstate_t flags; - /* Sample global registers */ + DEBUGASSERT(dmach != NULL && regs != NULL); + chan = dmach->chan; + regs->chan = chan; - flags = spin_lock_irqsave(); -#warning Missing logic + /* eDMA Global Registers */ - /* Sample channel registers */ -#warning Missing logic + flags = spin_lock_irqsave(); + + regs->cr = getreg32(IMXRT_EDMA_CR); /* Control */ + regs->es = getreg32(IMXRT_EDMA_ES); /* Error Status */ + regs->erq = getreg32(IMXRT_EDMA_ERQ); /* Enable Request */ + regs->req = getreg32(IMXRT_EDMA_INT); /* Interrupt Request */ + regs->err = getreg32(IMXRT_EDMA_ERR); /* Error */ + regs->hrs = getreg32(IMXRT_EDMA_HRS); /* Hardware Request Status */ + regs->ears = getreg32(IMXRT_EDMA_EARS); /* Enable Asynchronous Request in Stop */ + + /* eDMA Channel registers */ + + regaddr = IMXRT_EDMA_DCHPRI(chan); + regs->dchpri = getreg8(regaddr); /* Channel priority */ + + /* eDMA TCD */ + + base = IMXRT_EDMA_TCD_BASE(chan); + 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_ML_OFFSET); + regs->slast = getreg32(base + IMXRT_EDMA_TCD_SLAST_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_ELINK_OFFSET); + regs->dlastsga = getreg32(base + IMXRT_EDMA_TCD_DLASTSGA_OFFSET); + regs->csr = getreg16(base + IMXRT_EDMA_TCD_CSR_OFFSET); + regs->biter = getreg16(base + IMXRT_EDMA_TCD_BITER_ELINK_OFFSET); + + /* DMAMUX registers */ + + regaddr = IMXRT_DMAMUX_CHCF(chan); + regs->dmamux = getreg32(regaddr); /* Channel configuration */ spin_unlock_irqrestore(flags); } @@ -632,16 +682,48 @@ void imxrt_dmasample(DMA_HANDLE handle, struct imxrt_dmaregs_s *regs) ****************************************************************************/ #ifdef CONFIG_DEBUG_DMA -void imxrt_dmadump(DMA_HANDLE handle, const struct imxrt_dmaregs_s *regs, - const char *msg) +void imxrt_dmadump(const struct imxrt_dmaregs_s *regs, const char *msg) { - struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + unsigned int chan; + + DEBUGASSERT(regs != NULL && msg != NULL); + + chan = regs->chan; + DEBUGASSERT(chan < IMXRT_EDMA_NCHANNELS); dmainfo("%s\n", msg); - dmainfo(" DMA Global Registers:\n"); -#warning Missing logic - dmainfo(" DMA Channel Registers:\n"); -#warning Missing logic + dmainfo(" eDMA Global Registers:\n"); + dmainfo(" CR: %08x\n", regs->cr); + dmainfo(" ES: %08x\n", regs->es); + dmainfo(" ERQ: %08x\n", regs->erq); + dmainfo(" INT: %08x\n", regs->req); + dmainfo(" ERR: %08x\n", regs->err); + dmainfo(" EARS: %08x\n", 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", regs->saddr); + dmainfo(" SOFF: %04x\n", regs->soff); + dmainfo(" ATTR: %04x\n", regs->attr); + dmainfo(" NBML: %05x\n", regs->nbml); + dmainfo(" SLAST: %05x\n", regs->slast); + dmainfo(" DADDR: %05x\n", regs->daddr); + dmainfo(" DOFF: %04x\n", regs->doff); + dmainfo(" CITER: %04x\n", regs->citer); + dmainfo(" DLASTSGA: %08x\n", regs->dlastsga); + dmainfo(" CSR: %04x\n", regs->csr); + dmainfo(" BITER: %04x\n", regs->biter); + + /* DMAMUX registers */ + + dmainfo(" DMAMUX Channel %u Registers:\n", chan); + dmainfo(" DMAMUX: %08x\n", regs->dmamux); } #endif /* CONFIG_DEBUG_DMA */ #endif /* CONFIG_IMXRT_EDMA */ diff --git a/arch/arm/src/imxrt/imxrt_edma.h b/arch/arm/src/imxrt/imxrt_edma.h index da7f67fec2d..ea949dfcc2e 100644 --- a/arch/arm/src/imxrt/imxrt_edma.h +++ b/arch/arm/src/imxrt/imxrt_edma.h @@ -43,6 +43,7 @@ #include #include +#include "chip/imxrt_edma.h" /************************************************************************************ * Pre-processor Definitions @@ -54,9 +55,58 @@ * side is the peripheral and the other is memory (however, the interface could still * be used if, for example, both sides were memory although the naming would be * awkward) + * + * .... .... .... .... .... CCCC GGBA DDSS + * + * REVISIT: Initially, only vanilla Rx/Tx DMA block transfers are supported. */ -#define DMACH_FLAG_ +/* Source transfer size: + * + * .... .... .... .... .... .... .... ..SS + */ + +#define DMACH_FLAG_SSIZE_SHIFT (0) /* Bits 0-1: Source transfer size */ +#define DMACH_FLAG_SSIZE_MASK (7 << DMACH_FLAG_SSIZE_SHIFT) +# define DMACH_FLAG_SSIZE_8BIT (TCD_ATTR_SIZE_8BIT << DMACH_FLAG_SSIZE_SHIFT) /* 8-bit */ +# define DMACH_FLAG_SSIZE_16BIT (TCD_ATTR_SIZE_16BIT << DMACH_FLAG_SSIZE_SHIFT) /* 16-bit */ +# define DMACH_FLAG_SSIZE_32BIT (TCD_ATTR_SIZE_32BIT << DMACH_FLAG_SSIZE_SHIFT) /* 32-bit */ +# define DMACH_FLAG_SSIZE_64BIT (TCD_ATTR_SIZE_64BIT << DMACH_FLAG_SSIZE_SHIFT) /* 64-bit */ +# define DMACH_FLAG_SSIZE_256BIT (TCD_ATTR_SIZE_256BIT << DMACH_FLAG_SSIZE_SHIFT) /* 32-byte burst */ + +/* Destination transfer size: + * + * .... .... .... .... .... .... .... DD.. + */ + +#define DMACH_FLAG_DSIZE_SHIFT (2) /* Bits 2-3: Destination transfer size */ +#define DMACH_FLAG_DSIZE_MASK (7 << DMACH_FLAG_DSIZE_SHIFT) +# define EMACH_FLAG_DSIZE_8BIT (TCD_ATTR_SIZE_8BIT << DMACH_FLAG_DSIZE_SHIFT) /* 8-bit */ +# define EMACH_FLAG_DSIZE_16BIT (TCD_ATTR_SIZE_16BIT << DMACH_FLAG_DSIZE_SHIFT) /* 16-bit */ +# define EMACH_FLAG_DSIZE_32BIT (TCD_ATTR_SIZE_32BIT << DMACH_FLAG_DSIZE_SHIFT) /* 32-bit */ +# define EMACH_FLAG_DSIZE_64BIT (TCD_ATTR_SIZE_64BIT << DMACH_FLAG_DSIZE_SHIFT) /* 64-bit */ +# define EMACH_FLAG_DSIZE_256BIT (TCD_ATTR_SIZE_256BIT << DMACH_FLAG_DSIZE_SHIFT) /* 32-byte burst */ + +/* Arbitration: + * + * .... .... .... .... .... .... ..BA .... + */ + +#define DMACH_FLAG_CHRR (1 << 4) /* Bit 4: Round Robin Channel Arbitration */ +#define DMACH_FLAG_GRPRR (1 << 5) /* Bit 5: Round Robin Group Arbitration */ + +/* DMA Priorities: + * + * .... .... .... .... .... CCCC GG.. .... + */ + +#define DMACH_FLAG_GPPRI_SHIFT (6) /* Bits 6-7: Channel Group Priority */ +#define DMACH_FLAG_GRPPRI_MASK (3 << DMACH_FLAG_GPPRI_SHIFT) +# define DMACH_FLAG_GRPPRI(n) ((uint32_t)(n) << DMACH_FLAG_GPPRI_SHIFT) + +#define DMACH_FLAG_CHPRI_SHIFT (8) /* Bits 8-11: Channel Arbitration Priority */ +#define DMACH_FLAG_CHPRI_MASK (15 << DMACH_FLAG_CHPRI_SHIFT) +# define DMACH_FLAG_CHPRI(n) ((uint32_t)(n) << DMACH_FLAG_CHPRI_SHIFT) /************************************************************************************ * Public Types @@ -70,6 +120,8 @@ typedef void (*dma_callback_t)(DMA_HANDLE handle, void *arg, int result); #ifdef CONFIG_DEBUG_DMA struct imxrt_dmaregs_s { + uint8_t chan; /* Sampled channel */ + /* eDMA Global Registers */ uint32_t cr; /* Control */ @@ -95,7 +147,7 @@ struct imxrt_dmaregs_s uint16_t doff; /* TCD Signed Destination Address Offset */ uint16_t citer; /* TCD Current Minor Loop Link, Major Loop Count */ uint32_t dlastsga; /* TCD Last Destination Address Adjustment/Scatter Gather Address */ - uint32_t csr; /* TCD Control and Status */ + uint16_t csr; /* TCD Control and Status */ uint16_t biter; /* TCD Beginning Minor Loop Link, Major Loop Count */ /* DMAMUX registers */ @@ -233,8 +285,7 @@ void imxrt_dmasample(DMA_HANDLE handle, struct imxrt_dmaregs_s *regs); ************************************************************************************/ #ifdef CONFIG_DEBUG_DMA -void imxrt_dmadump(DMA_HANDLE handle, const struct imxrt_dmaregs_s *regs, - const char *msg); +void imxrt_dmadump(const struct imxrt_dmaregs_s *regs, const char *msg); #else # define imxrt_dmadump(handle,regs,msg) #endif