SAM3/4 DMA fixes in general for SPI DMA in particular

This commit is contained in:
Gregory Nutt 2014-03-14 11:25:16 -06:00
parent dba6cca886
commit e2ab7d8a33
7 changed files with 137 additions and 65 deletions

View File

@ -6995,4 +6995,7 @@
well have (temporarily) broken SPI for the SAM3/4/ family (2014-3-13).
* configs/sam4e-ek/src/sam_at25.c and sam_hsmci.c: Added support for
the AT25 serial FLASH. Restructured the logic that registers the
HSMCI block driver (2014-3-13).
HSMCI block driver (2014-3-13).
* arch/arm/src/sam34/sam_dmac.c and sam_spi.c: Fixes to DMA in general
and to SPI in particular (2014-3-14).

View File

@ -340,11 +340,15 @@ config SAM34_EIC
depends on ARCH_CHIP_SAM4L || ARCH_CHIP_SAM4E
config SAM34_DMAC0
bool "DMA controller (DMAC)"
bool "DMA controller (DMAC0)"
default n
depends on ARCH_CHIP_SAM3U || ARCH_CHIP_SAM3X || ARCH_CHIP_SAM3A || ARCH_CHIP_SAM4E
select ARCH_DMA
config SAM34_DMAC1
bool
default n
config SAM34_EMAC
bool "Ethernet MAC (EMAC)"
default n

View File

