diff --git a/arch/arm/src/imxrt/imxrt_edma.c b/arch/arm/src/imxrt/imxrt_edma.c index 1e38301ef01..486a79eba23 100644 --- a/arch/arm/src/imxrt/imxrt_edma.c +++ b/arch/arm/src/imxrt/imxrt_edma.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/imxrt/sam3u_edma.c + * arch/arm/src/imxrt/imxrt_edma.c * * Copyright (C) 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -69,14 +69,23 @@ * 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 { uint8_t chan; /* DMA channel number (0-IMXRT_EDMA_NCHANNELS) */ bool inuse; /* true: The DMA channel is in use */ - bool active; /* true: DMA has been started */ - bool rx; /* true: Peripheral to memory transfer */ + uint8_t ttype; /* Transfer type: M2M, M2P, P2M, or P2P */ + uint8_t state; /* Channel state. See enum imxrt_dmastate_e */ uint32_t flags; /* DMA channel flags */ dma_callback_t callback; /* Callback invoked when the DMA completes */ void *arg; /* Argument passed to callback function */ @@ -222,7 +231,7 @@ static void imxrt_dmaterminate(struct imxrt_dmach_s *dmach, int result) * to force reloads from memory. */ - if (dmach->rx) + if ((dmach->ttype & TTYPE_2P_MASK) == 0) { arch_invalidate_dcache(dmach->rxaddr, dmach->rxaddr + dmach->rxsize); } @@ -236,7 +245,7 @@ static void imxrt_dmaterminate(struct imxrt_dmach_s *dmach, int result) dmach->callback = NULL; dmach->arg = NULL; - dmach->active = false; + dmach->state = IMXRT_DMA_IDLE; } /**************************************************************************** @@ -286,7 +295,7 @@ static int imxrt_edma_interrupt(int irq, void *context, FAR void *arg) /* Check for an interrupt on the lower numbered DMA channel */ - if (dmach->active) + if (dmach->state == IMXRT_DMA_ACTIVE) { imxrt_dmach_interrupt(dmach); } @@ -297,7 +306,7 @@ static int imxrt_edma_interrupt(int irq, void *context, FAR void *arg) DEBUGASSERT(chan < IMXRT_EDMA_NCHANNELS); dmach = &g_edma.dmach[chan]; - if (dmach->active) + if (dmach->state == IMXRT_DMA_ACTIVE) { imxrt_dmach_interrupt(dmach); } @@ -420,9 +429,9 @@ DMA_HANDLE imxrt_dmachannel(void) struct imxrt_dmach_s *candidate = &g_edma.dmach[chndx]; if (!candidate->inuse) { - dmach = candidate; - dmach->inuse = true; - dmach->active = false; + dmach = candidate; + dmach->inuse = true; + dmach->state = IMXRT_DMA_IDLE; /* Clear any pending interrupts on the channel */ @@ -466,7 +475,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 && !dmach->active); + 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. @@ -474,78 +483,71 @@ void imxrt_dmafree(DMA_HANDLE handle) dmach->flags = 0; dmach->inuse = false; /* No longer in use */ - dmach->inuse = active; /* Better not be active */ + dmach->state = IMXRT_DMA_IDLE; /* Better not be active! */ } -/**************************************************************************** - * Name: imxrt_dmatxsetup +/************************************************************************************ + * Name: imxrt_dmasetup * * Description: - * Configure DMA for transmit of one buffer (memory to peripheral). This - * function may be called multiple times to handle large and/or dis- - * continuous transfers. Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() - * must not be intermixed on the same transfer, however. + * Configure DMA for one Rx (peripheral-to-memory) or Rx (memory-to-peripheral) + * transfer of one buffer. * - ****************************************************************************/ + * TODO: This function needs to be called multiple times to handle multiple, + * discontinuous transfers. + * + ************************************************************************************/ -int imxrt_dmatxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, - size_t nbytes, uint32_t chflags) +int imxrt_dmasetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, size_t nbytes, + uint32_t chflags) { struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; int ret = OK; - dmainfo("dmach: %p pchan: %u maddr: %08x nbytes: %d chflags %08x\n", - dmach, (int)pchan, (int)maddr, (int)nbytes, (unsigned int)chflags); DEBUGASSERT(dmach != NULL); + dmainfo("dmach%u: %p pchan: %u maddr: %08x nbytes: %d chflags %08x\n", + dmach, dmach->chan, (int)pchan, (int)maddr, (int)nbytes, + (unsigned int)chflags); + /* To initialize the eDMA: + * + * 1. Write to the CR if a configuration other than the default is desired. + * 2. Write the channel priority levels to the DCHPRIn registers if a + * configuration other than the default is desired. + * 3. Enable error interrupts in the EEI register if so desired. + * 4. Write the 32-byte TCD for each channel that may request service. + * 5. Enable any hardware service requests via the ERQ register. + * 6. Request channel service via either: + * - Software: setting the TCDn_CSR[START] + * - Hardware: slave device asserting its eDMA peripheral request signal + * + * This function performs steps 1-5. Step 6 is performed separately by + * imxrt_dmastart(). + */ #warning Missing logic - /* Save an indication so that the DMA interrupt completion logic will know - * that this was not an RX transfer. - */ + /* Check for an Rx (memory-to-peripheral) DMA transfer */ - dmach->rx = false; - dmach->active = true; + dmach->ttype = (chflags & DMACH_FLAG_TTYPE_MASK) >> DMACH_FLAG_TTYPE_SHIFT; + if (dmach->ttype == TTYPE_P2M) + { + /* Save an information so that the DMA interrupt completion logic will + * will be able to invalidate the cache after the Rx DMA. + */ - /* Clean caches associated with the DMA memory */ + dmach->rxaddr = maddr; + dmach->rxsize = nbytes; + } - arch_clean_dcache(maddr, maddr + nbytes); - return ret; -} + /* Check for an Tx (peripheral-to-memory) DMA transfer */ -/**************************************************************************** - * Name: imxrt_dmarxsetup - * - * Description: - * Configure DMA for receipt of one buffer (peripheral to memory). This - * function may be called multiple times to handle large and/or dis- - * continuous transfers. Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() - * must not be intermixed on the same transfer, however. - * - ****************************************************************************/ + else if (dmach->ttype != TTYPE_M2P) + { + dmaerr("ERROR: Unsupported ttype: %u\n", dmach->ttype); + return -ENOSYS; + } -int imxrt_dmarxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, - size_t nbytes, uint32_t chflags) -{ - struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; - size_t maxtransfer; - size_t remaining; - int ret = OK; - - dmainfo("dmach: %p pchan: %u maddr: %08x nbytes: %d chflags %08x\n", - dmach, (int)pchan, (int)maddr, (int)nbytes, (unsigned int)chflags); - DEBUGASSERT(dmach); - -#warning Missing logic - - /* Save an indication so that the DMA interrupt completion logic will know - * that this was an RX transfer and will invalidate the cache. - */ - - dmach->rx = true; - dmach->rxaddr = maddr; - dmach->rxsize = nbytes; - dmach->active = true; + dmach->state = IMXRT_DMA_CONFIGURED; /* Clean caches associated with the DMA memory */ @@ -567,7 +569,7 @@ int imxrt_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) int ret = -EINVAL; dmainfo("dmach: %p callback: %p arg: %p\n", dmach, callback, arg); - DEBUGASSERT(dmach != NULL); + DEBUGASSERT(dmach != NULL && dmach->state == IMXRT_DMA_CONFIGURED); /* Verify that the DMA has been setup (i.e., at least one entry in the * link list). @@ -577,6 +579,7 @@ int imxrt_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) dmach->callback = callback; dmach->arg = arg; + dmach->state = IMXRT_DMA_ACTIVE; #warning Missing logic diff --git a/arch/arm/src/imxrt/imxrt_edma.h b/arch/arm/src/imxrt/imxrt_edma.h index ea949dfcc2e..672be5a38c5 100644 --- a/arch/arm/src/imxrt/imxrt_edma.h +++ b/arch/arm/src/imxrt/imxrt_edma.h @@ -56,17 +56,40 @@ * be used if, for example, both sides were memory although the naming would be * awkward) * - * .... .... .... .... .... CCCC GGBA DDSS + * .... .... .... .... CCCC GGBA DDSS ..TT * * REVISIT: Initially, only vanilla Rx/Tx DMA block transfers are supported. */ -/* Source transfer size: +/* Transfer type: * - * .... .... .... .... .... .... .... ..SS + * .... .... .... .... .... .... .... ..TT */ -#define DMACH_FLAG_SSIZE_SHIFT (0) /* Bits 0-1: Source transfer size */ +#define TTYPE_M2M (0) /* Memory-to-memory (not supported) */ +#define TTYPE_M2P (1) /* Memory-to-peripheral (normal Tx) */ +#define TTYPE_P2M (2) /* Peripheral-to-memory (normal Rx) */ +#define TTYPE_P2P (3) /* Peripheral-to-peripheral (not supported) */ + +#define TTYPE_2P_MASK (1) /* Transfer to peripheral (M2P or P2P) */ +#define TTYPE_P2_MASK (2) /* Transfer from peripheral (P2M or P2P) */ + +#define DMACH_FLAG_TTYPE_SHIFT (0) /* Bits 0-1 Destination transfer size */ +#define DMACH_FLAG_TTYPE_MASK (3 << DMACH_FLAG_TTYPE_SHIFT) +# define DMACH_FLAG_TTYPE_M2M (TTYPE_M2M << DMACH_FLAG_TTYPE_SHIFT) /* Memory-to-memory */ +# define DMACH_FLAG_TTYPE_M2P (TTYPE_M2P << DMACH_FLAG_TTYPE_SHIFT) /* Memory-to-peripheral */ +# define DMACH_FLAG_TTYPE_P2M (TTYPE_P2M << DMACH_FLAG_TTYPE_SHIFT) /* Peripheral-to-memory */ +# define DMACH_FLAG_TTYPE_P2P (TTYPE_P2P << DMACH_FLAG_TTYPE_SHIFT) /* Peripheral-to-peripheral */ + +# define DMACH_FLAG_TTYPE_2P_MASK (TTYPE_2P_MASK << DMACH_FLAG_TTYPE_SHIFT) /* Transfer to peripheral */ +# define DMACH_FLAG_TTYPE_P2_MASK (TTYPE_P2_MASK << DMACH_FLAG_TTYPE_SHIFT) /* Transfer from peripheral */ + +/* Source transfer size: + * + * .... .... .... .... .... .... ..SS .... + */ + +#define DMACH_FLAG_SSIZE_SHIFT (4) /* Bits 4-5: 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 */ @@ -76,37 +99,37 @@ /* Destination transfer size: * - * .... .... .... .... .... .... .... DD.. + * .... .... .... .... .... .... DD.. .... */ -#define DMACH_FLAG_DSIZE_SHIFT (2) /* Bits 2-3: Destination transfer size */ +#define DMACH_FLAG_DSIZE_SHIFT (6) /* Bits 6-7: 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 */ +# define DMACH_FLAG_DSIZE_8BIT (TCD_ATTR_SIZE_8BIT << DMACH_FLAG_DSIZE_SHIFT) /* 8-bit */ +# define DMACH_FLAG_DSIZE_16BIT (TCD_ATTR_SIZE_16BIT << DMACH_FLAG_DSIZE_SHIFT) /* 16-bit */ +# define DMACH_FLAG_DSIZE_32BIT (TCD_ATTR_SIZE_32BIT << DMACH_FLAG_DSIZE_SHIFT) /* 32-bit */ +# define DMACH_FLAG_DSIZE_64BIT (TCD_ATTR_SIZE_64BIT << DMACH_FLAG_DSIZE_SHIFT) /* 64-bit */ +# define DMACH_FLAG_DSIZE_256BIT (TCD_ATTR_SIZE_256BIT << DMACH_FLAG_DSIZE_SHIFT) /* 32-byte burst */ /* Arbitration: * - * .... .... .... .... .... .... ..BA .... + * .... .... .... .... .... ..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 */ +#define DMACH_FLAG_CHRR (1 << 8) /* Bit 8: Round Robin Channel Arbitration */ +#define DMACH_FLAG_GRPRR (1 << 8) /* Bit 9: Round Robin Group Arbitration */ /* DMA Priorities: * - * .... .... .... .... .... CCCC GG.. .... + * .... .... .... .... 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_GPPRI_SHIFT (10) /* Bits 10-11: 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) +#define DMACH_FLAG_CHPRI_SHIFT (12) /* Bits 12-15: 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 @@ -214,32 +237,19 @@ DMA_HANDLE imxrt_dmachannel(void); void imxrt_dmafree(DMA_HANDLE handle); /************************************************************************************ - * Name: imxrt_dmatxsetup + * Name: imxrt_dmasetup * * Description: - * Configure DMA for transmit of one buffer (memory to peripheral). This function - * may be called multiple times to handle large and/or discontinuous transfers. - * Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() must not be intermixed on the - * same transfer, however. + * Configure DMA for one Rx (peripheral-to-memory) or Rx (memory-to-peripheral) + * transfer of one buffer. + * + * TODO: This function needs to be called multiple times to handle multiple, + * discontinuous transfers. * ************************************************************************************/ -int imxrt_dmatxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, size_t nbytes, - uint32_t chflags); - -/************************************************************************************ - * Name: imxrt_dmarxsetup - * - * Description: - * Configure DMA for receipt of one buffer (peripheral to memory). This function - * may be called multiple times to handle large and/or discontinuous transfers. - * Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() must not be intermixed on the - * same transfer, however. - * - ************************************************************************************/ - -int imxrt_dmarxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, size_t nbytes, - uint32_t chflags); +int imxrt_dmasetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, size_t nbytes, + uint32_t chflags); /************************************************************************************ * Name: imxrt_dmastart diff --git a/arch/arm/src/sama5/sam_dmac.c b/arch/arm/src/sama5/sam_dmac.c index c1c70ccd7f9..9df12bdd039 100644 --- a/arch/arm/src/sama5/sam_dmac.c +++ b/arch/arm/src/sama5/sam_dmac.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/sama5/sam3u_dmac.c + * arch/arm/src/sama5/sam_dmac.c * * Copyright (C) 2013, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt