SAMA5 DMA: Need to flush caches; DMA channel depends upon direction of DMA; the maximum transfer size in bytes depends on the number of bytes per transfer

This commit is contained in:
Gregory Nutt 2013-08-08 13:15:52 -06:00
parent 9d81d4727c
commit 83cbd61c8c
4 changed files with 498 additions and 92 deletions

View File

@ -424,7 +424,7 @@ static inline uint32_t sam_txctrla(struct sam_dma_s *dmach,
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
{
dmasize >>= 2;
dmasize = (dmasize + 3) >> 2;
}
DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
@ -516,7 +516,7 @@ static inline uint32_t sam_rxctrla(struct sam_dma_s *dmach,
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
{
dmasize >>= 2;
dmasize = (dmasize + 3) >> 2;
}
DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
@ -1311,6 +1311,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;
size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@ -1318,18 +1319,31 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
/* The maximum transfer size in bytes depends upon the maximum number of
* transfers and the number of bytes per transfer.
*/
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
{
maxtransfer = 4 * DMACHAN_CTRLA_BTSIZE_MAX;
}
else
{
maxtransfer = DMACHAN_CTRLA_BTSIZE_MAX;
}
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > DMACHAN_CTRLA_BTSIZE_MAX)
while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
ret = sam_txbuffer(dmach, paddr, maddr, DMACHAN_CTRLA_BTSIZE_MAX);
ret = sam_txbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
nbytes -= DMACHAN_CTRLA_BTSIZE_MAX;
nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@ -1337,12 +1351,12 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
paddr += DMACHAN_CTRLA_BTSIZE_MAX;
paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
maddr += DMACHAN_CTRLA_BTSIZE_MAX;
maddr += maxtransfer;
}
}
}
@ -1371,6 +1385,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;
size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@ -1378,18 +1393,31 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
/* The maximum transfer size in bytes depends upon the maximum number of
* transfers and the number of bytes per transfer.
*/
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
{
maxtransfer = 4 * DMACHAN_CTRLA_BTSIZE_MAX;
}
else
{
maxtransfer = DMACHAN_CTRLA_BTSIZE_MAX;
}
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > DMACHAN_CTRLA_BTSIZE_MAX)
while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
ret = sam_rxbuffer(dmach, paddr, maddr, DMACHAN_CTRLA_BTSIZE_MAX);
ret = sam_rxbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
nbytes -= DMACHAN_CTRLA_BTSIZE_MAX;
nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@ -1397,12 +1425,12 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
paddr += DMACHAN_CTRLA_BTSIZE_MAX;
paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
maddr += DMACHAN_CTRLA_BTSIZE_MAX;
maddr += maxtransfer;
}
}
}

View File