@ -71,10 +71,12 @@
/* DMA channel registers */
#define SAM_DMACHAN_OFFSET(n) (0x003c+((n)*0x28))
#define SAM_DMACHAN0_OFFSET 0x003c /* 0x3c-0x60: Channel 0 */
#define SAM_DMACHAN1_OFFSET 0x0064 /* 0x64-0x88: Channel 1 */
#define SAM_DMACHAN2_OFFSET 0x008c /* 0x8c-0xb0: Channel 2 */
#define SAM_DMACHAN3_OFFSET 0x00b4 /* 0xb4-0xd8: Channel 3 */
#define SAM_DMACHAN0_OFFSET 0x003c /* 0x003c-0x0060: Channel 0 */
#define SAM_DMACHAN1_OFFSET 0x0064 /* 0x0064-0x0088: Channel 1 */
#define SAM_DMACHAN2_OFFSET 0x008c /* 0x008c-0x00b0: Channel 2 */
#define SAM_DMACHAN3_OFFSET 0x00b4 /* 0x00b4-0x00d8: Channel 3 */
#define SAM_DMACHAN4_OFFSET 0x00dc /* 0x00dc-0x0103: Channel 4 */
#define SAM_DMACHAN5_OFFSET 0x0104 /* 0x0104-0x0128: Channel 5 */
#define SAM_DMACHAN_SADDR_OFFSET 0x0000 /* DMAC Channel Source Address Register */
#define SAM_DMACHAN_DADDR_OFFSET 0x0004 /* DMAC Channel Destination Address Register */
@ -115,6 +117,8 @@
#define SAM_DMACHAN1_BASE (SAM_DMAC_BASE+SAM_DMACHAN1_OFFSET)
#define SAM_DMACHAN2_BASE (SAM_DMAC_BASE+SAM_DMACHAN2_OFFSET)
#define SAM_DMACHAN3_BASE (SAM_DMAC_BASE+SAM_DMACHAN3_OFFSET)
#define SAM_DMACHAN4_BASE (SAM_DMAC_BASE+SAM_DMACHAN4_OFFSET)
#define SAM_DMACHAN5_BASE (SAM_DMAC_BASE+SAM_DMACHAN5_OFFSET)
#define SAM_DMACHAN_SADDR(n) (SAM_DMACHAN_BASE(n)+SAM_DMACHAN_SADDR_OFFSET)
#define SAM_DMACHAN_DADDR(n) (SAM_DMACHAN_BASE(n)+SAM_DMACHAN_DADDR_OFFSET)
@ -361,10 +365,19 @@
/* DMAC Channel n [n = 0..3] Descriptor Address Register -- 32-bit address*/
/* DMAC Channel n [n = 0..3] Control A Register */
#define DMACHAN_CTRLA_BTSIZE_MAX (0xfff)
#define DMACHAN_CTRLA_BTSIZE_SHIFT (0) /* Bits 0-11: Buffer Transfer Size */
#define DMACHAN_CTRLA_BTSIZE_MASK (DMACHAN_CTRLA_BTSIZE_MAX << DMACHAN_CTRLA_BTSIZE_SHIFT)
# define DMACHAN_CTRLA_BTSIZE(n) ((uint32_t)(n) << DMACHAN_CTRLA_BTSIZE_SHIFT)
#if defined(CONFIG_ARCH_CHIP_SAM3U) || defined(CONFIG_ARCH_CHIP_SAM3X) || \
defined(CONFIG_ARCH_CHIP_SAM3A)
# define DMACHAN_CTRLA_BTSIZE_MAX (0xfff)
# define DMACHAN_CTRLA_BTSIZE_SHIFT (0) /* Bits 0-11: Buffer Transfer Size */
# define DMACHAN_CTRLA_BTSIZE_MASK (DMACHAN_CTRLA_BTSIZE_MAX << DMACHAN_CTRLA_BTSIZE_SHIFT)
# define DMACHAN_CTRLA_BTSIZE(n) ((uint32_t)(n) << DMACHAN_CTRLA_BTSIZE_SHIFT)
#elif defined(CONFIG_ARCH_CHIP_SAM3X) || defined(CONFIG_ARCH_CHIP_SAM3A) || \
defined(CONFIG_ARCH_CHIP_SAM4E)
# define DMACHAN_CTRLA_BTSIZE_MAX (0xffff)
# define DMACHAN_CTRLA_BTSIZE_SHIFT (0) /* Bits 0-15: Buffer Transfer Size */
# define DMACHAN_CTRLA_BTSIZE_MASK (DMACHAN_CTRLA_BTSIZE_MAX << DMACHAN_CTRLA_BTSIZE_SHIFT)
# define DMACHAN_CTRLA_BTSIZE(n) ((uint32_t)(n) << DMACHAN_CTRLA_BTSIZE_SHIFT)
#endif
#if defined(CONFIG_ARCH_CHIP_SAM3U) || defined(CONFIG_ARCH_CHIP_SAM3X) || \
defined(CONFIG_ARCH_CHIP_SAM3A)
@ -458,15 +471,35 @@
/* DMA Hardware interface numbers *******************************************************/
#if defined(CONFIG_ARCH_CHIP_SAM3U) || defined(CONFIG_ARCH_CHIP_SAM3X) || \
defined(CONFIG_ARCH_CHIP_SAM3A)
# define DMACHAN_INTF_MCI0 0
# define DMACHAN_INTF_SSC 3
# define DMACHAN_INTF_MCI1 13
#endif
#if defined(CONFIG_ARCH_CHIP_SAM3U)
#if defined(CONFIG_ARCH_CHIP_SAM4E)
# define DMACHAN_INTF_HSMCI 0 /* HSMCI Transmit/Receive */
# define DMACHAN_INTF_HSMCI0 0
# define DMACHAN_INTF_SPI0TX 1 /* SPI0 Transmit */
# define DMACHAN_INTF_SPI0RX 2 /* SPI0 Receive */
# define DMACHAN_INTF_SSC0TX 3 /* SSC0 Transmit */
# define DMACHAN_INTF_SSC0RX 4 /* SSC0 Receive */
# define DMACHAN_INTF_PWM0EV0 5 /* PWM0 Event Line 0 */
# define DMACHAN_INTF_PWM0EV1 6 /* PWM0 Event Line 1 */
# define DMACHAN_INTF_TIO0 7 /* TIO Output of TC Ch. 0 */
#elif defined(CONFIG_ARCH_CHIP_SAM3X) || defined(CONFIG_ARCH_CHIP_SAM3A)
# define DMACHAN_INTF_HSMCI0 0 /* HSMCI0 Transmit/Receive */
# define DMACHAN_INTF_SPI0TX 1 /* SPI0 Transmit */
# define DMACHAN_INTF_SPI0RX 2 /* SPI0 Receive */
# define DMACHAN_INTF_SSC0TX 3 /* SSC0 Transmit */
# define DMACHAN_INTF_SSC0RX 4 /* SSC0 Receive */
# define DMACHAN_INTF_SPI0TX 5 /* SPI1 Transmit */
# define DMACHAN_INTF_SPI0RX 6 /* SPI1 Receive */
# define DMACHAN_INTF_USART0TX 11 /* USART0 Transmit */
# define DMACHAN_INTF_USART0RX 12 /* USART0 Receive */
# define DMACHAN_INTF_USART1TX 13 /* USART1 Transmit */
# define DMACHAN_INTF_USART1RX 14 /* USART1 Receive */
# define DMACHAN_INTF_PWM0TX 15 /* PWM0 Transmit */
#elif defined(CONFIG_ARCH_CHIP_SAM4E)
# define DMACHAN_INTF_HSMCI0 0 /* HSMCI Transmit/Receive */
# define DMACHAN_INTF_SPI0TX 1 /* SPI Transmit */
# define DMACHAN_INTF_SPI0RX 2 /* SPI Receive */
# define DMACHAN_INTF_USART0TX 3 /* USART0 Transmit */
@ -475,7 +508,8 @@
# define DMACHAN_INTF_USART1RX 6 /* USART1 Receive */
# define DMACHAN_INTF_AESTX 11 /* AES Transmit */
# define DMACHAN_INTF_AESRX 12 /* AES Receive */
# define DMACHAN_INTF_PWMTX 13 /* PWM Transmit */
# define DMACHAN_INTF_PWM0TX 13 /* PWM0 Transmit */
#endif
/****************************************************************************************

View File

@ -98,7 +98,7 @@
* Private Types
****************************************************************************/
/* This structure descibes one DMA channel */
/* This structure describes one DMA channel */
struct sam_dma_s
{
@ -153,8 +153,8 @@ static struct dma_linklist_s g_linklist[CONFIG_SAM34_NLLDESC];
static struct sam_dma_s g_dma[SAM34_NDMACHAN] =
{
#if defined(CONFIG_ARCH_CHIP_ATSAM3U4E)
/* the AT91SAM3U4E has four DMA channels. The FIFOs for channels 0-2 are
#if defined(CONFIG_ARCH_CHIP_SAM3U)
/* The SAM3U has four DMA channels. The FIFOs for channels 0-2 are
* 8 bytes in size; channel 3 is 32 bytes.
*/
@ -179,10 +179,50 @@ static struct sam_dma_s g_dma[SAM34_NDMACHAN] =
},
{
.chan = 3,
.flags = (DMACH_FLAG_FIFO_32BYTES | DMACH_FLAG_FLOWCONTROL),
.flags = DMACH_FLAG_FIFO_32BYTES,
.base = SAM_DMACHAN3_BASE,
}
#elif defined(CONFIG_ARCH_CHIP_SAM3X) || defined(CONFIG_ARCH_CHIP_SAM3A)
/* The SAM3A/X have six DMA channels. The FIFOs for channels 0-2 are
* 8 bytes in size; channel 3 is 32 bytes.
*/
#if SAM34_NDMACHAN != 6
# error "Logic here assumes SAM34_NDMACHAN is 6"
#endif
{
.chan = 0,
.flags = DMACH_FLAG_FIFO_8BYTES,
.base = SAM_DMACHAN0_BASE,
},
{
.chan = 1,
.flags = DMACH_FLAG_FIFO_8BYTES,
.base = SAM_DMACHAN1_BASE,
},
{
.chan = 2,
.flags = DMACH_FLAG_FIFO_8BYTES,
.base = SAM_DMACHAN2_BASE,
},
{
.chan = 3,
.flags = DMACH_FLAG_FIFO_32BYTES,
.base = SAM_DMACHAN3_BASE,
}
{
.chan = 4,
.flags = DMACH_FLAG_FIFO_8BYTES,
.base = SAM_DMACHAN4_BASE,
}
{
.chan = 5,
.flags = DMACH_FLAG_FIFO_32BYTES,
.base = SAM_DMACHAN5_BASE,
}
#elif defined(CONFIG_ARCH_CHIP_SAM4E)
/* The SAM4E16E, SAM4E8E, SAM4E16C, and SAM4E8C have four DMA channels.
*
@ -212,7 +252,7 @@ static struct sam_dma_s g_dma[SAM34_NDMACHAN] =
},
{
.chan = 3,
.flags = (DMACH_FLAG_FIFO_32BYTES | DMACH_FLAG_FLOWCONTROL),
.flags = DMACH_FLAG_FIFO_32BYTES,
.base = SAM_DMACHAN3_BASE,
}
@ -300,19 +340,6 @@ static unsigned int sam_fifosize(uint8_t chflags)
}
}
/****************************************************************************
* Name: sam_flowcontrol
*
* Description:
* Decode the FIFO flow control from the flags
*
****************************************************************************/
static inline bool sam_flowcontrol(uint8_t chflags)
{
return ((chflags & DMACH_FLAG_FLOWCONTROL) != 0);
}
/****************************************************************************
* Name: sam_fifocfg
*
@ -834,6 +861,7 @@ static inline uint32_t sam_rxctrlb(struct sam_dma_s *dmach)
{
regval |= DMACHAN_CTRLB_DSTINCR_FIXED;
}
return regval;
}
@ -1375,12 +1403,12 @@ void weak_function up_dmainitialize(void)
DMA_HANDLE sam_dmachannel(uint32_t chflags)
{
struct sam_dma_s *dmach;
unsigned int fifosize;
unsigned int chndx;
/* Get the search parameters */
bool flowcontrol = sam_flowcontrol(chflags);
unsigned int fifosize = sam_fifosize(chflags);
fifosize = sam_fifosize(chflags);
/* Search for an available DMA channel with at least the requested FIFO
* size.
@ -1393,8 +1421,7 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
{
struct sam_dma_s *candidate = &g_dma[chndx];
if (!candidate->inuse &&
(sam_fifosize(candidate->flags) >= fifosize) &&
(!flowcontrol || sam_flowcontrol(chflags)))
(sam_fifosize(candidate->flags) >= fifosize))
{
dmach = candidate;
dmach->inuse = true;
@ -1411,13 +1438,13 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
putreg32(DMAC_CHDR_DIS(chndx), SAM_DMAC_CHDR);
/* Set the DMA channel flags, retaining the fifo size and flow
* control settings which are inherent properties of the FIFO
* and cannot be changed.
/* Set the DMA channel flags, retaining the fifo size setting
* which is an inherent properties of the FIFO and cannot be
* changed.
*/
dmach->flags &= (DMACH_FLAG_FLOWCONTROL | DMACH_FLAG_FIFOSIZE_MASK);
dmach->flags |= (chflags & ~((DMACH_FLAG_FLOWCONTROL | DMACH_FLAG_FIFOSIZE_MASK)));
dmach->flags &= DMACH_FLAG_FIFOSIZE_MASK;
dmach->flags |= (chflags & ~DMACH_FLAG_FIFOSIZE_MASK);
break;
}
}
@ -1478,7 +1505,7 @@ void sam_dmafree(DMA_HANDLE handle)
* operation and so should be safe.
*/
dmach->flags &= (DMACH_FLAG_FLOWCONTROL | DMACH_FLAG_FIFOSIZE_MASK);
dmach->flags &= DMACH_FLAG_FIFOSIZE_MASK;
dmach->inuse = false; /* No longer in use */
}
@ -1496,6 +1523,7 @@ void sam_dmafree(DMA_HANDLE handle)
int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
{
struct sam_dma_s *dmach = (struct sam_dma_s *)handle;
ssize_t remaining = (ssize_t)nbytes;
size_t maxtransfer;
int ret = OK;
@ -1512,7 +1540,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > maxtransfer)
while (remaining > maxtransfer)
{
/* Set up the maximum size transfer */
@ -1521,7 +1549,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
{
/* Decrement the number of bytes left to transfer */
nbytes -= maxtransfer;
remaining -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@ -1541,9 +1569,9 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
/* Then set up the final buffer transfer */
if (ret == OK && nbytes > 0)
if (ret == OK && remaining > 0)
{
ret = sam_txbuffer(dmach, paddr, maddr, nbytes);
ret = sam_txbuffer(dmach, paddr, maddr, remaining);
}
return ret;
@ -1563,6 +1591,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
{
struct sam_dma_s *dmach = (struct sam_dma_s *)handle;
ssize_t remaining = (ssize_t)nbytes;
size_t maxtransfer;
int ret = OK;
@ -1579,7 +1608,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > maxtransfer)
while (remaining > maxtransfer)
{
/* Set up the maximum size transfer */
@ -1588,7 +1617,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
{
/* Decrement the number of bytes left to transfer */
nbytes -= maxtransfer;
remaining -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@ -1608,9 +1637,9 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
/* Then set up the final buffer transfer */
if (ret == OK && nbytes > 0)
if (ret == OK && remaining > 0)
{
ret = sam_rxbuffer(dmach, paddr, maddr, nbytes);
ret = sam_rxbuffer(dmach, paddr, maddr, remaining);
}
return ret;
@ -1638,12 +1667,12 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
if (dmach->llhead)
{
/* Save the callback info. This will be invoked whent the DMA commpletes */
/* Save the callback info. This will be invoked when the DMA completes */
dmach->callback = callback;
dmach->arg = arg;
/* Is this a single block transfer? Or a multiple block tranfer? */
/* Is this a single block transfer? Or a multiple block transfer? */
if (dmach->llhead == dmach->lltail)
{
@ -1654,6 +1683,7 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
ret = sam_multiple(dmach);
}
}
return ret;
}

View File

@ -65,7 +65,7 @@
/* Unchange-able properties of the channel */
#define DMACH_FLAG_FLOWCONTROL (1 << 0) /* Bit 0: Channel supports flow control */
/* Bit 0: Not used */
#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 */
@ -102,7 +102,7 @@
/* Memory endpoint characteristics */
#define DMACH_FLAG_MEMPID_SHIFT (14) /* Bits 14-17: Memory PID */
#define DMACH_FLAG_MEMPID_MASK (15 << DMACH_FLAG_PERIPHPID_SHIFT)
#define DMACH_FLAG_MEMPID_MASK (15 << DMACH_FLAG_MEMPID_SHIFT)
#define DMACH_FLAG_MEMH2SEL (1 << 18) /* Bits 18: HW handshaking */
#define DMACH_FLAG_MEMISPERIPH (1 << 19) /* Bits 19: 0=memory; 1=peripheral */
#define DMACH_FLAG_MEMWIDTH_SHIFT (20) /* Bits 20-21: Memory width */
@ -111,9 +111,10 @@
# define DMACH_FLAG_MEMWIDTH_16BITS (1 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */
# define DMACH_FLAG_MEMWIDTH_32BITS (2 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 32 bits */
#define DMACH_FLAG_MEMINCREMENT (1 << 22) /* Bit 22: Autoincrement memory address */
#define DMACH_FLAG_MEMCHUNKSIZE (1 << 22) /* Bit 23: Memory chunk size */
#define DMACH_FLAG_MEMCHUNKSIZE (1 << 23) /* Bit 23: Memory chunk size */
# define DMACH_FLAG_MEMCHUNKSIZE_1 (0) /* Memory chunksize = 1 */
# define DMACH_FLAG_MEMCHUNKSIZE_4 DMACH_FLAG_MEMCHUNKSIZE /* Memory chunksize = 4 */
/* Bits 24-31: Not used */
/************************************************************************************
* Public Types

View File

@ -125,7 +125,7 @@
#define DMA_FLAGS \
(DMACH_FLAG_FIFO_8BYTES | DMACH_FLAG_FIFOCFG_LARGEST | \
(DMACHAN_INTF_MCI0 << DMACH_FLAG_PERIPHPID_SHIFT) | \
(DMACHAN_INTF_HSMCI0 << DMACH_FLAG_PERIPHPID_SHIFT) | \
DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | \
DMACH_FLAG_PERIPHWIDTH_32BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
DMACH_FLAG_MEMWIDTH_32BITS | DMACH_FLAG_MEMINCREMENT | DMACH_FLAG_MEMCHUNKSIZE_4)

View File

@ -719,10 +719,10 @@ static void spi_dma_sampledone(struct sam_spics_s *spics)
"RX: At DMA callback");
}
sam_dmadump(spics->rxdma, &spics->rxdmaregs[DMA_END_TRANSFER],
"RX: At End-of-Transfer");
sam_dmadump(spics->txdma, &spics->txdmaregs[DMA_END_TRANSFER],
"TX: At End-of-Transfer");
sam_dmadump(spics->rxdma, &spics->rxdmaregs[DMA_END_TRANSFER],
"RX: At End-of-Transfer");
}
#endif
@ -1449,7 +1449,7 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
((uint32_t)spi->rxintf << DMACH_FLAG_PERIPHPID_SHIFT) |
DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH |
DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 |
((uint32_t)(0x3f) << DMACH_FLAG_MEMPID_SHIFT) |
((uint32_t)(15) << DMACH_FLAG_MEMPID_SHIFT) |
DMACH_FLAG_MEMWIDTH_8BITS | DMACH_FLAG_MEMCHUNKSIZE_1;
if (!rxbuffer)
@ -1471,7 +1471,7 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
((uint32_t)spi->txintf << DMACH_FLAG_PERIPHPID_SHIFT) |
DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH |
DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 |
((uint32_t)(0x3f) << DMACH_FLAG_MEMPID_SHIFT) |
((uint32_t)(15) << DMACH_FLAG_MEMPID_SHIFT) |
DMACH_FLAG_MEMWIDTH_8BITS | DMACH_FLAG_MEMCHUNKSIZE_1;
if (!txbuffer)