diff --git a/arch/arm/src/sam3u/sam3u_dmac.c b/arch/arm/src/sam3u/sam3u_dmac.c index e52fed8800..7a686ca153 100755 --- a/arch/arm/src/sam3u/sam3u_dmac.c +++ b/arch/arm/src/sam3u/sam3u_dmac.c @@ -69,12 +69,13 @@ struct sam3u_dma_s { uint8_t chan; /* DMA channel number (0-6) */ - uint8_t flags; /* DMA channel flags */ bool inuse; /* TRUE: The DMA channel is in use */ + uint16_t flags; /* DMA channel flags */ uint32_t base; /* DMA register channel base address */ dma_callback_t callback; /* Callback invoked when the DMA completes */ void *arg; /* Argument passed to callback function */ - volatile uint16_t xfrsize; /* Total transfer size */ + uint16_t bufsize; /* Transfer buffer size in bytes */ + volatile uint16_t remaining; /* Total number of bytes remaining to be transferred */ }; /**************************************************************************** @@ -85,6 +86,22 @@ struct sam3u_dma_s static sem_t g_dmasem; +/* CTRLA field lookups */ + +static const uint32_t g_srcwidth[3] = +{ + DMACHAN_CTRLA_SRCWIDTH_BYTE, + DMACHAN_CTRLA_SRCWIDTH_HWORD, + DMACHAN_CTRLA_SRCWIDTH_WORD +}; + +static const uint32_t g_destwidth[3] = +{ + DMACHAN_CTRLA_DSTWIDTH_BYTE, + DMACHAN_CTRLA_DSTWIDTH_HWORD, + DMACHAN_CTRLA_DSTWIDTH_WORD +}; + /* This array describes the state of each DMA */ static struct sam3u_dma_s g_dma[CONFIG_SAM3U_NDMACHAN] = @@ -201,42 +218,23 @@ static inline void sam3u_settxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits) { uint32_t regval; - uint32_t flags; + unsigned int ndx; DEBUGASSERT(dmach && dmasize <= DMACHAN_CTRLA_BTSIZE_MAX); regval = (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT) | otherbits; /* Since this is a transmit, the source is described by the memeory selections */ - flags = dmach->flags & DMACH_FLAG_MEMWIDTH_MASK; - if (flags == DMACH_FLAG_MEMWIDTH_8BITS) - { - regval |= DMACHAN_CTRLA_SRCWIDTH_BYTE; - } - else if (flags == DMACH_FLAG_MEMWIDTH_16BITS) - { - regval |= DMACHAN_CTRLA_SRCWIDTH_HWORD; - } - else /* if (flags == DMACH_FLAG_MEMWIDTH_32BITS) */ - { - regval |= DMACHAN_CTRLA_SRCWIDTH_WORD; - } + ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT; + DEBUGASSERT(ndx < 3); + regval |= g_srcwidth[ndx]; + return regval; /* Since this is a transmit, the destination is described by the peripheral selections */ - flags = dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK; - if (flags == DMACH_FLAG_PERIPHWIDTH_8BITS) - { - regval |= DMACHAN_CTRLA_DSTWIDTH_BYTE; - } - else if (flags == DMACH_FLAG_PERIPHWIDTH_16BITS) - { - regval |= DMACHAN_CTRLA_DSTWIDTH_HWORD; - } - else /* if (flags == DMACH_FLAG_PERIPHWIDTH_32BITS) */ - { - regval |= DMACHAN_CTRLA_DSTWIDTH_WORD; - } + ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT; + DEBUGASSERT(ndx < 3); + regval |= g_destwidth[ndx]; return regval; } @@ -252,46 +250,110 @@ sam3u_settxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits static inline void sam3u_setrxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits) { - uint32_t regval; - uint32_t flags; + uint32_t regval; + unsigned int ndx; DEBUGASSERT(dmach && dmasize <= DMACHAN_CTRLA_BTSIZE_MAX); regval = (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT) | otherbits; /* Since this is a receive, the source is described by the peripheral selections */ - flags = dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK; - if (flags == DMACH_FLAG_PERIPHWIDTH_8BITS) - { - regval |= DMACHAN_CTRLA_SRCWIDTH_BYTE; - } - else if (flags == DMACH_FLAG_PERIPHWIDTH_16BITS) - { - regval |= DMACHAN_CTRLA_SRCWIDTH_HWORD; - } - else /* if (flags == DMACH_FLAG_PERIPHWIDTH_32BITS) */ - { - regval |= DMACHAN_CTRLA_SRCWIDTH_WORD; - } + ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT; + DEBUGASSERT(ndx < 3); + regval |= g_srcwidth[ndx]; /* Since this is a receive, the destination is described by the memory selections */ - flags = dmach->flags & DMACH_FLAG_MEMWIDTH_MASK; - if (flags == DMACH_FLAG_MEMWIDTH_8BITS) - { - regval |= DMACHAN_CTRLA_DSTWIDTH_BYTE; - } - else if (flags == DMACH_FLAG_MEMWIDTH_16BITS) - { - regval |= DMACHAN_CTRLA_DSTWIDTH_HWORD; - } - else /* if (flags == DMACH_FLAG_MEMWIDTH_32BITS) */ - { - regval |= DMACHAN_CTRLA_DSTWIDTH_WORD; - } + ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT; + DEBUGASSERT(ndx < 3); + regval |= g_destwidth[ndx]; return regval; } +/************************************************************************************ + * Name: sam3u_srcctrlb + * + * Description: + * Set source related CTRLB fields + * + ************************************************************************************/ + +static void sam3u_srcctrlb(struct sam3u_dma_s *dmach, bool lli, bool autoincr) +{ + uint32_t regval; + + /* Fetch CTRLB and clear the configurable bits */ + + regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET); + regval &= ~ (DMACHAN_CTRLB_SRCDSCR | DMACHAN_CTRLB_SRCINCR_MASK | 1<<31); + + /* Disable the source descriptor if we are not using the LLI transfer mode */ + + if (lli) + { + regval |= DMACHAN_CTRLB_SRCDSCR; + } + + /* Select address incrementing */ + + regval |= autoincr ? DMACHAN_CTRLB_SRCINCR_INCR ? DMACHAN_CTRLB_SRCINCR_FIXED; + + /* Save the updated CTRLB value */ + + putreg32(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET) +} + +/************************************************************************************ + * Name: sam3u_destctrlb + * + * Description: + * Set destination related CTRLB fields + * + ************************************************************************************/ + +static void sam3u_destctrlb(struct sam3u_dma_s *dmach, bool lli, bool autoincr) +{ + uint32_t regval; + + /* Fetch CTRLB and clear the configurable bits */ + + regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET); + regval &= ~ (DMACHAN_CTRLB_DSTDSCR | DMACHAN_CTRLB_DSTINCR_MASK); + + /* Disable the source descriptor if we are not using the LLI transfer mode */ + + if (lli) + { + regval |= DMACHAN_CTRLB_DSTDSCR; + } + + /* Select address incrementing */ + + regval |= autoincr ? DMACHAN_CTRLB_DESTINCR_INCR ? DMACHAN_CTRLB_DESTINCR_FIXED; + + /* Save the updated CTRLB value */ + + putreg32(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET) +} + +/************************************************************************************ + * Name: sam3u_flowcontrol + * + * Description: + * Select flow control + * + ************************************************************************************/ + +static inline void sam3u_flowcontrol(struct sam3u_dma_s *dmach, uint32_t setting) +{ + uint32_t regval; + + regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET); + regval &= ~(DMACHAN_CTRLB_FC_MASK); + regval |= setting; + putreg(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET); +} + /************************************************************************************ * Name: sam3u_dmainterrupt * @@ -355,6 +417,11 @@ void weak_function up_dmainitialize(void) * the required FIFO size and flow control capabilities (determined by * dma_flags) then gives the caller exclusive access to the DMA channel. * + * The naming convention in all of the DMA interfaces is that one side is + * the 'peripheral' and the other is 'memory'. Howerver, the interface + * could still be used if, for example, both sides were memory although + * the naming would be awkward. + * * Returned Value: * If a DMA channel if the required FIFO size is available, this function * returns a non-NULL, void* DMA channel handle. NULL is returned on any @@ -362,7 +429,7 @@ void weak_function up_dmainitialize(void) * ****************************************************************************/ -DMA_HANDLE sam3u_dmachannel(uint8_t dmach_flags) +DMA_HANDLE sam3u_dmachannel(uint16_t dmach_flags) { struct sam3u_dma_s *dmach; unsigned int chndx; @@ -406,7 +473,7 @@ DMA_HANDLE sam3u_dmachannel(uint8_t dmach_flags) /* Initialize the transfer state */ - dmach->xfrsize = 0; + dmach->remaining = 0; break; } } diff --git a/arch/arm/src/sam3u/sam3u_dmac.h b/arch/arm/src/sam3u/sam3u_dmac.h index 817b3934c4..c92c45edf3 100755 --- a/arch/arm/src/sam3u/sam3u_dmac.h +++ b/arch/arm/src/sam3u/sam3u_dmac.h @@ -360,8 +360,8 @@ /* DMAC Channel n [n = 0..3] Control B Register */ -#define DMACHAN_CTRLB_SRCDSCR (1 << 16) /* Bit 16: Source uffer Descriptor Fetch operation disabled */ -#define DMACHAN_CTRLB_DSTDSCR (1 << 20) /* Bit 20: Dest Buffer Descriptor Fetch operation disabled */ +#define DMACHAN_CTRLB_SRCDSCR (1 << 16) /* Bit 16: Source buffer descriptor fetch operation disabled */ +#define DMACHAN_CTRLB_DSTDSCR (1 << 20) /* Bit 20: Dest buffer descriptor fetch operation disabled */ #define DMACHAN_CTRLB_FC_SHIFT (21) /* Bits 21-22: Flow controller */ #define DMACHAN_CTRLB_FC_MASK (3 << DMACHAN_CTRLB_FC_SHIFT) # define DMACHAN_CTRLB_FC_M2M (0 << DMACHAN_CTRLB_FC_SHIFT) /* Memory-to-Memory */ @@ -380,7 +380,7 @@ /* DMAC Channel n [n = 0..3] Configuration Register */ -#define DMACHAN_CFG_SRCPER_SHIFT (0) /* Bits 0-3: Chanel source associated with peripheral ID */ +#define DMACHAN_CFG_SRCPER_SHIFT (0) /* Bits 0-3: Channel source associated with peripheral ID */ #define DMACHAN_CFG_SRCPER_MASK (15 << DMACHAN_CFG_SRCPER_SHIFT) #define DMACHAN_CFG_DSTPER_SHIFT (4) /* Bits 4-7: Channel dest associated with peripheral ID */ #define DMACHAN_CFG_DSTPER_MASK (15 << DMACHAN_CFG_DSTPER_SHIFT) @@ -401,6 +401,12 @@ # define DMACHAN_CFG_FIFOCFG_HALF (1 << DMACHAN_CFG_FIFOCFG_SHIFT) /* Half FIFO size */ # define DMACHAN_CFG_FIFOCFG_SINGLE (2 << DMACHAN_CFG_FIFOCFG_SHIFT) /* Single AHB access */ +/* DMA Peripheral IDs *******************************************************************/ + +#define DMACHAN_PID_MCI0 0 +#define DMACHAN_PID_SSC 3 +#define DMACHAN_PID_MCI1 13 + /**************************************************************************************** * Public Types ****************************************************************************************/ diff --git a/arch/arm/src/sam3u/sam3u_hsmci.c b/arch/arm/src/sam3u/sam3u_hsmci.c index 144a6026a4..b47290debb 100755 --- a/arch/arm/src/sam3u/sam3u_hsmci.c +++ b/arch/arm/src/sam3u/sam3u_hsmci.c @@ -120,7 +120,9 @@ /* DMA configuration flags */ #define DMA_FLAGS \ - (DMACH_FLAG_FIFO_8BYTES|DMACH_FLAG_SRCWIDTH_32BITS|DMACH_FLAG_DESTWIDTH_32BITS|DMACH_FLAG_MEMINCREMENT) + ((DMACHAN_PID_MCI0 << DMACH_FLAG_PERIPHPID_SHIFT) | \ + DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHLLIMODE | DMACH_FLAG_PERIPHWIDTH_32BITS | \ + DMACH_FLAG_MEMLLIMODE | DMACH_FLAG_MEMWIDTH_32BITS | DMACH_FLAG_MEMINCREMENT) /* FIFO sizes */ diff --git a/arch/arm/src/sam3u/sam3u_internal.h b/arch/arm/src/sam3u/sam3u_internal.h index 41e0585064..d3fdd26a5d 100755 --- a/arch/arm/src/sam3u/sam3u_internal.h +++ b/arch/arm/src/sam3u/sam3u_internal.h @@ -297,23 +297,39 @@ * be used if, for example, both sides were memory although the naming would be awkward) */ -#define DMACH_FLAG_FLOWCONTROL (1 << 0) /* Bit 0: Channel supports flow control */ -#define DMACH_FLAG_FIFOSIZE_SHIFT (1) /* Bit 1: Size of DMA FIFO */ -#define DMACH_FLAG_FIFOSIZE_MASK (1 << DMACH_FLAG_FIFOSIZE_SHIFT) -# define DMACH_FLAG_FIFO_8BYTES (0 << DMACH_FLAG_FIFOSIZE_SHIFT) /* 8 bytes */ -# define DMACH_FLAG_FIFO_32BYTES (1 << DMACH_FLAG_FIFOSIZE_SHIFT) /* 32 bytes */ -#define DMACH_FLAG_PERIPHWIDTH_SHIFT (2) /* Bits 2-3: Peripheral width */ -#define DMACH_FLAG_PERIPHWIDTH_MASK (3 << DMACH_FLAG_PERIPHWIDTH_SHIFT) -# define DMACH_FLAG_PERIPHWIDTH_8BITS (0 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 8 bits */ -# define DMACH_FLAG_PERIPHWIDTH_16BITS (1 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 16 bits */ -# define DMACH_FLAG_PERIPHWIDTH_32BITS (2 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 16 bits */ -#define DMACH_FLAG_PERIPHINCREMENT (1 << 4) /* Bit 4: Autoincrement peripheral address */ -#define DMACH_FLAG_MEMWIDTH_SHIFT (5) /* Bits 5-6: Memory width */ -#define DMACH_FLAG_MEMWIDTH_MASK (3 << DMACH_FLAG_MEMWIDTH_SHIFT) -# define DMACH_FLAG_MEMWIDTH_8BITS (0 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 8 bits */ -# define DMACH_FLAG_MEMWIDTH_16BITS (1 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */ -# define DMACH_FLAG_MEMWIDTH_32BITS (2 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */ -#define DMACH_FLAG_MEMINCREMENT (1 << 7) /* Bit 7: Autoincrement memory address */ +/* Unchange-able properties of the channel */ + +#define DMACH_FLAG_FLOWCONTROL (1 << 0) /* Bit 0: Channel supports flow control */ +#define DMACH_FLAG_FIFOSIZE_SHIFT (1) /* Bit 1: Size of DMA FIFO */ +#define DMACH_FLAG_FIFOSIZE_MASK (1 << DMACH_FLAG_FIFOSIZE_SHIFT) +# define DMACH_FLAG_FIFO_8BYTES (0 << DMACH_FLAG_FIFOSIZE_SHIFT) /* 8 bytes */ +# define DMACH_FLAG_FIFO_32BYTES (1 << DMACH_FLAG_FIFOSIZE_SHIFT) /* 32 bytes */ + +/* Peripheral endpoint characteristics */ + +#define DMACH_FLAG_PERIPHPID_SHIFT (2) /* Bits 2-5: Peripheral PID */ +#define DMACH_FLAG_PERIPHPID_MASK (15 << DMACH_FLAG_PERIPHPID_SHIFT) +#define DMACH_FLAG_PERIPHH2SEL (1 << 6) /* Bits 6: HW handshaking */ +#define DMACH_FLAG_PERIPHWIDTH_SHIFT (7) /* Bits 7-8: Peripheral width */ +#define DMACH_FLAG_PERIPHWIDTH_MASK (3 << DMACH_FLAG_PERIPHWIDTH_SHIFT) +# define DMACH_FLAG_PERIPHWIDTH_8BITS (0 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 8 bits */ +# define DMACH_FLAG_PERIPHWIDTH_16BITS (1 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 16 bits */ +# define DMACH_FLAG_PERIPHWIDTH_32BITS (2 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 16 bits */ +#define DMACH_FLAG_PERIPHINCREMENT (1 << 9) /* Bit 9: Autoincrement peripheral address */ +#define DMACH_FLAG_PERIPHLLIMODE (1 << 10) /* Bit 10: Use link list descriptors */ + +/* Memory endpoint characteristics */ + +#define DMACH_FLAG_MEMPID_SHIFT (11) /* Bits 11-14: Memory PID */ +#define DMACH_FLAG_MEMPID_MASK (15 << DMACH_FLAG_PERIPHPID_SHIFT) +#define DMACH_FLAG_MEMH2SEL (1 << 15) /* Bits 15: HW handshaking */ +#define DMACH_FLAG_MEMWIDTH_SHIFT (16) /* Bits 16-17: Memory width */ +#define DMACH_FLAG_MEMWIDTH_MASK (3 << DMACH_FLAG_MEMWIDTH_SHIFT) +# define DMACH_FLAG_MEMWIDTH_8BITS (0 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 8 bits */ +# define DMACH_FLAG_MEMWIDTH_16BITS (1 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */ +# define DMACH_FLAG_MEMWIDTH_32BITS (2 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */ +#define DMACH_FLAG_MEMINCREMENT (1 << 18) /* Bit 18: Autoincrement memory address */ +#define DMACH_FLAG_MEMLLIMODE (1 << 19) /* Bit 19: Use link list descriptors */ /************************************************************************************ * Public Types @@ -492,6 +508,11 @@ EXTERN void sam3u_gpioirqdisable(int irq); * the required FIFO size and flow control capabilities (determined by * dma_flags) then gives the caller exclusive access to the DMA channel. * + * The naming convention in all of the DMA interfaces is that one side is + * the 'peripheral' and the other is 'memory'. Howerver, the interface + * could still be used if, for example, both sides were memory although + * the naming would be awkward. + * * Returned Value: * If a DMA channel if the required FIFO size is available, this function * returns a non-NULL, void* DMA channel handle. NULL is returned on any @@ -499,7 +520,7 @@ EXTERN void sam3u_gpioirqdisable(int irq); * ****************************************************************************/ -EXTERN DMA_HANDLE sam3u_dmachannel(uint8_t dmach_flags); +EXTERN DMA_HANDLE sam3u_dmachannel(uint32_t dmach_flags); /**************************************************************************** * Name: sam3u_dmafree @@ -520,7 +541,7 @@ EXTERN void sam3u_dmafree(DMA_HANDLE handle); * Name: sam3u_dmatxsetup * * Description: - * Configure DMA for transmit (memory to periphal) before using + * Configure DMA for transmit (memory to periphal). * ****************************************************************************/ @@ -531,7 +552,7 @@ EXTERN void sam3u_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, * Name: sam3u_dmarxsetup * * Description: - * Configure DMA for receive (peripheral to memory) before using + * Configure DMA for receive (peripheral to memory). * ****************************************************************************/