s32k1xx_edma:Add Looping and cleanup
s32k1xx:EDMA Use aligned_data macros s32k1xx:EDMA CONFIG_ARCH_CHIP_S32K14x->CONFIG_ARCH_CHIP_S32K14X s32k1xx:EDMA remove FAR keyword s32k1xx:EDMA Fix C&P error from Kinetis s32k1xx:EDMA TCD Alignment of 32 Bytes to support Scatter/Gather s32k1xx:EDMA Fix access violation s32k1xx:dmamux fixed missing closing paren
This commit is contained in:
parent
c18b5602e8
commit
3813320c31
@ -200,6 +200,7 @@ menu "S32K1XX Peripheral Selection"
|
|||||||
config S32K1XX_EDMA
|
config S32K1XX_EDMA
|
||||||
bool "eDMA"
|
bool "eDMA"
|
||||||
default n
|
default n
|
||||||
|
select ARCH_DMA
|
||||||
|
|
||||||
config S32K1XX_ENET
|
config S32K1XX_ENET
|
||||||
bool "Ethernet"
|
bool "Ethernet"
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#if defined(CONFIG_ARCH_CHIP_S32K11X)
|
#if defined(CONFIG_ARCH_CHIP_S32K11X)
|
||||||
# define S32K1XX_NDMACH 4
|
# define S32K1XX_NDMACH 4
|
||||||
#elif defined(CONFIG_ARCH_CHIP_S32K14X
|
#elif defined(CONFIG_ARCH_CHIP_S32K14X)
|
||||||
# define S32K1XX_NDMACH 16
|
# define S32K1XX_NDMACH 16
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
#if defined(CONFIG_ARCH_CHIP_S32K11X)
|
#if defined(CONFIG_ARCH_CHIP_S32K11X)
|
||||||
# define S32K1XX_EDMA_NCHANNELS 4
|
# define S32K1XX_EDMA_NCHANNELS 4
|
||||||
#elif defined(CONFIG_ARCH_CHIP_S32K14x)
|
#elif defined(CONFIG_ARCH_CHIP_S32K14X)
|
||||||
# define S32K1XX_EDMA_NCHANNELS 16
|
# define S32K1XX_EDMA_NCHANNELS 16
|
||||||
#else
|
#else
|
||||||
# error "Unknown number of DMA channels for this S32K1xx part"
|
# error "Unknown number of DMA channels for this S32K1xx part"
|
||||||
@ -837,8 +837,8 @@
|
|||||||
* Public Types
|
* Public Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* In-memory representation of the 32-byte Transfer Control Descriptor
|
/* Hardware representation of the 32-byte Transfer
|
||||||
* (TCD)
|
* Control Descriptor (TCD)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct s32k1xx_edmatcd_s
|
struct s32k1xx_edmatcd_s
|
||||||
|
@ -34,8 +34,8 @@
|
|||||||
#define S32K1XX_AIPS_LITE_BASE 0x40000000 /* Peripheral bridge (AIPS-Lite) */
|
#define S32K1XX_AIPS_LITE_BASE 0x40000000 /* Peripheral bridge (AIPS-Lite) */
|
||||||
# define S32K1XX_FLASHCFG_BASE 0x40000400 /* FLASH Configuration bytes */
|
# define S32K1XX_FLASHCFG_BASE 0x40000400 /* FLASH Configuration bytes */
|
||||||
# define S32K1XX_MSCM_BASE 0x40001000 /* MSCM */
|
# define S32K1XX_MSCM_BASE 0x40001000 /* MSCM */
|
||||||
# define S32K1XX_DMAC_BASE 0x40008000 /* DMA controller */
|
# define S32K1XX_EDMA_BASE 0x40008000 /* EDMA controller */
|
||||||
# define S32K1XX_DMADESC_BASE 0x40008000 /* DMA transfer control descriptors */
|
# define S32K1XX_EDMADESC_BASE 0x40008000 /* EDMA transfer control descriptors */
|
||||||
# define S32K1XX_MPU_BASE 0x4000d000 /* MPU */
|
# define S32K1XX_MPU_BASE 0x4000d000 /* MPU */
|
||||||
# define S32K1XX_GPIOCTL_BASE 0x4000f000 /* GPIO controller */
|
# define S32K1XX_GPIOCTL_BASE 0x4000f000 /* GPIO controller */
|
||||||
# define S32K1XX_GPIOALIAS_BASE 0x400ff000 /* GPIO controller (alias) */
|
# define S32K1XX_GPIOALIAS_BASE 0x400ff000 /* GPIO controller (alias) */
|
||||||
|
@ -86,22 +86,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_ARMV7M_DCACHE
|
#ifdef CONFIG_ARMV7M_DCACHE
|
||||||
/* Align to the cache line size which we assume is >= 8 */
|
# define EDMA_ALIGN ARMV7M_DCACHE_LINESIZE
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Special alignment is not required in this case,
|
/* 32 byte alignment for TCDs is required for scatter gather */
|
||||||
* but we will align to 8-bytes
|
|
||||||
*/
|
|
||||||
|
|
||||||
# define EDMA_ALIGN 8
|
#define EDMA_ALIGN 32
|
||||||
# define EDMA_ALIGN_MASK 7
|
|
||||||
# define EDMA_ALIGN_UP(n) (((n) + 7) & ~7)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define EDMA_ALIGN_MASK (EDMA_ALIGN - 1)
|
||||||
|
#define EDMA_ALIGN_UP(n) (((n) + EDMA_ALIGN_MASK) & ~EDMA_ALIGN_MASK)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -119,10 +113,10 @@ enum s32k1xx_dmastate_e
|
|||||||
|
|
||||||
struct s32k1xx_dmach_s
|
struct s32k1xx_dmach_s
|
||||||
{
|
{
|
||||||
uint8_t chan; /* DMA channel number (0-S32K1XX_EDMA_NCHANNELS) */
|
uint8_t chan; /* DMA channel number (0-S32K1XX_EDMA_NCHANNELS) */
|
||||||
bool inuse; /* true: The DMA channel is in use */
|
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 s32k1xx_dmastate_e */
|
||||||
uint8_t state; /* Channel state. See enum s32k1xx_dmastate_e */
|
uint8_t dmamux; /* The DMAMUX channel selection */
|
||||||
uint32_t flags; /* DMA channel flags */
|
uint32_t flags; /* DMA channel flags */
|
||||||
edma_callback_t callback; /* Callback invoked when the DMA completes */
|
edma_callback_t callback; /* Callback invoked when the DMA completes */
|
||||||
void *arg; /* Argument passed to callback function */
|
void *arg; /* Argument passed to callback function */
|
||||||
@ -338,18 +332,13 @@ static inline void s32k1xx_tcd_chanlink(uint8_t flags,
|
|||||||
|
|
||||||
if (linkch == NULL || flags == EDMA_CONFIG_LINKTYPE_LINKNONE)
|
if (linkch == NULL || flags == EDMA_CONFIG_LINKTYPE_LINKNONE)
|
||||||
{
|
{
|
||||||
#if 0 /* Already done */
|
|
||||||
/* No link or no link channel provided */
|
/* No link or no link channel provided */
|
||||||
|
|
||||||
/* Disable minor links */
|
/* Disable minor links is done in s32k1xx_tcd_configure */
|
||||||
|
|
||||||
tcd->citer &= ~EDMA_TCD_CITER_ELINK;
|
|
||||||
tcd->biter &= ~EDMA_TCD_BITER_ELINK;
|
|
||||||
|
|
||||||
/* Disable major link */
|
/* Disable major link */
|
||||||
|
|
||||||
tcd->csr &= ~EDMA_TCD_CSR_MAJORELINK;
|
tcd->csr &= ~EDMA_TCD_CSR_MAJORELINK;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (flags == EDMA_CONFIG_LINKTYPE_MINORLINK) /* Minor link config */
|
else if (flags == EDMA_CONFIG_LINKTYPE_MINORLINK) /* Minor link config */
|
||||||
{
|
{
|
||||||
@ -405,13 +394,16 @@ static inline void s32k1xx_tcd_configure(struct s32k1xx_edmatcd_s *tcd,
|
|||||||
tcd->attr = EDMA_TCD_ATTR_SSIZE(config->ssize) | /* Transfer Attributes */
|
tcd->attr = EDMA_TCD_ATTR_SSIZE(config->ssize) | /* Transfer Attributes */
|
||||||
EDMA_TCD_ATTR_DSIZE(config->dsize);
|
EDMA_TCD_ATTR_DSIZE(config->dsize);
|
||||||
tcd->nbytes = config->nbytes;
|
tcd->nbytes = config->nbytes;
|
||||||
tcd->slast = tcd->slast;
|
tcd->slast = config->flags & EDMA_CONFIG_LOOPSRC ? -config->iter : 0;
|
||||||
tcd->daddr = config->daddr;
|
tcd->daddr = config->daddr;
|
||||||
tcd->doff = config->doff;
|
tcd->doff = config->doff;
|
||||||
tcd->citer = config->iter & EDMA_TCD_CITER_CITER_MASK;
|
tcd->citer = config->iter & EDMA_TCD_CITER_CITER_MASK;
|
||||||
tcd->biter = config->iter & EDMA_TCD_BITER_BITER_MASK;
|
tcd->biter = config->iter & EDMA_TCD_BITER_BITER_MASK;
|
||||||
tcd->csr = EDMA_TCD_CSR_DREQ; /* Assume last transfer */
|
tcd->csr = config->flags & EDMA_CONFIG_LOOP_MASK ?
|
||||||
tcd->dlastsga = 0;
|
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 */
|
/* And special case flags */
|
||||||
|
|
||||||
@ -440,6 +432,10 @@ static void s32k1xx_tcd_instantiate(struct s32k1xx_dmach_s *dmach,
|
|||||||
|
|
||||||
/* Push tcd into hardware TCD register */
|
/* Push tcd into hardware TCD register */
|
||||||
|
|
||||||
|
/* Clear DONE bit first, otherwise ESG cannot be set */
|
||||||
|
|
||||||
|
putreg16(0, base + S32K1XX_EDMA_TCD_CSR_OFFSET);
|
||||||
|
|
||||||
putreg32(tcd->saddr, base + S32K1XX_EDMA_TCD_SADDR_OFFSET);
|
putreg32(tcd->saddr, base + S32K1XX_EDMA_TCD_SADDR_OFFSET);
|
||||||
putreg16(tcd->soff, base + S32K1XX_EDMA_TCD_SOFF_OFFSET);
|
putreg16(tcd->soff, base + S32K1XX_EDMA_TCD_SOFF_OFFSET);
|
||||||
putreg16(tcd->attr, base + S32K1XX_EDMA_TCD_ATTR_OFFSET);
|
putreg16(tcd->attr, base + S32K1XX_EDMA_TCD_ATTR_OFFSET);
|
||||||
@ -450,9 +446,6 @@ static void s32k1xx_tcd_instantiate(struct s32k1xx_dmach_s *dmach,
|
|||||||
putreg16(tcd->citer, base + S32K1XX_EDMA_TCD_CITER_ELINK_OFFSET);
|
putreg16(tcd->citer, base + S32K1XX_EDMA_TCD_CITER_ELINK_OFFSET);
|
||||||
putreg32(tcd->dlastsga, base + S32K1XX_EDMA_TCD_DLASTSGA_OFFSET);
|
putreg32(tcd->dlastsga, base + S32K1XX_EDMA_TCD_DLASTSGA_OFFSET);
|
||||||
|
|
||||||
/* Clear DONE bit first, otherwise ESG cannot be set */
|
|
||||||
|
|
||||||
putreg16(0, base + S32K1XX_EDMA_TCD_CSR_OFFSET);
|
|
||||||
putreg16(tcd->csr, base + S32K1XX_EDMA_TCD_CSR_OFFSET);
|
putreg16(tcd->csr, base + S32K1XX_EDMA_TCD_CSR_OFFSET);
|
||||||
|
|
||||||
putreg16(tcd->biter, base + S32K1XX_EDMA_TCD_BITER_ELINK_OFFSET);
|
putreg16(tcd->biter, base + S32K1XX_EDMA_TCD_BITER_ELINK_OFFSET);
|
||||||
@ -488,25 +481,25 @@ static void s32k1xx_dmaterminate(struct s32k1xx_dmach_s *dmach, int result)
|
|||||||
regval8 = EDMA_CERQ(chan);
|
regval8 = EDMA_CERQ(chan);
|
||||||
putreg8(regval8, S32K1XX_EDMA_CERQ);
|
putreg8(regval8, S32K1XX_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 = S32K1XX_EDMA_TCD_CSR(chan);
|
regaddr = S32K1XX_EDMA_TCD_CSR(chan);
|
||||||
putreg16(0, regaddr);
|
putreg16(0, regaddr);
|
||||||
|
|
||||||
/* Cancel next TCD transfer. */
|
/* Cancel next TCD transfer. */
|
||||||
|
|
||||||
regaddr = S32K1XX_EDMA_TCD_DLASTSGA(chan);
|
regaddr = S32K1XX_EDMA_TCD_DLASTSGA(chan);
|
||||||
putreg16(0, regaddr);
|
putreg32(0, regaddr);
|
||||||
|
|
||||||
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
||||||
/* Return all allocated TCDs to the free list */
|
/* Return all allocated TCDs to the free list */
|
||||||
|
|
||||||
for (tcd = dmach->head; tcd != NULL; tcd = next)
|
for (tcd = dmach->head; tcd != NULL; tcd = next)
|
||||||
{
|
{
|
||||||
next = (struct s32k1xx_edmatcd_s *)tcd->dlastsga;
|
/* If channel looped to itself we are done
|
||||||
|
* if not continue to free tcds in chain
|
||||||
|
*/
|
||||||
|
|
||||||
|
next = dmach->flags & EDMA_CONFIG_LOOPDEST ?
|
||||||
|
NULL : (struct s32k1xx_edmatcd_s *)tcd->dlastsga;
|
||||||
s32k1xx_tcd_free(tcd);
|
s32k1xx_tcd_free(tcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,15 +507,6 @@ static void s32k1xx_dmaterminate(struct s32k1xx_dmach_s *dmach, int result)
|
|||||||
dmach->tail = NULL;
|
dmach->tail = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check for an Rx (memory-to-peripheral/memory-to-memory) DMA transfer */
|
|
||||||
|
|
||||||
if (dmach->ttype == EMDA_MEM2MEM || dmach->ttype == EMDA_PERIPH2MEM)
|
|
||||||
{
|
|
||||||
/* Invalidate the cache to force reloads from memory. */
|
|
||||||
|
|
||||||
#warning Missing logic
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform the DMA complete callback */
|
/* Perform the DMA complete callback */
|
||||||
|
|
||||||
if (dmach->callback)
|
if (dmach->callback)
|
||||||
@ -556,13 +540,13 @@ static int s32k1xx_edma_interrupt(int irq, void *context, void *arg)
|
|||||||
{
|
{
|
||||||
struct s32k1xx_dmach_s *dmach;
|
struct s32k1xx_dmach_s *dmach;
|
||||||
uintptr_t regaddr;
|
uintptr_t regaddr;
|
||||||
uint32_t regval32;
|
uint32_t regval32;
|
||||||
uint16_t regval16;
|
uint16_t regval16;
|
||||||
uint8_t regval8;
|
uint8_t regval8;
|
||||||
uint8_t chan;
|
uint8_t chan;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* 'arg' should the DMA channel instance. */
|
/* 'arg' should be the DMA channel instance. */
|
||||||
|
|
||||||
dmach = (struct s32k1xx_dmach_s *)arg;
|
dmach = (struct s32k1xx_dmach_s *)arg;
|
||||||
DEBUGASSERT(dmach != NULL);
|
DEBUGASSERT(dmach != NULL);
|
||||||
@ -584,7 +568,7 @@ static int s32k1xx_edma_interrupt(int irq, void *context, void *arg)
|
|||||||
/* Clear the pending eDMA channel interrupt */
|
/* Clear the pending eDMA channel interrupt */
|
||||||
|
|
||||||
regval8 = EDMA_CINT(chan);
|
regval8 = EDMA_CINT(chan);
|
||||||
putreg32(regval8, S32K1XX_EDMA_CINT);
|
putreg8(regval8, S32K1XX_EDMA_CINT);
|
||||||
|
|
||||||
/* Get the eDMA TCD Control and Status register value. */
|
/* Get the eDMA TCD Control and Status register value. */
|
||||||
|
|
||||||
@ -604,7 +588,7 @@ static int s32k1xx_edma_interrupt(int irq, void *context, void *arg)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
#if CONFIG_S32K1XX_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)
|
if (dmach->callback != NULL)
|
||||||
{
|
{
|
||||||
@ -612,7 +596,7 @@ static int s32k1xx_edma_interrupt(int irq, void *context, void *arg)
|
|||||||
false, OK);
|
false, OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return OK;
|
||||||
#else
|
#else
|
||||||
/* Otherwise the interrupt was not expected! */
|
/* Otherwise the interrupt was not expected! */
|
||||||
|
|
||||||
@ -623,8 +607,18 @@ static int s32k1xx_edma_interrupt(int irq, void *context, void *arg)
|
|||||||
|
|
||||||
/* Terminate the transfer when it is done. */
|
/* Terminate the transfer when it is done. */
|
||||||
|
|
||||||
s32k1xx_dmaterminate(dmach, result);
|
if ((dmach->flags & EDMA_CONFIG_LOOP_MASK) == 0)
|
||||||
|
{
|
||||||
|
s32k1xx_dmaterminate(dmach, result);
|
||||||
|
}
|
||||||
|
else if (dmach->callback != NULL)
|
||||||
|
{
|
||||||
|
dmach->callback((DMACH_HANDLE)dmach, dmach->arg,
|
||||||
|
true, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -661,7 +655,7 @@ static int s32k1xx_error_interrupt(int irq, void *context, void *arg)
|
|||||||
/* Clear the pending error interrupt status. */
|
/* Clear the pending error interrupt status. */
|
||||||
|
|
||||||
regval8 = EDMA_CERR(chan);
|
regval8 = EDMA_CERR(chan);
|
||||||
putreg32(regval8, S32K1XX_EDMA_CERR);
|
putreg8(regval8, S32K1XX_EDMA_CERR);
|
||||||
|
|
||||||
/* Remove the bit from the sample ERR register so that perhaps we
|
/* Remove the bit from the sample ERR register so that perhaps we
|
||||||
* can exit this loop early.
|
* can exit this loop early.
|
||||||
@ -755,24 +749,12 @@ void weak_function arm_dma_initialize(void)
|
|||||||
|
|
||||||
/* Attach DMA interrupt vectors. */
|
/* Attach DMA interrupt vectors. */
|
||||||
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH0, s32k1xx_edma_interrupt, &g_edma.dmach[0]);
|
for (i = 0; i < S32K1XX_EDMA_NCHANNELS; i++)
|
||||||
irq_attach(S32K1XX_IRQ_DMACH1, s32k1xx_edma_interrupt, &g_edma.dmach[1]);
|
{
|
||||||
irq_attach(S32K1XX_IRQ_DMACH2, s32k1xx_edma_interrupt, &g_edma.dmach[2]);
|
irq_attach(S32K1XX_IRQ_DMACH0 + i,
|
||||||
irq_attach(S32K1XX_IRQ_DMACH3, s32k1xx_edma_interrupt, &g_edma.dmach[3]);
|
s32k1xx_edma_interrupt, &g_edma.dmach[i]);
|
||||||
#if S32K1XX_EDMA_NCHANNELS > 4
|
}
|
||||||
irq_attach(S32K1XX_IRQ_DMACH4, s32k1xx_edma_interrupt, &g_edma.dmach[4]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH5, s32k1xx_edma_interrupt, &g_edma.dmach[5]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH6, s32k1xx_edma_interrupt, &g_edma.dmach[6]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH7, s32k1xx_edma_interrupt, &g_edma.dmach[7]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH8, s32k1xx_edma_interrupt, &g_edma.dmach[8]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH9, s32k1xx_edma_interrupt, &g_edma.dmach[9]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH10, s32k1xx_edma_interrupt, &g_edma.dmach[10]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH11, s32k1xx_edma_interrupt, &g_edma.dmach[11]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH12, s32k1xx_edma_interrupt, &g_edma.dmach[12]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH13, s32k1xx_edma_interrupt, &g_edma.dmach[13]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH14, s32k1xx_edma_interrupt, &g_edma.dmach[14]);
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH15, s32k1xx_edma_interrupt, &g_edma.dmach[15]);
|
|
||||||
#endif
|
|
||||||
/* Attach the DMA error interrupt vector */
|
/* Attach the DMA error interrupt vector */
|
||||||
|
|
||||||
irq_attach(S32K1XX_IRQ_DMACH_ERR, s32k1xx_error_interrupt, NULL);
|
irq_attach(S32K1XX_IRQ_DMACH_ERR, s32k1xx_error_interrupt, NULL);
|
||||||
@ -790,6 +772,14 @@ void weak_function arm_dma_initialize(void)
|
|||||||
|
|
||||||
regaddr = S32K1XX_EDMA_TCD_CSR(i);
|
regaddr = S32K1XX_EDMA_TCD_CSR(i);
|
||||||
putreg16(0, regaddr);
|
putreg16(0, regaddr);
|
||||||
|
|
||||||
|
/* Set all TCD entries to 0 so that biter and citer
|
||||||
|
* will be 0 when DONE is not set so that s32k1xx_dmach_getcount
|
||||||
|
* reports 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset((void *)S32K1XX_EDMA_TCD_BASE(i), 0,
|
||||||
|
sizeof(struct s32k1xx_edmatcd_s));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear all pending DMA channel interrupts */
|
/* Clear all pending DMA channel interrupts */
|
||||||
@ -800,24 +790,10 @@ void weak_function arm_dma_initialize(void)
|
|||||||
* controller).
|
* controller).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH0);
|
for (i = 0; i < S32K1XX_EDMA_NCHANNELS; i++)
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH1);
|
{
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH2);
|
up_enable_irq(S32K1XX_IRQ_DMACH0 + i);
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH3);
|
}
|
||||||
#if S32K1XX_EDMA_NCHANNELS > 4
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH4);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH5);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH6);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH7);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH8);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH9);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH10);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH11);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH12);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH13);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH14);
|
|
||||||
up_enable_irq(S32K1XX_IRQ_DMACH15);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Enable the DMA error interrupt */
|
/* Enable the DMA error interrupt */
|
||||||
|
|
||||||
@ -837,7 +813,6 @@ void weak_function arm_dma_initialize(void)
|
|||||||
* Settings include:
|
* Settings include:
|
||||||
*
|
*
|
||||||
* DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required)
|
* DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required)
|
||||||
* DMAMUX_CHCFG_AON DMA Channel Always Enable (optional)
|
|
||||||
* DMAMUX_CHCFG_TRIG DMA Channel Trigger Enable (optional)
|
* DMAMUX_CHCFG_TRIG DMA Channel Trigger Enable (optional)
|
||||||
* DMAMUX_CHCFG_ENBL DMA Mux Channel Enable (required)
|
* DMAMUX_CHCFG_ENBL DMA Mux Channel Enable (required)
|
||||||
*
|
*
|
||||||
@ -858,7 +833,7 @@ void weak_function arm_dma_initialize(void)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
DMACH_HANDLE s32k1xx_dmach_alloc(uint32_t dmamux, uint8_t dchpri)
|
DMACH_HANDLE s32k1xx_dmach_alloc(uint8_t dmamux, uint8_t dchpri)
|
||||||
{
|
{
|
||||||
struct s32k1xx_dmach_s *dmach;
|
struct s32k1xx_dmach_s *dmach;
|
||||||
unsigned int chndx;
|
unsigned int chndx;
|
||||||
@ -884,6 +859,7 @@ DMACH_HANDLE s32k1xx_dmach_alloc(uint32_t dmamux, uint8_t dchpri)
|
|||||||
dmach = candidate;
|
dmach = candidate;
|
||||||
dmach->inuse = true;
|
dmach->inuse = true;
|
||||||
dmach->state = S32K1XX_DMA_IDLE;
|
dmach->state = S32K1XX_DMA_IDLE;
|
||||||
|
dmach->dmamux = dmamux;
|
||||||
|
|
||||||
/* Clear any pending interrupts on the channel */
|
/* Clear any pending interrupts on the channel */
|
||||||
|
|
||||||
@ -896,10 +872,9 @@ DMACH_HANDLE s32k1xx_dmach_alloc(uint32_t dmamux, uint8_t dchpri)
|
|||||||
regval8 = EDMA_CERQ(chndx);
|
regval8 = EDMA_CERQ(chndx);
|
||||||
putreg8(regval8, S32K1XX_EDMA_CERQ);
|
putreg8(regval8, S32K1XX_EDMA_CERQ);
|
||||||
|
|
||||||
/* Set the DMAMUX register associated with this channel */
|
/* Disable the associated DMAMUX for now */
|
||||||
|
|
||||||
regaddr = S32K1XX_DMAMUX_CHCFG(chndx);
|
putreg8(0, S32K1XX_DMAMUX_CHCFG(chndx));
|
||||||
putreg32(dmamux, regaddr);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -936,7 +911,6 @@ DMACH_HANDLE s32k1xx_dmach_alloc(uint32_t dmamux, uint8_t dchpri)
|
|||||||
void s32k1xx_dmach_free(DMACH_HANDLE handle)
|
void s32k1xx_dmach_free(DMACH_HANDLE handle)
|
||||||
{
|
{
|
||||||
struct s32k1xx_dmach_s *dmach = (struct s32k1xx_dmach_s *)handle;
|
struct s32k1xx_dmach_s *dmach = (struct s32k1xx_dmach_s *)handle;
|
||||||
uintptr_t regaddr;
|
|
||||||
uint8_t regval8;
|
uint8_t regval8;
|
||||||
|
|
||||||
dmainfo("dmach: %p\n", dmach);
|
dmainfo("dmach: %p\n", dmach);
|
||||||
@ -958,8 +932,7 @@ void s32k1xx_dmach_free(DMACH_HANDLE handle)
|
|||||||
|
|
||||||
/* Disable the associated DMAMUX */
|
/* Disable the associated DMAMUX */
|
||||||
|
|
||||||
regaddr = S32K1XX_DMAMUX_CHCFG(dmach->chan);
|
putreg8(0, S32K1XX_DMAMUX_CHCFG(dmach->chan));
|
||||||
putreg32(0, regaddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -995,12 +968,16 @@ int s32k1xx_dmach_xfrsetup(DMACH_HANDLE *handle,
|
|||||||
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
||||||
struct s32k1xx_edmatcd_s *tcd;
|
struct s32k1xx_edmatcd_s *tcd;
|
||||||
struct s32k1xx_edmatcd_s *prev;
|
struct s32k1xx_edmatcd_s *prev;
|
||||||
|
uint16_t mask = config->flags & EDMA_CONFIG_INTMAJOR ? 0 :
|
||||||
|
EDMA_TCD_CSR_INTMAJOR;
|
||||||
#endif
|
#endif
|
||||||
uintptr_t regaddr;
|
uintptr_t regaddr;
|
||||||
uint16_t regval16;
|
uint16_t regval16;
|
||||||
|
|
||||||
DEBUGASSERT(dmach != NULL);
|
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_S32K1XX_EDMA_NTCD > 0
|
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
||||||
/* Scatter/gather DMA is supported */
|
/* Scatter/gather DMA is supported */
|
||||||
@ -1029,7 +1006,6 @@ int s32k1xx_dmach_xfrsetup(DMACH_HANDLE *handle,
|
|||||||
|
|
||||||
dmach->head = tcd;
|
dmach->head = tcd;
|
||||||
dmach->tail = tcd;
|
dmach->tail = tcd;
|
||||||
dmach->ttype = config->ttype;
|
|
||||||
|
|
||||||
/* And instantiate the first TCD in the DMA channel TCD registers. */
|
/* And instantiate the first TCD in the DMA channel TCD registers. */
|
||||||
|
|
||||||
@ -1037,11 +1013,9 @@ int s32k1xx_dmach_xfrsetup(DMACH_HANDLE *handle,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Cannot mix transfer types (only because of cache-related operations.
|
/* Cannot mix transfer types */
|
||||||
* this restriction could be removed with some effort).
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (dmach->ttype != config->ttype)
|
if (dmach->flags & EDMA_CONFIG_LOOP_MASK)
|
||||||
{
|
{
|
||||||
s32k1xx_tcd_free(tcd);
|
s32k1xx_tcd_free(tcd);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1053,8 +1027,9 @@ int s32k1xx_dmach_xfrsetup(DMACH_HANDLE *handle,
|
|||||||
|
|
||||||
prev = dmach->tail;
|
prev = dmach->tail;
|
||||||
regval16 = prev->csr;
|
regval16 = prev->csr;
|
||||||
regval16 &= ~EDMA_TCD_CSR_DREQ;
|
regval16 &= ~(EDMA_TCD_CSR_DREQ | mask);
|
||||||
regval16 |= EDMA_TCD_CSR_ESG;
|
regval16 |= EDMA_TCD_CSR_ESG;
|
||||||
|
|
||||||
prev->csr = regval16;
|
prev->csr = regval16;
|
||||||
|
|
||||||
prev->dlastsga = (uint32_t)tcd;
|
prev->dlastsga = (uint32_t)tcd;
|
||||||
@ -1076,7 +1051,7 @@ int s32k1xx_dmach_xfrsetup(DMACH_HANDLE *handle,
|
|||||||
|
|
||||||
regaddr = S32K1XX_EDMA_TCD_CSR(dmach->chan);
|
regaddr = S32K1XX_EDMA_TCD_CSR(dmach->chan);
|
||||||
regval16 = getreg16(regaddr);
|
regval16 = getreg16(regaddr);
|
||||||
regval16 &= ~EDMA_TCD_CSR_DREQ;
|
regval16 &= ~(EDMA_TCD_CSR_DREQ | mask);
|
||||||
regval16 |= EDMA_TCD_CSR_ESG;
|
regval16 |= EDMA_TCD_CSR_ESG;
|
||||||
putreg16(regval16, regaddr);
|
putreg16(regval16, regaddr);
|
||||||
|
|
||||||
@ -1115,34 +1090,9 @@ int s32k1xx_dmach_xfrsetup(DMACH_HANDLE *handle,
|
|||||||
modifyreg16(regaddr, 0, EDMA_TCD_CSR_INTMAJOR);
|
modifyreg16(regaddr, 0, EDMA_TCD_CSR_INTMAJOR);
|
||||||
#endif
|
#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 == EMDA_MEM2MEM || dmach->ttype == EMDA_PERIPH2MEM)
|
putreg8(dmach->dmamux, S32K1XX_DMAMUX_CHCFG(dmach->chan));
|
||||||
{
|
|
||||||
/* 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 == EMDA_MEM2MEM || dmach->ttype == EMDA_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
dmach->state = S32K1XX_DMA_CONFIGURED;
|
dmach->state = S32K1XX_DMA_CONFIGURED;
|
||||||
return OK;
|
return OK;
|
||||||
@ -1155,10 +1105,10 @@ int s32k1xx_dmach_xfrsetup(DMACH_HANDLE *handle,
|
|||||||
* Start the DMA transfer. This function should be called after the final
|
* Start the DMA transfer. This function should be called after the final
|
||||||
* call to s32k1xx_dmach_xfrsetup() in order to avoid race conditions.
|
* call to s32k1xx_dmach_xfrsetup() in order to avoid race conditions.
|
||||||
*
|
*
|
||||||
* At the conclusion of each major DMA loop, a callback to the user
|
* At the conclusion of each major DMA loop, a callback to
|
||||||
* provided function is made: |For "normal" DMAs, this will correspond to
|
* the user-provided function is made: For "normal" DMAs, this will
|
||||||
* the DMA DONE interrupt; for scatter gather DMAs, multiple interrupts
|
* correspond to the DMA DONE interrupt; for scatter gather DMAs,
|
||||||
* will be generated with the final being the DONE interrupt.
|
* this will be generated with the final TCD.
|
||||||
*
|
*
|
||||||
* At the conclusion of the DMA, the DMA channel is reset, all TCDs are
|
* 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
|
* freed, and the callback function is called with the the success/fail
|
||||||
@ -1191,14 +1141,13 @@ int s32k1xx_dmach_start(DMACH_HANDLE handle, edma_callback_t callback,
|
|||||||
|
|
||||||
DEBUGASSERT(dmach != NULL && dmach->state == S32K1XX_DMA_CONFIGURED);
|
DEBUGASSERT(dmach != NULL && dmach->state == S32K1XX_DMA_CONFIGURED);
|
||||||
chan = dmach->chan;
|
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 */
|
/* Save the callback info. This will be invoked when the DMA completes */
|
||||||
|
|
||||||
flags = spin_lock_irqsave(NULL);
|
flags = spin_lock_irqsave(NULL);
|
||||||
dmach->callback = callback;
|
dmach->callback = callback;
|
||||||
dmach->arg = arg;
|
dmach->arg = arg;
|
||||||
dmach->state = S32K1XX_DMA_ACTIVE;
|
|
||||||
|
|
||||||
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
#if CONFIG_S32K1XX_EDMA_NTCD > 0
|
||||||
/* Although it is not recommended, it might be possible to call this
|
/* Although it is not recommended, it might be possible to call this
|
||||||
@ -1208,6 +1157,8 @@ int s32k1xx_dmach_start(DMACH_HANDLE handle, edma_callback_t callback,
|
|||||||
if (dmach->state != S32K1XX_DMA_ACTIVE)
|
if (dmach->state != S32K1XX_DMA_ACTIVE)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
dmach->state = S32K1XX_DMA_ACTIVE;
|
||||||
|
|
||||||
/* Enable channel ERROR interrupts */
|
/* Enable channel ERROR interrupts */
|
||||||
|
|
||||||
regval8 = EDMA_SEEI(chan);
|
regval8 = EDMA_SEEI(chan);
|
||||||
@ -1216,7 +1167,7 @@ int s32k1xx_dmach_start(DMACH_HANDLE handle, edma_callback_t callback,
|
|||||||
/* Enable the DMA request for this channel */
|
/* Enable the DMA request for this channel */
|
||||||
|
|
||||||
regval8 = EDMA_SERQ(chan);
|
regval8 = EDMA_SERQ(chan);
|
||||||
putreg8(regval8, S32K1XX_EDMA_SERQ_OFFSET);
|
putreg8(regval8, S32K1XX_EDMA_SERQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(NULL, flags);
|
spin_unlock_irqrestore(NULL, flags);
|
||||||
|
@ -122,6 +122,18 @@
|
|||||||
# define EDMA_CONFIG_LINKTYPE_MINORLINK (1 << EDMA_CONFIG_LINKTYPE_SHIFT) /* Channel link after each minor loop */
|
# 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_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
|
* Public Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -130,19 +142,19 @@ typedef void *DMACH_HANDLE;
|
|||||||
typedef void (*edma_callback_t)(DMACH_HANDLE handle,
|
typedef void (*edma_callback_t)(DMACH_HANDLE handle,
|
||||||
void *arg, bool done, int result);
|
void *arg, bool done, int result);
|
||||||
|
|
||||||
/* eDMA transfer type */
|
|
||||||
|
|
||||||
enum s32k1xx_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 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* This structure holds the source/destination transfer attribute
|
/* This structure holds the source/destination transfer attribute
|
||||||
* configuration.
|
* configuration.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eDMA transfer sizes */
|
||||||
|
|
||||||
|
enum s32k1xx_edma_sizes_e
|
||||||
|
{
|
||||||
|
EDMA_8BIT = 0, /* Transfer data size 8 */
|
||||||
|
EDMA_16BIT = 1, /* Transfer data size 16 */
|
||||||
|
EDMA_32BIT = 2, /* Transfer data size 32 */
|
||||||
|
};
|
||||||
|
|
||||||
struct s32k1xx_edma_xfrconfig_s
|
struct s32k1xx_edma_xfrconfig_s
|
||||||
{
|
{
|
||||||
uint32_t saddr; /* Source data address. */
|
uint32_t saddr; /* Source data address. */
|
||||||
@ -153,7 +165,6 @@ struct s32k1xx_edma_xfrconfig_s
|
|||||||
uint8_t flags; /* See EDMA_CONFIG_* definitions */
|
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 rdware/. */
|
||||||
uint8_t dsize; /* Destination data transfer size. */
|
uint8_t dsize; /* Destination data transfer size. */
|
||||||
uint8_t ttype; /* Transfer type (see enum s32k1xx_edma_xfrtype_e). */
|
|
||||||
#ifdef CONFIG_S32K1XX_EDMA_EMLIM
|
#ifdef CONFIG_S32K1XX_EDMA_EMLIM
|
||||||
uint16_t nbytes; /* Bytes to transfer in a minor loop */
|
uint16_t nbytes; /* Bytes to transfer in a minor loop */
|
||||||
#else
|
#else
|
||||||
@ -264,7 +275,7 @@ extern "C"
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
DMACH_HANDLE s32k1xx_dmach_alloc(uint32_t dmamux, uint8_t dchpri);
|
DMACH_HANDLE s32k1xx_dmach_alloc(uint8_t dmamux, uint8_t dchpri);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: s32k1xx_dmach_free
|
* Name: s32k1xx_dmach_free
|
||||||
|
Loading…
Reference in New Issue
Block a user