SAML21 DMA: Add logic to set up base and writeback table addresses
This commit is contained in:
parent
4d4d96cb2f
commit
758183d41d
@ -241,7 +241,7 @@ config ARCH_FAMILY_SAMD20J
|
||||
config ARCH_FAMILY_SAML21
|
||||
bool
|
||||
default n
|
||||
selest SAMDL_HAVE_DMAC
|
||||
select SAMDL_HAVE_DMAC
|
||||
|
||||
config ARCH_FAMILY_SAML21E
|
||||
bool
|
||||
@ -420,9 +420,18 @@ config SAMDL_SERCOM0_ISUSART
|
||||
endchoice
|
||||
|
||||
config SAMDL_DMAC_NDESC
|
||||
int "Number of DMA Descriptors"
|
||||
default 64
|
||||
int "Number of additional DMA Descriptors"
|
||||
default 0
|
||||
depends on SAMDL_DMAC
|
||||
---help---
|
||||
This provides the number of additional DMA descriptors that can be
|
||||
use to support multi-linked DMA transfers. A minimum of 16
|
||||
descriptors will always be allocated (16 for the base descriptor which
|
||||
overlap the writeback descriptors). If this value is set to zero,
|
||||
then only single block DMA transfers can be supported.
|
||||
|
||||
Each additional DMA descriptor will require 16-bytes for LPRAM
|
||||
memory.
|
||||
|
||||
choice
|
||||
prompt "SERCOM1 mode"
|
||||
|
@ -174,7 +174,7 @@
|
||||
# define DMAC_QOSCTRL_DQOS_MEDIUM (2 << DMAC_QOSCTRL_DQOS_SHIFT) /* Sensitive latency */
|
||||
# define DMAC_QOSCTRL_DQOS_HIGH (3 << DMAC_QOSCTRL_DQOS_SHIFT) /* Critical latency */
|
||||
|
||||
/* Common bit defintions for: Software Trigger Control Register, Interrupt Status Register,
|
||||
/* Common bit definitions for: Software Trigger Control Register, Interrupt Status Register,
|
||||
* Busy Channels Register, and Pending Channels Register
|
||||
*/
|
||||
|
||||
|
@ -77,7 +77,7 @@
|
||||
/* Number of DMA descriptors in LPRAM */
|
||||
|
||||
#ifndef CONFIG_SAMDL_DMAC_NDESC
|
||||
# define CONFIG_SAMDL_DMAC_NDESC 64
|
||||
# define CONFIG_SAMDL_DMAC_NDESC 0
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
@ -93,8 +93,9 @@ struct sam_dmach_s
|
||||
uint32_t dc_flags; /* DMA channel flags */
|
||||
dma_callback_t dc_callback; /* Callback invoked when the DMA completes */
|
||||
void *dc_arg; /* Argument passed to callback function */
|
||||
struct dma_desc_s *llhead; /* DMA link list head */
|
||||
struct dma_desc_s *lltail; /* DMA link list head */
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
struct dma_desc_s *dc_tail; /* DMA link list tail */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -103,13 +104,15 @@ struct sam_dmach_s
|
||||
|
||||
static void sam_takechsem(void);
|
||||
static inline void sam_givechsem(void);
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
static void sam_takedsem(void);
|
||||
static inline void sam_givedsem(void);
|
||||
#endif
|
||||
static void sam_dmaterminate(struct sam_dmach_s *dmach, int result);
|
||||
static int sam_dmainterrupt(int irq, void *context);
|
||||
static struct dma_desc_s *
|
||||
sam_allocdesc(struct sam_dmach_s *dmach,
|
||||
struct dma_desc_s *prev, uint16_t btctrl, uint16_t btcnt,
|
||||
static struct dma_desc_s *sam_alloc_desc(struct sam_dmach_s *dmach);
|
||||
static struct dma_desc_s *sam_append_desc(struct sam_dmach_s *dmach,
|
||||
uint16_t btctrl, uint16_t btcnt,
|
||||
uint32_t srcaddr,uint32_t dstaddr);
|
||||
static void sam_freelinklist(struct sam_dmach_s *dmach);
|
||||
static size_t sam_maxtransfer(struct sam_dmach_s *dmach);
|
||||
@ -127,16 +130,34 @@ static int sam_multiple(struct sam_dmach_s *dmach);
|
||||
/* These semaphores protect the DMA channel and descriptor tables */
|
||||
|
||||
static sem_t g_chsem;
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
static sem_t g_dsem;
|
||||
#endif
|
||||
|
||||
/* This array describes the state of each DMA channel */
|
||||
|
||||
static struct sam_dmach_s g_dmach[SAMDL_NDMACHAN];
|
||||
|
||||
/* DMA descriptors positioned in LPRAM */
|
||||
/* DMA descriptor tables positioned in LPRAM */
|
||||
|
||||
static struct dma_desc_s g_base_desc[SAMDL_NDMACHAN]
|
||||
__attribute__ ((section(".lpram"),aligned(16)));
|
||||
|
||||
#if 0
|
||||
static struct dma_desc_s g_writeback_desc[SAMDL_NDMACHAN]
|
||||
__attribute__ ((section(".lpram"),aligned(16)));
|
||||
#else
|
||||
# define g_writeback_desc g_base_desc
|
||||
#endif
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
/* Additional DMA descriptors for multi-block transfers. Also positioned
|
||||
* in LPRAM.
|
||||
*/
|
||||
|
||||
static struct dma_desc_s g_dma_desc[CONFIG_SAMDL_DMAC_NDESC]
|
||||
__attribute__ ((section(".lpram"),aligned(16)));
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -177,6 +198,7 @@ static inline void sam_givechsem(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
static void sam_takedsem(void)
|
||||
{
|
||||
/* Take the semaphore (perhaps waiting) */
|
||||
@ -195,6 +217,7 @@ static inline void sam_givedsem(void)
|
||||
{
|
||||
(void)sem_post(&g_dsem);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_dmaterminate
|
||||
@ -312,10 +335,12 @@ static size_t sam_addrincr(struct sam_dmach_s *dmach)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_allocdesc
|
||||
* Name: sam_alloc_desc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and add one descriptor to the DMA channel's link list.
|
||||
* Allocate one DMA descriptor. If the base DMA descriptor list entry is
|
||||
* unused, then that value structure will be returned. Otherwise, this
|
||||
* function will search for a free descriptor in the g_desc[] list.
|
||||
*
|
||||
* NOTE: link list entries are freed by the DMA interrupt handler. However,
|
||||
* since the setting/clearing of the 'in use' indication is atomic, no
|
||||
@ -325,78 +350,46 @@ static size_t sam_addrincr(struct sam_dmach_s *dmach)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static struct dma_desc_s *
|
||||
sam_allocdesc(struct sam_dmach_s *dmach, struct dma_desc_s *prev,
|
||||
uint16_t btctrl, uint16_t btcnt, uint32_t srcaddr,
|
||||
uint32_t dstaddr)
|
||||
static struct dma_desc_s *sam_alloc_desc(struct sam_dmach_s *dmach)
|
||||
{
|
||||
struct dma_desc_s *desc = NULL;
|
||||
struct dma_desc_s *desc;
|
||||
int i;
|
||||
|
||||
/* Sanity check -- src == 0 is the indication that the link is unused.
|
||||
* Obviously setting it to zero would break that usage.
|
||||
*/
|
||||
/* First check if the base descriptor for the DMA channel is available */
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
if (src != 0)
|
||||
#endif
|
||||
desc = &g_base_desc[dmach->dc_chan];
|
||||
if (desc->srcaddr == 0)
|
||||
{
|
||||
/* Table a descriptor table semaphore count. When we get one, then there
|
||||
* is at least one free descriptor in the table and it is ours.
|
||||
/* Yes, return a pointer to the base descriptor */
|
||||
|
||||
desc->srcaddr = (uint32_t)-1; /* Any non-zero value */
|
||||
return desc;
|
||||
}
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
else
|
||||
{
|
||||
/* Wait if no descriptor is available. When we get a semaphore count,
|
||||
* then there will be at least one free descriptor in the table and
|
||||
* it is ours.
|
||||
*/
|
||||
|
||||
sam_takedsem();
|
||||
|
||||
/* Examine each link list entry to find an available one -- i.e., one
|
||||
* with src == 0. That src field is set to zero by the DMA transfer
|
||||
* complete interrupt handler. The following should be safe because
|
||||
* that is an atomic operation.
|
||||
* with srcaddr == 0. That srcaddr field is set to zero by the DMA
|
||||
* transfer complete interrupt handler. The following should be safe
|
||||
* because that is an atomic operation.
|
||||
*/
|
||||
|
||||
sam_takechsem();
|
||||
for (i = 0; i < CONFIG_SAMDL_DMAC_NDESC; i++)
|
||||
{
|
||||
if (g_dma_desc[i].srcaddr == 0)
|
||||
desc = &g_dma_desc[i];
|
||||
if (desc->srcaddr == 0)
|
||||
{
|
||||
/* We have it. Initialize the new link list entry */
|
||||
/* We have it */
|
||||
|
||||
desc = &g_dma_desc[i];
|
||||
desc->btctrl = btctrl; /* Block Transfer Control Register */
|
||||
desc->btcnt = btcnt; /* Block Transfer Count Register */
|
||||
desc->srcaddr = srcaddr; /* Block Transfer Source Address Register */
|
||||
desc->dstaddr = dstaddr; /* Block Transfer Destination Address Register */
|
||||
desc->descaddr = 0; /* Next Address Descriptor Register */
|
||||
|
||||
/* And then hook it at the tail of the link list */
|
||||
|
||||
if (!prev)
|
||||
{
|
||||
/* There is no previous link. This is the new head of
|
||||
* the list
|
||||
*/
|
||||
|
||||
DEBUGASSERT(dmach->llhead == NULL && dmach->lltail == NULL);
|
||||
dmach->llhead = desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGASSERT(dmach->llhead != NULL && dmach->lltail == prev);
|
||||
|
||||
/* When the second link is added to the list, that is the
|
||||
* cue that we are going to do the link list transfer.
|
||||
*/
|
||||
#warning Missing logic
|
||||
|
||||
/* Link the previous tail to the new tail */
|
||||
|
||||
prev->descaddr = (uint32_t)desc;
|
||||
}
|
||||
|
||||
/* In any event, this is the new tail of the list. */
|
||||
#warning Missing logic
|
||||
|
||||
dmach->lltail = desc;
|
||||
break;
|
||||
desc->srcaddr = (uint32_t)-1; /* Any non-zero value */
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,8 +397,72 @@ sam_allocdesc(struct sam_dmach_s *dmach, struct dma_desc_s *prev,
|
||||
* search loop should always be successful.
|
||||
*/
|
||||
|
||||
sam_givechsem();
|
||||
DEBUGASSERT(desc != NULL);
|
||||
DEBUGPANIC();
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_append_desc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and add one descriptor to the DMA channel's link list.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static struct dma_desc_s *sam_append_desc(struct sam_dmach_s *dmach,
|
||||
uint16_t btctrl, uint16_t btcnt,
|
||||
uint32_t srcaddr, uint32_t dstaddr)
|
||||
{
|
||||
struct dma_desc_s *desc;
|
||||
|
||||
/* Sanity check -- srcaddr == 0 is the indication that the link is unused.
|
||||
* Obviously setting it to zero would break that usage.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(srcaddr != 0);
|
||||
|
||||
/* Allocate a DMA descriptor */
|
||||
|
||||
desc = sam_alloc_desc(dmach);
|
||||
if (desc == NULL)
|
||||
{
|
||||
/* We have it. Initialize the new link list entry */
|
||||
|
||||
desc->btctrl = btctrl; /* Block Transfer Control Register */
|
||||
desc->btcnt = btcnt; /* Block Transfer Count Register */
|
||||
desc->srcaddr = srcaddr; /* Block Transfer Source Address Register */
|
||||
desc->dstaddr = dstaddr; /* Block Transfer Destination Address Register */
|
||||
desc->descaddr = 0; /* Next Address Descriptor Register */
|
||||
|
||||
/* And then hook it at the tail of the link list */
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
if (dmach->dc_tail)
|
||||
{
|
||||
struct dma_desc_s *prev;
|
||||
|
||||
DEBUGASSERT(desc != g_base_desc[dmach->dc_chan]);
|
||||
|
||||
/* Link the previous tail to the new tail */
|
||||
|
||||
prev->descaddr = (uint32_t)desc;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* There is no previous link. This is the new head of the list */
|
||||
|
||||
DEBUGASSERT(desc == g_base_desc[dmach->dc_chan]);
|
||||
}
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
/* In either, this is the new tail of the list. */
|
||||
|
||||
dmach->dc_tail = desc;
|
||||
#endif
|
||||
}
|
||||
|
||||
return desc;
|
||||
@ -424,26 +481,39 @@ sam_allocdesc(struct sam_dmach_s *dmach, struct dma_desc_s *prev,
|
||||
static void sam_freelinklist(struct sam_dmach_s *dmach)
|
||||
{
|
||||
struct dma_desc_s *desc;
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
struct dma_desc_s *next;
|
||||
#endif
|
||||
|
||||
/* Get the head of the link list and detach the link list from the DMA
|
||||
* channel
|
||||
/* Get the base descriptor pointer */
|
||||
|
||||
desc = &g_base_desc[dmach->dc_chan];
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
dmach->dc_tail = NULL;
|
||||
#endif
|
||||
|
||||
/* Nullify the base descriptor */
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
next = (struct dma_desc_s *)desc->descaddr;
|
||||
#endif
|
||||
memset(desc, 0, sizeof(struct dma_desc_s));
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
/* Reset each additional descriptor in the link list (thereby freeing
|
||||
* them)
|
||||
*/
|
||||
|
||||
desc = dmach->llhead;
|
||||
dmach->llhead = NULL;
|
||||
dmach->lltail = NULL;
|
||||
|
||||
/* Reset each descriptor in the link list (thereby freeing them) */
|
||||
|
||||
while (desc != NULL)
|
||||
while (next != NULL)
|
||||
{
|
||||
desc = next;
|
||||
DEBUGASSERT(desc->srcaddr != 0);
|
||||
|
||||
next = (struct dma_desc_s *)desc->descaddr;
|
||||
DEBUGASSERT(desc->src != 0);
|
||||
memset(desc, 0, sizeof(struct dma_desc_s));
|
||||
sam_givedsem();
|
||||
desc = next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -484,7 +554,7 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
|
||||
/* Add the new link list entry */
|
||||
|
||||
if (!sam_allocdesc(dmach, dmach->lltail, btctrl, btcnt, maddr, paddr))
|
||||
if (!sam_append_desc(dmach, btctrl, btcnt, maddr, paddr))
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -516,7 +586,7 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
|
||||
/* Add the new link list entry */
|
||||
|
||||
if (!sam_allocdesc(dmach, dmach->lltail, btctrl, btcnt, paddr, maddr))
|
||||
if (!sam_append_desc(dmach, btctrl, btcnt, paddr, maddr))
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -534,7 +604,7 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
|
||||
static int sam_single(struct sam_dmach_s *dmach)
|
||||
{
|
||||
struct dma_desc_s *llhead = dmach->llhead;
|
||||
struct dma_desc_s *head = &g_base_desc[dmach->dc_chan];
|
||||
|
||||
/* Clear any pending interrupts from any previous DMAC transfer.
|
||||
*
|
||||
@ -545,7 +615,7 @@ static int sam_single(struct sam_dmach_s *dmach)
|
||||
|
||||
/* Set up the DMA */
|
||||
#warning Missing logic
|
||||
DEBUGASSERT(llhead != NULL && llhead->src != 0);
|
||||
DEBUGASSERT(head->srcaddr != 0);
|
||||
|
||||
/* Enable the channel */
|
||||
#warning Missing logic
|
||||
@ -564,9 +634,10 @@ static int sam_single(struct sam_dmach_s *dmach)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
static int sam_multiple(struct sam_dmach_s *dmach)
|
||||
{
|
||||
struct dma_desc_s *llhead = dmach->llhead;
|
||||
struct dma_desc_s *head = &g_base_desc[dmach->dc_chan];
|
||||
|
||||
/* Clear any pending interrupts from any previous DMAC transfer.
|
||||
*
|
||||
@ -577,8 +648,7 @@ static int sam_multiple(struct sam_dmach_s *dmach)
|
||||
|
||||
/* Set up the initial DMA */
|
||||
#warning Missing logic
|
||||
DEBUGASSERT(llhead != NULL && llhead->src != 0);
|
||||
|
||||
DEBUGASSERT(head->srcaddr != 0);
|
||||
|
||||
/* Enable the channel */
|
||||
#warning Missing logic
|
||||
@ -588,6 +658,7 @@ static int sam_multiple(struct sam_dmach_s *dmach)
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@ -612,7 +683,9 @@ void weak_function up_dmainitialize(void)
|
||||
/* Initialize global semaphores */
|
||||
|
||||
sem_init(&g_chsem, 0, 1);
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
sem_init(&g_dsem, 0, CONFIG_SAMDL_DMAC_NDESC);
|
||||
#endif
|
||||
|
||||
/* Initialized the DMA channel table */
|
||||
|
||||
@ -621,26 +694,41 @@ void weak_function up_dmainitialize(void)
|
||||
g_dmach[i].dc_chan = i;
|
||||
}
|
||||
|
||||
/* Clear descriptors (this will not be done automatically because they are
|
||||
* not in .bss).
|
||||
*/
|
||||
|
||||
memset(g_base_desc, 0, sizeof(struct dma_desc_s)*SAMDL_NDMACHAN);
|
||||
memset(g_writeback_desc, 0, sizeof(struct dma_desc_s)*SAMDL_NDMACHAN);
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
memset(g_dma_desc, 0, sizeof(struct dma_desc_s)*CONFIG_SAMDL_DMAC_NDESC);
|
||||
#endif
|
||||
|
||||
/* Enable peripheral clock */
|
||||
|
||||
sam_dmac_enableperiph();
|
||||
|
||||
/* Disable all DMA interrupts */
|
||||
#warning Missing logic
|
||||
/* Disable and reset the DMAC */
|
||||
|
||||
/* Disable all DMA channels */
|
||||
#warning Missing logic
|
||||
putreg16(0, SAM_DMAC_CTRL);
|
||||
putreg16(DMAC_CTRL_SWRST, SAM_DMAC_CTRL);
|
||||
|
||||
/* Attach DMA interrupt vector */
|
||||
|
||||
(void)irq_attach(SAM_IRQ_DMAC, sam_dmainterrupt);
|
||||
|
||||
/* Enable the DMA controller */
|
||||
|
||||
putreg16(DMAC_CTRL_DMAENABLE, SAM_DMAC_CTRL);
|
||||
|
||||
/* Set the LPRAM DMA descriptor table addresses */
|
||||
|
||||
putreg32((uint32_t)g_base_desc, SAM_DMAC_BASEADDR);
|
||||
putreg32((uint32_t)g_writeback_desc, SAM_DMAC_WRBADDR);
|
||||
|
||||
/* Enable the IRQ at the NVIC (still disabled at the DMA controller) */
|
||||
|
||||
up_enable_irq(SAM_IRQ_DMAC);
|
||||
|
||||
/* Enable the DMA controller */
|
||||
#warning Missing logic
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -665,6 +753,7 @@ void weak_function up_dmainitialize(void)
|
||||
DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
{
|
||||
struct sam_dmach_s *dmach;
|
||||
irqstate_t flags;
|
||||
unsigned int chndx;
|
||||
|
||||
/* Search for an available DMA channel */
|
||||
@ -680,19 +769,20 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
dmach = candidate;
|
||||
dmach->dc_inuse = true;
|
||||
|
||||
/* Clear any pending interrupts.
|
||||
*
|
||||
* REVISIT: If DMAC interrupts are disabled at the NVIC, then
|
||||
* reading the EBCISR register could cause a loss of interrupts!
|
||||
*/
|
||||
#warning Missing logic
|
||||
|
||||
/* Disable the channel */
|
||||
#warning Missing logic
|
||||
|
||||
/* Set the DMA channel flags */
|
||||
|
||||
dmach->dc_flags = chflags;
|
||||
|
||||
/* Disable the DMA channel */
|
||||
|
||||
flags = irqsave();
|
||||
putreg8(chndx, SAM_DMAC_CHID);
|
||||
putreg8(0, SAM_DMAC_CHCTRLA);
|
||||
|
||||
/* Reset the channel */
|
||||
|
||||
putreg8(DMAC_CHCTRLA_SWRST, SAM_DMAC_CHCTRLA);
|
||||
irqrestore(flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -779,7 +869,9 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
|
||||
dmach, (int)paddr, (int)maddr, (int)nbytes);
|
||||
DEBUGASSERT(dmach);
|
||||
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
dmavdbg("dc_tail: %p\n", dmach->dc_tail);
|
||||
#endif
|
||||
|
||||
/* The maximum transfer size in bytes depends upon the maximum number of
|
||||
* transfers and the number of bytes per transfer.
|
||||
@ -849,7 +941,9 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
|
||||
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
|
||||
dmach, (int)paddr, (int)maddr, (int)nbytes);
|
||||
DEBUGASSERT(dmach);
|
||||
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
dmavdbg("dc_tail: %p\n", dmach->dc_tail);
|
||||
#endif
|
||||
|
||||
/* The maximum transfer size in bytes depends upon the maximum number of
|
||||
* transfers and the number of bytes per transfer.
|
||||
@ -909,25 +1003,28 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
|
||||
int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
{
|
||||
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
|
||||
struct dma_desc_s *head;
|
||||
int ret = -EINVAL;
|
||||
|
||||
dmavdbg("dmach: %p callback: %p arg: %p\n", dmach, callback, arg);
|
||||
DEBUGASSERT(dmach != NULL);
|
||||
DEBUGASSERT(dmach != NULL && dmach->dc_chan < SAMDL_NDMACHAN);
|
||||
head = &g_base_desc[dmach->dc_chan];
|
||||
|
||||
/* Verify that the DMA has been setup (i.e., at least one entry in the
|
||||
* link list).
|
||||
* link list, the base entry).
|
||||
*/
|
||||
|
||||
if (dmach->llhead)
|
||||
if (head->srcaddr != 0)
|
||||
{
|
||||
/* Save the callback info. This will be invoked when the DMA completes */
|
||||
|
||||
dmach->dc_callback = callback;
|
||||
dmach->dc_arg = arg;
|
||||
|
||||
#if CONFIG_SAMDL_DMAC_NDESC > 0
|
||||
/* Is this a single block transfer? Or a multiple block transfer? */
|
||||
|
||||
if (dmach->llhead == dmach->lltail)
|
||||
if (head == dmach->dc_tail)
|
||||
{
|
||||
ret = sam_single(dmach);
|
||||
}
|
||||
@ -935,6 +1032,9 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
{
|
||||
ret = sam_multiple(dmach);
|
||||
}
|
||||
#else
|
||||
ret = sam_single(dmach);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user