mirror of
https://github.com/apache/nuttx.git
synced 2026-06-09 02:44:53 +08:00
imxrt:EDMA add loop support
imxrt:edma imxrt_dmach_{xfrsetup|getcount} DMACH_HANDLE *->DMACH_HANDLE
imxrt:EDMA TCD Alignment of 32 Bytes to support Scatter/Gather
This commit is contained in:
committed by
Xiang Xiao
parent
1421bc58db
commit
33efeeeafd
@@ -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 */
|
||||
|
||||
+95
-136
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user