@ -51,6 +51,7 @@
#include <arch/irq.h>
#include "up_arch.h"
#include "cache.h"
#include "up_internal.h"
#include "os_internal.h"
@ -110,6 +111,13 @@
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure maps a peripheral ID to an DMA channel */
struct sam_pidmap_s
{
uint8_t pid; /* Peripheral identifier */
uint8_t pchan; /* DMA channel */
};
/* This structure descibes one DMA channel */
@ -177,6 +185,86 @@ static const uint32_t g_fifocfg[3] =
DMAC_CH_CFG_FIFOCFG_ASAP
};
/* These tables map peripheral IDs to channels. A lookup is performed
* before each DMA transfer in order to map the peripheral IDs to the
* correct channel. This must be done because the channel can change with
* the direction of the transfer.
*
* DMA controller 0, RX DMA:
*/
static const struct sam_pidmap_s g_dmac0_rxchan[] =
{
{ SAM_PID_HSMCI0, DMAC0_CH_HSMCI0 }, /* HSMCI0 Receive/transmit */
{ SAM_PID_SPI0, DMAC0_CH_SPI0_RX }, /* SPI0 Receive */
{ SAM_PID_USART0, DMAC0_CH_USART0_RX }, /* USART0 Receive */
{ SAM_PID_USART1, DMAC0_CH_USART1_RX }, /* USART1 Receive */
{ SAM_PID_TWI0, DMAC0_CH_TWI0_RX }, /* TWI0 Receive */
{ SAM_PID_TWI1, DMAC0_CH_TWI1_RX }, /* TWI1 Receive */
{ SAM_PID_UART0, DMAC0_CH_UART0_RX }, /* UART0 Receive */
{ SAM_PID_SSC0, DMAC0_CH_SSC0_RX }, /* SSC0 Receive */
{ SAM_PID_SMD, DMAC0_CH_SMD_RX }, /* SMD Receive */
};
#define NDMAC0_RXCHANNELS (sizeof(g_dmac0_rxchan) / sizeof(struct sam_pidmap_s))
#ifdef CONFIG_SAMA5_DMAC0
/* DMA controller 0, TX DMA: */
static const struct sam_pidmap_s g_dmac0_txchan[] =
{
{ SAM_PID_HSMCI0, DMAC0_CH_HSMCI0 }, /* HSMCI0 Receive/transmit */
{ SAM_PID_SPI0, DMAC0_CH_SPI0_TX }, /* SPI0 Transmit */
{ SAM_PID_USART0, DMAC0_CH_USART0_TX }, /* USART0 Transmit */
{ SAM_PID_USART1, DMAC0_CH_USART1_TX }, /* USART1 Transmit */
{ SAM_PID_TWI0, DMAC0_CH_TWI0_TX }, /* TWI0 Transmit */
{ SAM_PID_TWI1, DMAC0_CH_TWI1_TX }, /* TWI1 Transmit */
{ SAM_PID_UART0, DMAC0_CH_UART0_TX }, /* UART0 Transmit */
{ SAM_PID_SSC0, DMAC0_CH_SSC0_TX }, /* SSC0 Transmit */
{ SAM_PID_SMD, DMAC0_CH_SMD_TX }, /* SMD Transmit */
};
#define NDMAC0_TXCHANNELS (sizeof(g_dmac0_txchan) / sizeof(struct sam_pidmap_s))
#endif
#ifdef CONFIG_SAMA5_DMAC1
/* DMA controller 1, RX DMA: */
static const struct sam_pidmap_s g_dmac1_rxchan[] =
{
{ SAM_PID_HSMCI1, DMAC1_CH_HSMCI1 }, /* HSMCI1 Receive/transmit */
{ SAM_PID_HSMCI2, DMAC1_CH_HSMCI2 }, /* HSMCI2 Receive/transmit */
{ SAM_PID_ADC, DMAC1_CH_ADC_RX }, /* ADC Receive */
{ SAM_PID_SSC1, DMAC1_CH_SSC1_RX }, /* SSC1 Receive */
{ SAM_PID_UART1, DMAC1_CH_UART1_RX }, /* UART1 Receive */
{ SAM_PID_USART2, DMAC1_CH_USART2_RX }, /* USART2 Receive */
{ SAM_PID_USART3, DMAC1_CH_USART3_RX }, /* USART3 Receive */
{ SAM_PID_TWI2, DMAC1_CH_TWI2_RX }, /* TWI2 Receive */
{ SAM_PID_DBGU, DMAC1_CH_DBGU_RX }, /* DBGU Receive */
{ SAM_PID_SPI1, DMAC1_CH_SPI1_RX }, /* SPI1 Receive */
{ SAM_PID_AES, DMAC1_CH_AES_RX }, /* AES Receive */
{ SAM_PID_TDES, DMAC1_CH_TDES_RX }, /* TDES Receive */
};
#define NDMAC1_RXCHANNELS (sizeof(g_dmac1_rxchan) / sizeof(struct sam_pidmap_s))
/* DMA controller 1, TX DMA: */
static const struct sam_pidmap_s g_dmac1_txchan[] =
{
{ SAM_PID_HSMCI1, DMAC1_CH_HSMCI1 }, /* HSMCI1 Receive/transmit */
{ SAM_PID_HSMCI2, DMAC1_CH_HSMCI2 }, /* HSMCI2 Receive/transmit */
{ SAM_PID_SSC1, DMAC1_CH_SSC1_TX }, /* SSC1 Transmit */
{ SAM_PID_UART1, DMAC1_CH_UART1_TX }, /* UART1 Transmit */
{ SAM_PID_USART2, DMAC1_CH_USART2_TX }, /* USART2 Transmit */
{ SAM_PID_USART3, DMAC1_CH_USART3_TX }, /* USART3 Transmit */
{ SAM_PID_TWI2, DMAC1_CH_TWI2_TX }, /* TWI2 Transmit */
{ SAM_PID_DBGU, DMAC1_CH_DBGU_TX }, /* DBGU Transmit */
{ SAM_PID_SPI1, DMAC1_CH_SPI1_TX }, /* SPI1 Transmit */
{ SAM_PID_SHA, DMAC1_CH_SHA_TX }, /* SHA Transmit */
{ SAM_PID_AES, DMAC1_CH_AES_TX }, /* AES Transmit */
{ SAM_PID_TDES, DMAC1_CH_TDES_TX }, /* TDES Transmit */
};
#define NDMAC1_TXCHANNELS (sizeof(g_dmac1_txchan) / sizeof(struct sam_pidmap_s))
#endif
#ifdef CONFIG_SAMA5_DMAC0
/* This array describes the available link list descriptors */
@ -533,6 +621,126 @@ static inline uint32_t sam_fifocfg(struct sam_dmach_s *dmach)
return g_fifocfg[ndx];
}
/****************************************************************************
* Name: sam_channel, sam_source_channel, and sam_sink_channel
*
* Description:
* Return the RX or TX channel associated with a PID. As a clarification:
*
* The source channel refers to the source of data for the DMA. This is,
* either (1) memory for a TX DMA or (2) a peripheral register for an RX
* DMA.
*
* The sink channel is the recipient of the DMA data. This is either
* (1) memory for an RX DMA, or (2) a peripheral register for a TX DMA.
*
****************************************************************************/
static uint8_t sam_channel(uint8_t pid, const struct sam_pidmap_s *table,
unsigned int nentries)
{
int i;
/* Search until either the entry with the matching PID is found or until
* all of the table entries have been examined without finding the PID.
*/
for (i = 0; i < nentries; i++, table++)
{
if (table->pid == pid)
{
return table->pchan;
}
}
fdbg("No channel found for pid %d\n", pid);
DEBUGPANIC();
return 0x3f;
}
static uint32_t sam_source_channel(struct sam_dmach_s *dmach, uint8_t pid,
bool isperiph)
{
const struct sam_pidmap_s *table;
unsigned int nentries;
if (!isperiph)
{
/* The source is memory, not a peripheral. */
return 0x3f;
}
else
#ifdef CONFIG_SAMA5_DMAC0
#ifdef CONFIG_SAMA5_DMAC1
if (dmach->dmac == 0)
#endif
{
/* Use the DMAC0 lookup table */
table = g_dmac0_rxchan;
nentries = NDMAC0_RXCHANNELS;
}
#endif
#ifdef CONFIG_SAMA5_DMAC1
#ifdef CONFIG_SAMA5_DMAC0
else
#endif
{
/* Use the DMAC1 lookup table */
table = g_dmac1_rxchan;
nentries = NDMAC1_RXCHANNELS;
}
#endif
return (uint32_t)sam_channel(pid, table, nentries);
}
static uint32_t sam_sink_channel(struct sam_dmach_s *dmach, uint8_t pid,
bool isperiph)
{
const struct sam_pidmap_s *table;
unsigned int nentries;
if (!isperiph)
{
/* The source is memory, not a peripheral. */
return 0x3f;
}
else
#ifdef CONFIG_SAMA5_DMAC0
#ifdef CONFIG_SAMA5_DMAC1
if (dmach->dmac == 0)
#endif
{
/* Use the DMAC0 lookup table */
table = g_dmac0_txchan;
nentries = NDMAC0_TXCHANNELS;
}
#endif
#ifdef CONFIG_SAMA5_DMAC1
#ifdef CONFIG_SAMA5_DMAC0
else
#endif
{
/* Use the DMAC1 lookup table */
table = g_dmac1_txchan;
nentries = NDMAC1_TXCHANNELS;
}
#endif
return (uint32_t)sam_channel(pid, table, nentries);
}
/****************************************************************************
* Name: sam_txcfg
*
@ -546,20 +754,28 @@ static inline uint32_t sam_txcfg(struct sam_dmach_s *dmach)
{
uint32_t regval;
unsigned int pid;
unsigned int pchan;
bool isperiph;
/* Set transfer (memory to peripheral) DMA channel configuration register */
pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
regval = ((pid & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
regval |= ((pid & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
isperiph = ((dmach->flags & DMACH_FLAG_MEMISPERIPH) != 0);
pchan = sam_source_channel(dmach, pid, isperiph);
pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
regval |= ((pid & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
regval |= ((pid & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
regval = ((pchan & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
regval |= ((pchan & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
regval |= sam_fifocfg(dmach);
pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
isperiph = ((dmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0);
pchan = sam_sink_channel(dmach, pid, isperiph);
regval |= ((pchan & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
regval |= ((pchan & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
regval |= sam_fifocfg(dmach);
return regval;
}
@ -576,20 +792,28 @@ static inline uint32_t sam_rxcfg(struct sam_dmach_s *dmach)
{
uint32_t regval;
unsigned int pid;
unsigned int pchan;
bool isperiph;
/* Set received (peripheral to memory) DMA channel config */
pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
regval = ((pid & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
regval |= ((pid & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
isperiph = ((dmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0);
pchan = sam_source_channel(dmach, pid, isperiph);
pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
regval |= ((pid & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
regval |= ((pid & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
regval = ((pchan & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
regval |= ((pchan & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
regval |= sam_fifocfg(dmach);
pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
isperiph = ((dmach->flags & DMACH_FLAG_MEMISPERIPH) != 0);
pchan = sam_sink_channel(dmach, pid, isperiph);
regval |= ((pchan & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
regval |= ((pchan & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
regval |= sam_fifocfg(dmach);
return regval;
}
@ -644,28 +868,73 @@ static inline uint32_t sam_txctrlabits(struct sam_dmach_s *dmach)
}
/****************************************************************************
* Name: sam_txctrla
* Name: sam_maxtxtransfer
*
* Description:
* Or in the variable CTRLA bits
* Maximum number of bytes that can be sent in on transfer
*
****************************************************************************/
static inline uint32_t sam_txctrla(struct sam_dmach_s *dmach,
uint32_t dmasize, uint32_t ctrla)
static size_t sam_maxtxtransfer(struct sam_dmach_s *dmach)
{
unsigned int chunksize;
size_t maxtransfer;
/* Set the buffer transfer size field. This is the number of transfers to
* be performed, that is, the number of source width transfers to perform.
*/
/* Adjust the the source transfer size for the source chunk size (memory
* chunk size)
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size). BTSIZE is "the number of transfers to be performed, that
* is, for writes it refers to the number of source width transfers
* to perform when DMAC is flow controller. For Reads, BTSIZE refers to
* the number of transfers completed on the Source Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK)
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
switch (chunksize)
{
default:
case 0: /* 1 byte */
maxtransfer = DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 1: /* 4 bytes */
maxtransfer = 4 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 2: /* 8 bytes */
maxtransfer = 8 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 3: /* 16 bytes */
maxtransfer = 16 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
}
return maxtransfer;
}
/****************************************************************************
* Name: sam_ntxtransfers
*
* Description:
* Number of TX transfers via DMA
*
****************************************************************************/
static uint32_t sam_ntxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
{
unsigned int chunksize;
/* Adjust the the source transfer size for the source chunk size (memory
* chunk size). BTSIZE is "the number of transfers to be performed, that
* is, for writes it refers to the number of source width transfers
* to perform when DMAC is flow controller. For Reads, BTSIZE refers to
* the number of transfers completed on the Source Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK)
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
switch (chunksize)
{
default:
@ -673,21 +942,43 @@ static inline uint32_t sam_txctrla(struct sam_dmach_s *dmach,
break;
case 1: /* 4 bytes */
dmasize >>= 2;
dmasize = (dmasize + 3) >> 2;
break;
case 2: /* 8 bytes */
dmasize >>= 3;
dmasize = (dmasize + 7) >> 3;
break;
case 3: /* 16 bytes */
dmasize >>= 4;
dmasize = (dmasize + 15) >> 4;
break;
}
DEBUGASSERT(dmasize <= DMAC_CH_CTRLA_BTSIZE_MAX);
return dmasize;
}
/****************************************************************************
* Name: sam_txctrla
*
* Description:
* 'OR' in the variable CTRLA bits
*
****************************************************************************/
static inline uint32_t sam_txctrla(struct sam_dmach_s *dmach,
uint32_t dmasize, uint32_t ctrla)
{
uint32_t ntransfers;
/* Set the buffer transfer size field. This is the number of transfers to
* be performed, that is, the number of source width transfers to perform.
*/
ntransfers = sam_ntxtransfers(dmach, dmasize);
DEBUGASSERT(ntransfers <= DMAC_CH_CTRLA_BTSIZE_MAX);
return (ctrla & ~DMAC_CH_CTRLA_BTSIZE_MASK) |
(dmasize << DMAC_CH_CTRLA_BTSIZE_SHIFT);
(ntransfers << DMAC_CH_CTRLA_BTSIZE_SHIFT);
}
/****************************************************************************
@ -744,6 +1035,96 @@ static inline uint32_t sam_rxctrlabits(struct sam_dmach_s *dmach)
return regval;
}
/****************************************************************************
* Name: sam_maxrxtransfer
*
* Description:
* Maximum number of bytes that can be sent in on transfer
*
****************************************************************************/
static size_t sam_maxrxtransfer(struct sam_dmach_s *dmach)
{
unsigned int chunksize;
size_t maxtransfer;
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size). BTSIZE is "the number of transfers to be performed, that
* is, for writes it refers to the number of source width transfers
* to perform when DMAC is flow controller. For Reads, BTSIZE refers to
* the number of transfers completed on the Source Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
switch (chunksize)
{
default:
case 0: /* 1 byte */
maxtransfer = DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 1: /* 4 bytes */
maxtransfer = 4 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 2: /* 8 bytes */
maxtransfer = 8 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 3: /* 16 bytes */
maxtransfer = 16 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
}
return maxtransfer;
}
/****************************************************************************
* Name: sam_nrxtransfers
*
* Description:
* Number of RX transfers via DMA
*
****************************************************************************/
static uint32_t sam_nrxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
{
unsigned int chunksize;
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size). BTSIZE is "the number of transfers to be performed, that
* is, for writes it refers to the number of source width transfers
* to perform when DMAC is flow controller. For Reads, BTSIZE refers to
* the number of transfers completed on the Source Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
switch (chunksize)
{
default:
case 0: /* 1 byte */
break;
case 1: /* 4 bytes */
dmasize = (dmasize + 3) >> 2;
break;
case 2: /* 8 bytes */
dmasize = (dmasize + 7) >> 3;
break;
case 3: /* 16 bytes */
dmasize = (dmasize + 15) >> 4;
break;
}
return dmasize;
}
/****************************************************************************
* Name: sam_rxctrla
*
@ -755,40 +1136,17 @@ static inline uint32_t sam_rxctrlabits(struct sam_dmach_s *dmach)
static inline uint32_t sam_rxctrla(struct sam_dmach_s *dmach,
uint32_t dmasize, uint32_t ctrla)
{
unsigned int chunksize;
uint32_t ntransfers;
/* Set the buffer transfer size field. This is the number of transfers to
* be performed, that is, the number of source width transfers to perform.
*/
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size)
*/
ntransfers = sam_nrxtransfers(dmach, dmasize);
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
switch (chunksize)
{
default:
case 0: /* 1 byte */
break;
case 1: /* 4 bytes */
dmasize >>= 2;
break;
case 2: /* 8 bytes */
dmasize >>= 3;
break;
case 3: /* 16 bytes */
dmasize >>= 4;
break;
}
DEBUGASSERT(dmasize <= DMAC_CH_CTRLA_BTSIZE_MAX);
DEBUGASSERT(ntransfers <= DMAC_CH_CTRLA_BTSIZE_MAX);
return (ctrla & ~DMAC_CH_CTRLA_BTSIZE_MASK) |
(dmasize << DMAC_CH_CTRLA_BTSIZE_SHIFT);
(ntransfers << DMAC_CH_CTRLA_BTSIZE_SHIFT);
}
/****************************************************************************
@ -1166,6 +1524,7 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
*/
dmach->cfg = sam_txcfg(dmach);
return OK;
}
@ -1692,9 +2051,11 @@ void sam_dmafree(DMA_HANDLE handle)
*
****************************************************************************/
int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
size_t nbytes)
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@ -1702,18 +2063,24 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
/* The maximum transfer size in bytes depends upon the maximum number of
* transfers and the number of bytes per transfer.
*/
maxtransfer = sam_maxtxtransfer(dmach);
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > DMAC_CH_CTRLA_BTSIZE_MAX)
while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
ret = sam_txbuffer(dmach, paddr, maddr, DMAC_CH_CTRLA_BTSIZE_MAX);
ret = sam_txbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
nbytes -= DMAC_CH_CTRLA_BTSIZE_MAX;
nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@ -1721,12 +2088,12 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
paddr += DMAC_CH_CTRLA_BTSIZE_MAX;
paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
maddr += DMAC_CH_CTRLA_BTSIZE_MAX;
maddr += maxtransfer;
}
}
}
@ -1738,6 +2105,9 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
ret = sam_txbuffer(dmach, paddr, maddr, nbytes);
}
/* Clean caches associated with the DMA memory */
cp15_coherent_dcache(maddr, maddr + nbytes);
return ret;
}
@ -1756,6 +2126,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
size_t nbytes)
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@ -1763,18 +2134,24 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
/* The maximum transfer size in bytes depends upon the maximum number of
* transfers and the number of bytes per transfer.
*/
maxtransfer = sam_maxrxtransfer(dmach);
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > DMAC_CH_CTRLA_BTSIZE_MAX)
while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
ret = sam_rxbuffer(dmach, paddr, maddr, DMAC_CH_CTRLA_BTSIZE_MAX);
ret = sam_rxbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
nbytes -= DMAC_CH_CTRLA_BTSIZE_MAX;
nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@ -1782,12 +2159,12 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
paddr += DMAC_CH_CTRLA_BTSIZE_MAX;
paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
maddr += DMAC_CH_CTRLA_BTSIZE_MAX;
maddr += maxtransfer;
}
}
}
@ -1799,6 +2176,9 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
ret = sam_rxbuffer(dmach, paddr, maddr, nbytes);
}
/* Clean caches associated with the DMA memory */
cp15_coherent_dcache(maddr, maddr + nbytes);
return ret;
}

View File

@ -104,7 +104,7 @@
/* Memory endpoint characteristics */
#define DMACH_FLAG_MEMPID_SHIFT (17) /* Bits 17-22: Memory PID */
#define DMACH_FLAG_MEMPID_MASK (63 << DMACH_FLAG_PERIPHPID_SHIFT)
#define DMACH_FLAG_MEMPID_MASK (63 << DMACH_FLAG_MEMPID_SHIFT)
#define DMACH_FLAG_MEMH2SEL (1 << 23) /* Bits 23: HW handshaking */
#define DMACH_FLAG_MEMISPERIPH (1 << 24) /* Bits 24: 0=memory; 1=peripheral */
#define DMACH_FLAG_MEMAHB_SHIFT (25) /* Bits 25-26: Peripheral ABH layer number */

View File

@ -175,7 +175,7 @@
( HSMCI_INT_CSTOE | HSMCI_INT_RTOE | HSMCI_INT_RENDE | HSMCI_INT_RDIRE | \
HSMCI_INT_RINDE )
#define HSMCI_RESPONSE_TIMEOUT_ERRORS \
( HSMCI_INT_CSTOE | HSMCI_INT_RTOE )
( HSMCI_INT_CSTOE | HSMCI_INT_RTOE )
/* Data transfer errors:
*
@ -261,7 +261,6 @@
/****************************************************************************
* Private Types
****************************************************************************/
/* Register logging support */
#if defined(CONFIG_SAMA5_HSMCI_XFRDEBUG) || defined(CONFIG_SAMA5_HSMCI_CMDDEBUG)
@ -432,7 +431,7 @@ static void sam_notransfer(struct sam_dev_s *priv);
/* Interrupt Handling *******************************************************/
static int sam_hsmci_interrupt(struct sam_dev_s *priv);
static int sam_hsmci_interrupt(struct sam_dev_s *priv);
#ifdef CONFIG_SAMA5_HSMCI0
static int sam_hsmci0_interrupt(int irq, void *context);
#endif
@ -497,7 +496,6 @@ static void sam_callback(void *arg);
/****************************************************************************
* Private Data
****************************************************************************/
/* Callbacks */
static const struct sdio_dev_s g_callbacks =
@ -2733,7 +2731,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* For DMA channel selection */
dmac = 0;
pid = DMAC0_CH_HSMCI0;
pid = SAM_PID_HSMCI0;
}
else
#endif
@ -2770,7 +2768,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* For DMA channel selection */
dmac = 1;
pid = DMAC1_CH_HSMCI1;
pid = SAM_PID_HSMCI1;
}
else
#endif
@ -2807,7 +2805,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* For DMA channel selection */
dmac = 1;
pid = DMAC1_CH_HSMCI2;
pid = SAM_PID_HSMCI2;
}
else
#endif
@ -2827,7 +2825,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* Initialize the callbacks */
memcpy(&priv->dev, &g_callbacks, sizeof(struct sdio_dev_s ));
memcpy(&priv->dev, &g_callbacks, sizeof(struct sdio_dev_s));
/* Allocate a DMA channel */