Kinetis:edma Cleanup
Kientis:edma Cleanup Kinetis:EDMA Interrupt on last TCD Kintis:edma remove dcache operations on passed data Data can be chained in TCD and both read and write can be in the chain. So the dmach ttype is not relevent for all; the TCDs. Therefor we only perform dcache operations on internal strutures, The caller must perform dcache operations on their data. kinetis:EDMA TCD Alignment of 32 Bytes to support Scatter/Gather
This commit is contained in:
parent
20b9cc37d5
commit
7a7a01153b
@ -831,14 +831,12 @@
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* In-memory representation of the 32-byte Transfer Control Descriptor
|
||||
* (TCD)
|
||||
/* Hardware representation of the 32-byte Transfer
|
||||
* Control Descriptor (TCD)
|
||||
*/
|
||||
|
||||
struct kinetis_edmatcd_s
|
||||
{
|
||||
sq_entry_t node;
|
||||
uint8_t flags; /* See EDMA_CONFIG_* definitions */
|
||||
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 */
|
||||
|
@ -88,22 +88,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
|
||||
****************************************************************************/
|
||||
@ -121,11 +115,10 @@ enum kinetis_dmastate_e
|
||||
|
||||
struct kinetis_dmach_s
|
||||
{
|
||||
uint8_t chan; /* DMA channel number (0-KINETIS_EDMA_NCHANNELS) */
|
||||
bool inuse; /* true: The DMA channel is in use */
|
||||
uint8_t dmamux; /* The DMAMUX channel selection */
|
||||
uint8_t ttype; /* Transfer type: M2M, M2P, P2M, or P2P */
|
||||
uint8_t state; /* Channel state. See enum kinetis_dmastate_e */
|
||||
uint8_t chan; /* DMA channel number (0-KINETIS_EDMA_NCHANNELS) */
|
||||
bool inuse; /* true: The DMA channel is in use */
|
||||
uint8_t state; /* Channel state. See enum kinetis_dmastate_e */
|
||||
uint8_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 */
|
||||
@ -341,18 +334,13 @@ static inline void kinetis_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 kinetis_tcd_configure */
|
||||
|
||||
/* Disable major link */
|
||||
|
||||
tcd->csr &= ~EDMA_TCD_CSR_MAJORELINK;
|
||||
#endif
|
||||
}
|
||||
else if (flags == EDMA_CONFIG_LINKTYPE_MINORLINK) /* Minor link config */
|
||||
{
|
||||
@ -403,22 +391,21 @@ static inline void kinetis_tcd_chanlink(uint8_t flags,
|
||||
static inline void kinetis_tcd_configure(struct kinetis_edmatcd_s *tcd,
|
||||
const struct kinetis_edma_xfrconfig_s *config)
|
||||
{
|
||||
tcd->flags = config->flags;
|
||||
tcd->saddr = config->saddr;
|
||||
tcd->soff = config->soff;
|
||||
tcd->attr = EDMA_TCD_ATTR_SSIZE(config->ssize) | /* Transfer Attributes */
|
||||
EDMA_TCD_ATTR_DSIZE(config->dsize);
|
||||
tcd->nbytes = config->nbytes;
|
||||
tcd->slast = config->flags & EDMA_CONFIG_LOOPSRC ? -config->iter : 0;
|
||||
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 = config->flags & EDMA_CONFIG_LOOPDEST ?
|
||||
tcd->csr = config->flags & EDMA_CONFIG_LOOP_MASK ?
|
||||
0 : EDMA_TCD_CSR_DREQ;
|
||||
tcd->csr |= config->flags & EDMA_CONFIG_INTHALF ?
|
||||
tcd->csr |= config->flags & EDMA_CONFIG_INTHALF ?
|
||||
EDMA_TCD_CSR_INTHALF : 0;
|
||||
tcd->dlastsga = config->flags & EDMA_CONFIG_LOOPDEST ? -config->iter : 0;
|
||||
tcd->dlastsga = config->flags & EDMA_CONFIG_LOOPDEST ? -config->iter : 0;
|
||||
|
||||
/* And special case flags */
|
||||
|
||||
@ -447,6 +434,10 @@ static void kinetis_tcd_instantiate(struct kinetis_dmach_s *dmach,
|
||||
|
||||
/* Push tcd into hardware TCD register */
|
||||
|
||||
/* Clear DONE bit first, otherwise ESG cannot be set */
|
||||
|
||||
putreg16(0, base + KINETIS_EDMA_TCD_CSR_OFFSET);
|
||||
|
||||
putreg32(tcd->saddr, base + KINETIS_EDMA_TCD_SADDR_OFFSET);
|
||||
putreg16(tcd->soff, base + KINETIS_EDMA_TCD_SOFF_OFFSET);
|
||||
putreg16(tcd->attr, base + KINETIS_EDMA_TCD_ATTR_OFFSET);
|
||||
@ -457,9 +448,6 @@ static void kinetis_tcd_instantiate(struct kinetis_dmach_s *dmach,
|
||||
putreg16(tcd->citer, base + KINETIS_EDMA_TCD_CITER_ELINK_OFFSET);
|
||||
putreg32(tcd->dlastsga, base + KINETIS_EDMA_TCD_DLASTSGA_OFFSET);
|
||||
|
||||
/* Clear DONE bit first, otherwise ESG cannot be set */
|
||||
|
||||
putreg16(0, base + KINETIS_EDMA_TCD_CSR_OFFSET);
|
||||
putreg16(tcd->csr, base + KINETIS_EDMA_TCD_CSR_OFFSET);
|
||||
|
||||
putreg16(tcd->biter, base + KINETIS_EDMA_TCD_BITER_ELINK_OFFSET);
|
||||
@ -495,34 +483,13 @@ static void kinetis_dmaterminate(struct kinetis_dmach_s *dmach, int result)
|
||||
regval8 = EDMA_CERQ(chan);
|
||||
putreg8(regval8, KINETIS_EDMA_CERQ);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
dmach->callback((DMACH_HANDLE)dmach, dmach->arg, true, result);
|
||||
}
|
||||
|
||||
/* 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 = KINETIS_EDMA_TCD_CSR(chan);
|
||||
putreg16(0, regaddr);
|
||||
|
||||
/* Cancel next TCD transfer. */
|
||||
|
||||
regaddr = KINETIS_EDMA_TCD_DLASTSGA(chan);
|
||||
putreg16(0, regaddr);
|
||||
putreg32(0, regaddr);
|
||||
|
||||
#if CONFIG_KINETIS_EDMA_NTCD > 0
|
||||
/* Return all allocated TCDs to the free list */
|
||||
@ -533,7 +500,7 @@ static void kinetis_dmaterminate(struct kinetis_dmach_s *dmach, int result)
|
||||
* if not continue to free tcds in chain
|
||||
*/
|
||||
|
||||
next = tcd->flags & EDMA_CONFIG_LOOPDEST ?
|
||||
next = dmach->flags & EDMA_CONFIG_LOOPDEST ?
|
||||
NULL : (struct kinetis_edmatcd_s *)tcd->dlastsga;
|
||||
|
||||
kinetis_tcd_free(tcd);
|
||||
@ -543,6 +510,13 @@ static void kinetis_dmaterminate(struct kinetis_dmach_s *dmach, int result)
|
||||
dmach->tail = NULL;
|
||||
#endif
|
||||
|
||||
/* Perform the DMA complete callback */
|
||||
|
||||
if (dmach->callback)
|
||||
{
|
||||
dmach->callback((DMACH_HANDLE)dmach, dmach->arg, true, result);
|
||||
}
|
||||
|
||||
dmach->callback = NULL;
|
||||
dmach->arg = NULL;
|
||||
dmach->state = KINETIS_DMA_IDLE;
|
||||
@ -569,13 +543,13 @@ static int kinetis_edma_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct kinetis_dmach_s *dmach;
|
||||
uintptr_t regaddr;
|
||||
uint8_t regval8;
|
||||
uint16_t regval16;
|
||||
uint32_t regval32;
|
||||
uint16_t regval16;
|
||||
uint8_t regval8;
|
||||
uint8_t chan;
|
||||
int result;
|
||||
|
||||
/* 'arg' should the DMA channel instance. */
|
||||
/* 'arg' should be the DMA channel instance. */
|
||||
|
||||
dmach = (struct kinetis_dmach_s *)arg;
|
||||
DEBUGASSERT(dmach != NULL);
|
||||
@ -617,12 +591,12 @@ static int kinetis_edma_interrupt(int irq, void *context, void *arg)
|
||||
else
|
||||
{
|
||||
#if CONFIG_KINETIS_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)
|
||||
{
|
||||
dmach->callback((DMACH_HANDLE)dmach, dmach->arg,
|
||||
false, 0);
|
||||
false, OK);
|
||||
}
|
||||
|
||||
return OK;
|
||||
@ -636,7 +610,15 @@ static int kinetis_edma_interrupt(int irq, void *context, void *arg)
|
||||
|
||||
/* Terminate the transfer when it is done. */
|
||||
|
||||
kinetis_dmaterminate(dmach, result);
|
||||
if ((dmach->flags & EDMA_CONFIG_LOOP_MASK) == 0)
|
||||
{
|
||||
kinetis_dmaterminate(dmach, result);
|
||||
}
|
||||
else if (dmach->callback != NULL)
|
||||
{
|
||||
dmach->callback((DMACH_HANDLE)dmach, dmach->arg,
|
||||
true, result);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
@ -805,6 +787,14 @@ void weak_function arm_dma_initialize(void)
|
||||
|
||||
regaddr = KINETIS_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 kinetis_dmach_getcount
|
||||
* reports 0.
|
||||
*/
|
||||
|
||||
memset((void *)KINETIS_EDMA_TCD_BASE(i), 0,
|
||||
sizeof(struct kinetis_edmatcd_s));
|
||||
}
|
||||
|
||||
/* Clear all pending DMA channel interrupts */
|
||||
@ -993,6 +983,8 @@ int kinetis_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
#if CONFIG_KINETIS_EDMA_NTCD > 0
|
||||
struct kinetis_edmatcd_s *tcd;
|
||||
struct kinetis_edmatcd_s *prev;
|
||||
uint16_t mask = config->flags & EDMA_CONFIG_INTMAJOR ? 0 :
|
||||
EDMA_TCD_CSR_INTMAJOR;
|
||||
#endif
|
||||
uintptr_t regaddr;
|
||||
uint16_t regval16;
|
||||
@ -1000,6 +992,8 @@ int kinetis_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
DEBUGASSERT(dmach != NULL);
|
||||
dmainfo("dmach%u: %p config: %p\n", dmach->chan, dmach, config);
|
||||
|
||||
dmach->flags = config->flags;
|
||||
|
||||
#if CONFIG_KINETIS_EDMA_NTCD > 0
|
||||
/* Scatter/gather DMA is supported */
|
||||
|
||||
@ -1019,20 +1013,6 @@ int kinetis_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
|
||||
tcd->csr |= EDMA_TCD_CSR_INTMAJOR;
|
||||
|
||||
/* Is looped to it's self? */
|
||||
|
||||
if (config->flags & EDMA_CONFIG_LOOP_MASK)
|
||||
{
|
||||
/* Enable major link */
|
||||
|
||||
tcd->csr |= EDMA_TCD_CSR_MAJORELINK;
|
||||
|
||||
/* Set major linked channel back to this one */
|
||||
|
||||
tcd->csr &= ~EDMA_TCD_CSR_MAJORLINKCH_MASK;
|
||||
tcd->csr |= EDMA_TCD_CSR_MAJORLINKCH(dmach->chan);
|
||||
}
|
||||
|
||||
/* Is this the first descriptor in the list? */
|
||||
|
||||
if (dmach->head == NULL)
|
||||
@ -1041,7 +1021,6 @@ int kinetis_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. */
|
||||
|
||||
@ -1049,12 +1028,9 @@ int kinetis_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 ||
|
||||
dmach->flags & EDMA_CONFIG_LOOPDEST)
|
||||
if (dmach->flags & EDMA_CONFIG_LOOP_MASK)
|
||||
{
|
||||
kinetis_tcd_free(tcd);
|
||||
return -EINVAL;
|
||||
@ -1066,8 +1042,9 @@ int kinetis_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;
|
||||
@ -1089,7 +1066,7 @@ int kinetis_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
|
||||
regaddr = KINETIS_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);
|
||||
|
||||
@ -1128,35 +1105,6 @@ int kinetis_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 */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Set the DMAMUX source and enable and optional trigger */
|
||||
|
||||
putreg8(dmach->dmamux, KINETIS_DMAMUX_CHCFG(dmach->chan));
|
||||
@ -1172,10 +1120,10 @@ int kinetis_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
* Start the DMA transfer. This function should be called after the final
|
||||
* call to kinetis_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
|
||||
|
@ -122,13 +122,17 @@
|
||||
# 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: Loop type */
|
||||
#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 << 3) /* Bits 3: Int on HALF */
|
||||
#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
|
||||
@ -138,16 +142,7 @@ typedef void *DMACH_HANDLE;
|
||||
typedef void (*edma_callback_t)(DMACH_HANDLE handle,
|
||||
void *arg, bool done, int result);
|
||||
|
||||
/* eDMA transfer type */
|
||||
|
||||
enum kinetis_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 */
|
||||
/* eDMA transfer sizes */
|
||||
|
||||
enum kinetis_edma_sizes_e
|
||||
{
|
||||
@ -170,7 +165,6 @@ struct kinetis_edma_xfrconfig_s
|
||||
uint8_t flags; /* See EDMA_CONFIG_* definitions */
|
||||
uint8_t ssize; /* Source data transfer size (see TCD_ATTR_SIZE_* definitions in rdware/. */
|
||||
uint8_t dsize; /* Destination data transfer size. */
|
||||
uint8_t ttype; /* Transfer type (see enum kinetis_edma_xfrtype_e). */
|
||||
#ifdef CONFIG_KINETIS_EDMA_EMLIM
|
||||
uint16_t nbytes; /* Bytes to transfer in a minor loop */
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user