mirror of
https://github.com/apache/nuttx.git
synced 2026-06-07 01:05:54 +08:00
Check return from nxsem_wait_uninterruptible()
This commit is for all DMA drivers under arch/.
This commit is contained in:
@@ -125,7 +125,8 @@ static struct dma_channel_s g_dmach[EFM32_DMA_NCHANNELS];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFM32_DMA_ALTDSEC
|
||||
static struct dma_descriptor_s g_descriptors[DESC_TABLE_SIZE + EFM32_DMA_NCHANNELS]
|
||||
static struct dma_descriptor_s
|
||||
g_descriptors[DESC_TABLE_SIZE + EFM32_DMA_NCHANNELS]
|
||||
__attribute__((aligned(DESC_TABLE_ALIGN)));
|
||||
#else
|
||||
static struct dma_descriptor_s g_descriptors[EFM32_DMA_NCHANNELS]
|
||||
@@ -148,15 +149,18 @@ static struct dma_descriptor_s g_descriptors[EFM32_DMA_NCHANNELS]
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void efm32_set_chctrl(struct dma_channel_s *dmach, dma_config_t config)
|
||||
static void efm32_set_chctrl(struct dma_channel_s *dmach,
|
||||
dma_config_t config)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
uint32_t decoded;
|
||||
uint32_t regval;
|
||||
|
||||
decoded = (uint32_t)(config & EFM32_DMA_SIGSEL_MASK) >> EFM32_DMA_SIGSEL_SHIFT;
|
||||
decoded = (uint32_t)(config & EFM32_DMA_SIGSEL_MASK) >>
|
||||
EFM32_DMA_SIGSEL_SHIFT;
|
||||
regval = (decoded << _DMA_CH_CTRL_SIGSEL_SHIFT);
|
||||
decoded = (uint32_t)(config & EFM32_DMA_SOURCSEL_MASK) >> EFM32_DMA_SOURCSEL_SHIFT;
|
||||
decoded = (uint32_t)(config & EFM32_DMA_SOURCSEL_MASK) >>
|
||||
EFM32_DMA_SOURCSEL_SHIFT;
|
||||
regval |= (decoded << _DMA_CH_CTRL_SOURCESEL_SHIFT);
|
||||
|
||||
regaddr = EFM32_DMA_CHn_CTRL(dmach->chan);
|
||||
@@ -337,6 +341,7 @@ DMA_HANDLE efm32_dmachannel(void)
|
||||
struct dma_channel_s *dmach;
|
||||
unsigned int chndx;
|
||||
uint32_t bit;
|
||||
int ret;
|
||||
|
||||
/* Take a count from the channel counting semaphore. We may block
|
||||
* if there are no free channels. When we get the count, then we can
|
||||
@@ -344,11 +349,20 @@ DMA_HANDLE efm32_dmachannel(void)
|
||||
* reserved for us.
|
||||
*/
|
||||
|
||||
nxsem_wait_uninterruptible(&g_dmac.chansem);
|
||||
ret = nxsem_wait_uninterruptible(&g_dmac.chansem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get exclusive access to the DMA channel list */
|
||||
|
||||
nxsem_wait_uninterruptible(&g_dmac.exclsem);
|
||||
ret = nxsem_wait_uninterruptible(&g_dmac.exclsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxsem_post(&g_dmac.chansem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Search for an available DMA channel */
|
||||
|
||||
@@ -387,7 +401,7 @@ DMA_HANDLE efm32_dmachannel(void)
|
||||
* Name: efm32_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* in a call to efm32_dmachannel, then this function will re-assign the
|
||||
* DMA channel to that thread and wake it up. NOTE: The 'handle' used
|
||||
* in this argument must NEVER be used again until efm32_dmachannel() is
|
||||
@@ -413,8 +427,8 @@ void efm32_dmafree(DMA_HANDLE handle)
|
||||
|
||||
putreg32(1 << dmach->chan, EFM32_DMA_CHENC);
|
||||
|
||||
/* Mark the channel no longer in use. Clearing the in-use flag is an atomic
|
||||
* operation and so should be safe.
|
||||
/* Mark the channel no longer in use. Clearing the in-use flag is an
|
||||
* atomic operation and so should be safe.
|
||||
*/
|
||||
|
||||
dmach->inuse = false;
|
||||
@@ -459,8 +473,8 @@ void efm32_rxdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
|
||||
shift = efm32_align_shift(config);
|
||||
mask = ALIGN_MASK(shift);
|
||||
|
||||
/* Make sure that the number of bytes we are asked to transfer is a multiple
|
||||
* of the transfer size.
|
||||
/* Make sure that the number of bytes we are asked to transfer is a
|
||||
* multiple of the transfer size.
|
||||
*/
|
||||
|
||||
xfersize = (1 << shift);
|
||||
@@ -556,8 +570,8 @@ void efm32_txdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
|
||||
shift = efm32_align_shift(config);
|
||||
mask = ALIGN_MASK(shift);
|
||||
|
||||
/* Make sure that the number of bytes we are asked to transfer is a multiple
|
||||
* of the transfer size.
|
||||
/* Make sure that the number of bytes we are asked to transfer is a
|
||||
* multiple of the transfer size.
|
||||
*/
|
||||
|
||||
xfersize = (1 << shift);
|
||||
@@ -651,8 +665,8 @@ void efm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
bit = 1 << dmach->chan;
|
||||
if ((dmach->config & EFM32_DMA_SINGLE_MASK) == EFM32_DMA_BUFFER_FULL)
|
||||
{
|
||||
/* Disable the single requests for the channel (i.e. do not react to data
|
||||
* available, wait for buffer full)
|
||||
/* Disable the single requests for the channel (i.e. do not react to
|
||||
* data available, wait for buffer full)
|
||||
*/
|
||||
|
||||
putreg32(bit, EFM32_DMA_CHUSEBURSTS);
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Portions of the eDMA logic derive from NXP sample code which has a compatible
|
||||
* BSD 3-clause license:
|
||||
* Portions of the eDMA logic derive from NXP sample code which has a
|
||||
* compatible BSD 3-clause license:
|
||||
*
|
||||
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2017 NXP
|
||||
@@ -126,8 +126,8 @@ struct imxrt_dmach_s
|
||||
|
||||
#if CONFIG_IMXRT_EDMA_NTCD > 0
|
||||
/* That TCD list is linked through the DLAST SGA field. The first transfer
|
||||
* to be performed is at the head of the list. Subsequent TCDs are added at
|
||||
* the tail of the list.
|
||||
* to be performed is at the head of the list. Subsequent TCDs are added
|
||||
* at the tail of the list.
|
||||
*/
|
||||
|
||||
struct imxrt_edmatcd_s *head; /* First TCD in the list */
|
||||
@@ -183,9 +183,9 @@ static struct imxrt_edmatcd_s g_tcd_pool[CONFIG_IMXRT_EDMA_NTCD]
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void imxrt_takechsem(void)
|
||||
static int imxrt_takechsem(void)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&g_edma.chsem);
|
||||
return nxsem_wait_uninterruptible(&g_edma.chsem);
|
||||
}
|
||||
|
||||
static inline void imxrt_givechsem(void)
|
||||
@@ -302,13 +302,14 @@ static inline void imxrt_tcd_initialize(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: imxrt_tcd_chanlink
|
||||
*
|
||||
* Description:
|
||||
* This function configures either a minor link or a major link. The minor link
|
||||
* means the channel link is triggered every time CITER decreases by 1. The major
|
||||
* link means that the channel link is triggered when the CITER is exhausted.
|
||||
* This function configures either a minor link or a major link. The minor
|
||||
* link means the channel link is triggered every time CITER decreases by 1
|
||||
* The major link means that the channel link is triggered when the CITER
|
||||
* is exhausted.
|
||||
*
|
||||
* NOTE: Users should ensure that DONE flag is cleared before calling this
|
||||
* interface, or the configuration is invalid.
|
||||
@@ -321,10 +322,11 @@ static inline void imxrt_tcd_initialize(void)
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_IMXRT_EDMA_ELINK
|
||||
static inline void imxrt_tcd_chanlink(uint8_t flags, struct imxrt_dmach_s *linkch,
|
||||
static inline void imxrt_tcd_chanlink(uint8_t flags,
|
||||
struct imxrt_dmach_s *linkch,
|
||||
struct imxrt_edmatcd_s *tcd)
|
||||
{
|
||||
uint16_t regval16;
|
||||
@@ -392,7 +394,7 @@ static inline void imxrt_tcd_chanlink(uint8_t flags, struct imxrt_dmach_s *linkc
|
||||
****************************************************************************/
|
||||
|
||||
static inline void imxrt_tcd_configure(struct imxrt_edmatcd_s *tcd,
|
||||
const struct imxrt_edma_xfrconfig_s *config)
|
||||
const struct imxrt_edma_xfrconfig_s *config)
|
||||
{
|
||||
tcd->saddr = config->saddr;
|
||||
tcd->soff = config->soff;
|
||||
@@ -858,7 +860,8 @@ void weak_function up_dma_initialize(void)
|
||||
*
|
||||
* Input Parameters:
|
||||
* dmamux - DMAMUX configuration see DMAMUX channel configuration register
|
||||
* bit-field definitions in hardware/imxrt_dmamux.h. Settings include:
|
||||
* bit-field definitions in hardware/imxrt_dmamux.h.
|
||||
* Settings include:
|
||||
*
|
||||
* DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required)
|
||||
* DMAMUX_CHCFG_AON DMA Channel Always Enable (optional)
|
||||
@@ -886,11 +889,17 @@ DMACH_HANDLE imxrt_dmach_alloc(uint32_t dmamux, uint8_t dchpri)
|
||||
{
|
||||
struct imxrt_dmach_s *dmach;
|
||||
unsigned int chndx;
|
||||
int ret;
|
||||
|
||||
/* Search for an available DMA channel */
|
||||
|
||||
dmach = NULL;
|
||||
imxrt_takechsem();
|
||||
ret = imxrt_takechsem();
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chndx = 0; chndx < IMXRT_EDMA_NCHANNELS; chndx++)
|
||||
{
|
||||
struct imxrt_dmach_s *candidate = &g_edma.dmach[chndx];
|
||||
@@ -958,7 +967,8 @@ void imxrt_dmach_free(DMACH_HANDLE handle)
|
||||
uint8_t regval8;
|
||||
|
||||
dmainfo("dmach: %p\n", dmach);
|
||||
DEBUGASSERT(dmach != NULL && dmach->inuse && dmach->state != IMXRT_DMA_ACTIVE);
|
||||
DEBUGASSERT(dmach != NULL && dmach->inuse &&
|
||||
dmach->state != IMXRT_DMA_ACTIVE);
|
||||
|
||||
/* Mark the channel no longer in use. Clearing the inuse flag is an atomic
|
||||
* operation and so should be safe.
|
||||
@@ -988,7 +998,8 @@ void imxrt_dmach_free(DMACH_HANDLE handle)
|
||||
* structure. For "normal" DMA, imxrt_dmach_xfrsetup is called only once.
|
||||
* Scatter/gather DMA is accomplished by calling this function repeatedly,
|
||||
* once for each transfer in the sequence. Scatter/gather DMA processing
|
||||
* is enabled automatically when the second transfer configuration is received.
|
||||
* is enabled automatically when the second transfer configuration is
|
||||
* received.
|
||||
*
|
||||
* This function may be called multiple times to handle multiple,
|
||||
* discontinuous transfers (scatter-gather)
|
||||
@@ -1020,6 +1031,7 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
|
||||
#if CONFIG_IMXRT_EDMA_NTCD > 0
|
||||
/* Scatter/gather DMA is supported */
|
||||
|
||||
/* Allocate a TCD, waiting if necessary */
|
||||
|
||||
tcd = imxrt_tcd_alloc();
|
||||
@@ -1063,6 +1075,7 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
}
|
||||
|
||||
/* Chain from previous descriptor in the list. */
|
||||
|
||||
/* Enable scatter/gather feature in the previous TCD. */
|
||||
|
||||
prev = dmach->tail;
|
||||
@@ -1120,8 +1133,8 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
|
||||
/* Configure channel TCD registers to the values specified in config. */
|
||||
|
||||
imxrt_tcd_configure((struct imxrt_edmatcd_s *)IMXRT_EDMA_TCD_BASE(dmach->chan),
|
||||
config);
|
||||
imxrt_tcd_configure((struct imxrt_edmatcd_s *)
|
||||
IMXRT_EDMA_TCD_BASE(dmach->chan), config);
|
||||
|
||||
/* Enable the DONE interrupt when the major iteration count completes. */
|
||||
|
||||
@@ -1162,38 +1175,41 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE *handle,
|
||||
return OK;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: imxrt_dmach_start
|
||||
*
|
||||
* Description:
|
||||
* Start the DMA transfer. This function should be called after the final call
|
||||
* to imxrt_dmach_xfrsetup() in order to avoid race conditions.
|
||||
* Start the DMA transfer. This function should be called after the final
|
||||
* call to imxrt_dmach_xfrsetup() in order to avoid race conditions.
|
||||
*
|
||||
* At the conclusion of each major DMA loop, a callback to the user-provided
|
||||
* function is made: |For "normal" DMAs, this will correspond to the DMA DONE
|
||||
* interrupt; for scatter gather DMAs, multiple interrupts will be generated
|
||||
* with the final being the DONE interrupt.
|
||||
* At the conclusion of each major DMA loop a callback to the user-provided
|
||||
* function is made: |For "normal" DMAs, this will correspond to the DMA
|
||||
* DONE interrupt; for scatter gather DMAs, multiple interrupts will be
|
||||
* generated with the final being the DONE interrupt.
|
||||
*
|
||||
* 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 result of the DMA.
|
||||
* 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
|
||||
* result of the DMA.
|
||||
*
|
||||
* NOTE: On Rx DMAs (peripheral-to-memory or memory-to-memory), it is necessary
|
||||
* to invalidate the destination memory. That is not done automatically by the
|
||||
* DMA module. Invalidation of the destination memory regions is the
|
||||
* responsibility of the caller.
|
||||
* NOTE: On Rx DMAs (peripheral-to-memory or memory-to-memory), it is
|
||||
* necessary to invalidate the destination memory. That is not done
|
||||
* automatically by the DMA module. Invalidation of the destination memory
|
||||
* regions is the responsibility of the caller.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - DMA channel handle created by imxrt_dmach_alloc()
|
||||
* callback - The callback to be invoked when the DMA is completes or is aborted.
|
||||
* callback - The callback to be invoked when the DMA is completes or is
|
||||
* aborted.
|
||||
* arg - An argument that accompanies the callback
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, void *arg)
|
||||
int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback,
|
||||
void *arg)
|
||||
{
|
||||
struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle;
|
||||
irqstate_t flags;
|
||||
@@ -1212,8 +1228,8 @@ int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, void *arg)
|
||||
dmach->state = IMXRT_DMA_ACTIVE;
|
||||
|
||||
#if CONFIG_IMXRT_EDMA_NTCD > 0
|
||||
/* Although it is not recommended, it might be possible to call this function multiple times
|
||||
* while adding TCDs on the fly.
|
||||
/* Although it is not recommended, it might be possible to call this
|
||||
* function multiple times while adding TCDs on the fly.
|
||||
*/
|
||||
|
||||
if (dmach->state != IMXRT_DMA_ACTIVE)
|
||||
@@ -1234,13 +1250,13 @@ int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, void *arg)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: imxrt_dmach_stop
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After imxrt_dmach_stop() is called, the DMA channel is reset,
|
||||
* all TCDs are freed, and imxrt_dmarx/txsetup() must be called before
|
||||
* imxrt_dmach_start() can be called again
|
||||
* Cancel the DMA. After imxrt_dmach_stop() is called, the DMA channel is
|
||||
* reset, all TCDs are freed, and imxrt_dmarx/txsetup() must be called
|
||||
* before imxrt_dmach_start() can be called again
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - DMA channel handle created by imxrt_dmach_alloc()
|
||||
@@ -1248,7 +1264,7 @@ int imxrt_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, void *arg)
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
void imxrt_dmach_stop(DMACH_HANDLE handle)
|
||||
{
|
||||
@@ -1286,7 +1302,7 @@ void imxrt_dmach_stop(DMACH_HANDLE handle)
|
||||
* initial value of NBYTES (for example copied before enabling the channel)
|
||||
* is needed. The formula to calculate it is shown below:
|
||||
*
|
||||
* RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured)
|
||||
* RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured)
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - DMA channel handle created by imxrt_dmach_alloc()
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure represents the state of one DMA channel */
|
||||
|
||||
struct lpc17_40_dmach_s
|
||||
@@ -97,6 +98,7 @@ struct lpc17_40_gpdma_s
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* The state of the LPC17 DMA block */
|
||||
|
||||
static struct lpc17_40_gpdma_s g_gpdma;
|
||||
@@ -150,8 +152,8 @@ static void lpc17_40_dmainprogress(struct lpc17_40_dmach_s *dmach)
|
||||
* Description:
|
||||
* A DMA has completed. Decrement the g_dma_inprogress counter.
|
||||
*
|
||||
* This function is called only from lpc17_40_dmastop which, in turn, will be
|
||||
* called either by the user directly, by the user indirectly via
|
||||
* This function is called only from lpc17_40_dmastop which, in turn, will
|
||||
* be called either by the user directly, by the user indirectly via
|
||||
* lpc17_40_dmafree(), or from gpdma_interrupt when the transfer completes.
|
||||
*
|
||||
* NOTE: In the first two cases, we must be able to handle the case where
|
||||
@@ -272,8 +274,8 @@ static int gpdma_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
* Name: up_dma_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the GPDMA subsystem. Called from up_initialize() early in the
|
||||
* boot-up sequence. Prototyped in up_internal.h.
|
||||
* Initialize the GPDMA subsystem. Called from up_initialize() early in
|
||||
* the boot-up sequence. Prototyped in up_internal.h.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
@@ -390,10 +392,15 @@ DMA_HANDLE lpc17_40_dmachannel(void)
|
||||
{
|
||||
struct lpc17_40_dmach_s *dmach = NULL;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Get exclusive access to the GPDMA state structure */
|
||||
|
||||
nxsem_wait_uninterruptible(&g_gpdma.exclsem);
|
||||
ret = nxsem_wait_uninterruptible(&g_gpdma.exclsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find an available DMA channel */
|
||||
|
||||
@@ -420,8 +427,8 @@ DMA_HANDLE lpc17_40_dmachannel(void)
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel. NOTE: The 'handle' used in this argument must
|
||||
* NEVER be used again until lpc17_40_dmachannel() is called again to re-gain
|
||||
* a valid handle.
|
||||
* NEVER be used again until lpc17_40_dmachannel() is called again to
|
||||
* re-gain a valid handle.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
@@ -582,7 +589,8 @@ int lpc17_40_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
base = LPC17_40_DMACH_BASE((uint32_t)dmach->chn);
|
||||
regval = getreg32(base + LPC17_40_DMACH_CONTROL_OFFSET);
|
||||
regval &= ~DMACH_CONTROL_XFRSIZE_MASK;
|
||||
regval |= (DMACH_CONTROL_I | ((uint32_t)dmach->nxfrs << DMACH_CONTROL_XFRSIZE_SHIFT));
|
||||
regval |= (DMACH_CONTROL_I |
|
||||
((uint32_t)dmach->nxfrs << DMACH_CONTROL_XFRSIZE_SHIFT));
|
||||
putreg32(regval, base + LPC17_40_DMACH_CONTROL_OFFSET);
|
||||
|
||||
/* Enable the channel and unmask terminal count and error interrupts.
|
||||
@@ -602,8 +610,8 @@ int lpc17_40_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After lpc17_40_dmastop() is called, the DMA channel is
|
||||
* reset and lpc17_40_dmasetup() must be called before lpc17_40_dmastart() can be
|
||||
* called again
|
||||
* reset and lpc17_40_dmasetup() must be called before lpc17_40_dmastart()
|
||||
* can be called again
|
||||
*
|
||||
* This function will be called either by the user directly, by the user
|
||||
* indirectly via lpc17_40_dmafree(), or from gpdma_interrupt when the
|
||||
@@ -692,8 +700,9 @@ void lpc17_40_dmasample(DMA_HANDLE handle, struct lpc17_40_dmaregs_s *regs)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG__DEBUG_DMA_INFO
|
||||
void lpc17_40_dmadump(DMA_HANDLE handle, const struct lpc17_40_dmaregs_s *regs,
|
||||
const char *msg)
|
||||
void lpc17_40_dmadump(DMA_HANDLE handle,
|
||||
const struct lpc17_40_dmaregs_s *regs,
|
||||
const char *msg)
|
||||
{
|
||||
struct lpc17_40_dmach_s *dmach = (DMA_HANDLE)handle;
|
||||
uint32_t base;
|
||||
|
||||
@@ -272,8 +272,8 @@ static int gpdma_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
* Name: up_dma_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the GPDMA subsystem. Called from up_initialize() early in the
|
||||
* boot-up sequence. Prototyped in up_internal.h.
|
||||
* Initialize the GPDMA subsystem. Called from up_initialize() early in
|
||||
* the boot-up sequence. Prototyped in up_internal.h.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
@@ -391,10 +391,15 @@ DMA_HANDLE lpc43_dmachannel(void)
|
||||
{
|
||||
struct lpc43_dmach_s *dmach = NULL;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Get exclusive access to the GPDMA state structure */
|
||||
|
||||
nxsem_wait_uninterruptible(&g_gpdma.exclsem);
|
||||
ret = nxsem_wait_uninterruptible(&g_gpdma.exclsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find an available DMA channel */
|
||||
|
||||
@@ -584,7 +589,8 @@ int lpc43_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
base = LPC43_GPDMA_CHANNEL((uint32_t)dmach->chn);
|
||||
regval = getreg32(base + LPC43_GPDMA_CONTROL_CHOFFSET);
|
||||
regval &= ~GPDMA_CONTROL_XFRSIZE_MASK;
|
||||
regval |= (GPDMA_CONTROL_IE | ((uint32_t)dmach->nxfrs << GPDMA_CONTROL_XFRSIZE_SHIFT));
|
||||
regval |= (GPDMA_CONTROL_IE |
|
||||
((uint32_t)dmach->nxfrs << GPDMA_CONTROL_XFRSIZE_SHIFT));
|
||||
putreg32(regval, base + LPC43_GPDMA_CONTROL_CHOFFSET);
|
||||
|
||||
/* Enable the channel and unmask terminal count and error interrupts.
|
||||
@@ -694,7 +700,8 @@ void lpc43_dmasample(DMA_HANDLE handle, struct lpc43_dmaregs_s *regs)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA
|
||||
void lpc43_dmadump(DMA_HANDLE handle, const struct lpc43_dmaregs_s *regs, const char *msg)
|
||||
void lpc43_dmadump(DMA_HANDLE handle, const struct lpc43_dmaregs_s *regs,
|
||||
const char *msg)
|
||||
{
|
||||
struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle;
|
||||
uint32_t base;
|
||||
|
||||
+107
-64
@@ -273,9 +273,9 @@ static struct sam_dma_s g_dma[SAM34_NDMACHAN] =
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takechsem(void)
|
||||
static int sam_takechsem(void)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&g_chsem);
|
||||
return nxsem_wait_uninterruptible(&g_chsem);
|
||||
}
|
||||
|
||||
static inline void sam_givechsem(void)
|
||||
@@ -332,7 +332,9 @@ static unsigned int sam_fifosize(uint8_t chflags)
|
||||
|
||||
static inline uint32_t sam_fifocfg(struct sam_dma_s *dmach)
|
||||
{
|
||||
unsigned int ndx = (dmach->flags & DMACH_FLAG_FIFOCFG_MASK) >> DMACH_FLAG_FIFOCFG_SHIFT;
|
||||
unsigned int ndx;
|
||||
|
||||
ndx = (dmach->flags & DMACH_FLAG_FIFOCFG_MASK) >> DMACH_FLAG_FIFOCFG_SHIFT;
|
||||
DEBUGASSERT(ndx < 3);
|
||||
return g_fifocfg[ndx];
|
||||
}
|
||||
@@ -353,10 +355,14 @@ static inline uint32_t sam_txcfg(struct sam_dma_s *dmach)
|
||||
/* Set transfer (memory to peripheral) DMA channel configuration register */
|
||||
|
||||
regval = DMACHAN_CFG_SOD;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT) << DMACHAN_CFG_SRCPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMACHAN_CFG_SRCH2SEL : 0;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT) << DMACHAN_CFG_DSTPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMACHAN_CFG_DSTH2SEL : 0;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_MEMPID_MASK) >>
|
||||
DMACH_FLAG_MEMPID_SHIFT) << DMACHAN_CFG_SRCPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ?
|
||||
DMACHAN_CFG_SRCH2SEL : 0;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >>
|
||||
DMACH_FLAG_PERIPHPID_SHIFT) << DMACHAN_CFG_DSTPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ?
|
||||
DMACHAN_CFG_DSTH2SEL : 0;
|
||||
regval |= sam_fifocfg(dmach);
|
||||
return regval;
|
||||
}
|
||||
@@ -377,10 +383,14 @@ static inline uint32_t sam_rxcfg(struct sam_dma_s *dmach)
|
||||
/* Set received (peripheral to memory) DMA channel config */
|
||||
|
||||
regval = DMACHAN_CFG_SOD;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT) << DMACHAN_CFG_SRCPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMACHAN_CFG_SRCH2SEL : 0;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT) << DMACHAN_CFG_DSTPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMACHAN_CFG_DSTH2SEL : 0;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >>
|
||||
DMACH_FLAG_PERIPHPID_SHIFT) << DMACHAN_CFG_SRCPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ?
|
||||
DMACHAN_CFG_SRCH2SEL : 0;
|
||||
regval |= (((dmach->flags & DMACH_FLAG_MEMPID_MASK) >>
|
||||
DMACH_FLAG_MEMPID_SHIFT) << DMACHAN_CFG_DSTPER_SHIFT);
|
||||
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ?
|
||||
DMACHAN_CFG_DSTH2SEL : 0;
|
||||
regval |= sam_fifocfg(dmach);
|
||||
return regval;
|
||||
}
|
||||
@@ -404,11 +414,12 @@ sam_txctrlabits(struct sam_dma_s *dmach)
|
||||
|
||||
DEBUGASSERT(dmach);
|
||||
|
||||
/* Since this is a transmit, the source is described by the memory selections.
|
||||
* Set the source width (memory width).
|
||||
/* Since this is a transmit, the source is described by the memory
|
||||
* selection. Set the source width (memory width).
|
||||
*/
|
||||
|
||||
ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
|
||||
ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >>
|
||||
DMACH_FLAG_MEMWIDTH_SHIFT;
|
||||
DEBUGASSERT(ndx < 3);
|
||||
regval = g_srcwidth[ndx];
|
||||
|
||||
@@ -428,11 +439,12 @@ sam_txctrlabits(struct sam_dma_s *dmach)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Since this is a transmit, the destination is described by the peripheral selections.
|
||||
* Set the destination width (peripheral width).
|
||||
/* Since this is a transmit, the destination is described by the peripheral
|
||||
* selections. Set the destination width (peripheral width).
|
||||
*/
|
||||
|
||||
ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT;
|
||||
ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >>
|
||||
DMACH_FLAG_PERIPHWIDTH_SHIFT;
|
||||
DEBUGASSERT(ndx < 3);
|
||||
regval |= g_destwidth[ndx];
|
||||
|
||||
@@ -440,7 +452,8 @@ sam_txctrlabits(struct sam_dma_s *dmach)
|
||||
defined(CONFIG_ARCH_CHIP_SAM3A)
|
||||
/* Set the destination chunk size (peripheral chunk size) */
|
||||
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) ==
|
||||
DMACH_FLAG_PERIPHCHUNKSIZE_4)
|
||||
{
|
||||
regval |= DMACHAN_CTRLA_DCSIZE_4;
|
||||
}
|
||||
@@ -559,7 +572,8 @@ static inline uint32_t sam_rxctrlabits(struct sam_dma_s *dmach)
|
||||
* selections. Set the source width (peripheral width).
|
||||
*/
|
||||
|
||||
ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT;
|
||||
ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >>
|
||||
DMACH_FLAG_PERIPHWIDTH_SHIFT;
|
||||
DEBUGASSERT(ndx < 3);
|
||||
regval = g_srcwidth[ndx];
|
||||
|
||||
@@ -567,7 +581,8 @@ static inline uint32_t sam_rxctrlabits(struct sam_dma_s *dmach)
|
||||
defined(CONFIG_ARCH_CHIP_SAM3A)
|
||||
/* Set the source chunk size (peripheral chunk size) */
|
||||
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) ==
|
||||
DMACH_FLAG_PERIPHCHUNKSIZE_4)
|
||||
{
|
||||
regval |= DMACHAN_CTRLA_SCSIZE_4;
|
||||
}
|
||||
@@ -579,11 +594,12 @@ static inline uint32_t sam_rxctrlabits(struct sam_dma_s *dmach)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Since this is a receive, the destination is described by the memory selections.
|
||||
* Set the destination width (memory width).
|
||||
/* Since this is a receive, the destination is described by the memory
|
||||
* selections. Set the destination width (memory width).
|
||||
*/
|
||||
|
||||
ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
|
||||
ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >>
|
||||
DMACH_FLAG_MEMWIDTH_SHIFT;
|
||||
DEBUGASSERT(ndx < 3);
|
||||
regval |= g_destwidth[ndx];
|
||||
|
||||
@@ -764,6 +780,7 @@ static inline uint32_t sam_txctrlb(struct sam_dma_s *dmach)
|
||||
{
|
||||
regval |= DMACHAN_CTRLB_DSTINCR_FIXED;
|
||||
}
|
||||
|
||||
return regval;
|
||||
}
|
||||
|
||||
@@ -780,8 +797,8 @@ static inline uint32_t sam_rxctrlb(struct sam_dma_s *dmach)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Assume that we will not be using the link list and disable the source and
|
||||
* destination descriptors. The default will be single transfer mode.
|
||||
/* Assume that we will not be using the link list and disable the source
|
||||
* and destination descriptors. The default will be single transfer mode.
|
||||
*/
|
||||
|
||||
regval = DMACHAN_CTRLB_BOTHDSCR;
|
||||
@@ -867,6 +884,7 @@ sam_allocdesc(struct sam_dma_s *dmach, struct dma_linklist_s *prev,
|
||||
{
|
||||
struct dma_linklist_s *desc = NULL;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Sanity check -- src == 0 is the indication that the link is unused.
|
||||
* Obviously setting it to zero would break that usage.
|
||||
@@ -876,8 +894,8 @@ sam_allocdesc(struct sam_dma_s *dmach, struct dma_linklist_s *prev,
|
||||
if (src != 0)
|
||||
#endif
|
||||
{
|
||||
/* 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.
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
sam_takedsem();
|
||||
@@ -888,7 +906,12 @@ sam_allocdesc(struct sam_dma_s *dmach, struct dma_linklist_s *prev,
|
||||
* that is an atomic operation.
|
||||
*/
|
||||
|
||||
sam_takechsem();
|
||||
ret = sam_takechsem();
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_SAM34_NLLDESC; i++)
|
||||
{
|
||||
if (g_linklist[i].src == 0)
|
||||
@@ -910,12 +933,14 @@ sam_allocdesc(struct sam_dma_s *dmach, struct dma_linklist_s *prev,
|
||||
* the list
|
||||
*/
|
||||
|
||||
DEBUGASSERT(dmach->llhead == NULL && dmach->lltail == NULL);
|
||||
DEBUGASSERT(dmach->llhead == NULL &&
|
||||
dmach->lltail == NULL);
|
||||
dmach->llhead = desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGASSERT(dmach->llhead != NULL && dmach->lltail == prev);
|
||||
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.
|
||||
@@ -934,8 +959,9 @@ sam_allocdesc(struct sam_dma_s *dmach, struct dma_linklist_s *prev,
|
||||
}
|
||||
|
||||
/* In any event, this is the new tail of the list. The source
|
||||
* and destination descriptors must be disabled for the last entry
|
||||
* in the link list. */
|
||||
* and destination descriptors must be disabled for the last
|
||||
* entry in the link list.
|
||||
*/
|
||||
|
||||
desc->ctrlb |= DMACHAN_CTRLB_BOTHDSCR;
|
||||
dmach->lltail = desc;
|
||||
@@ -1070,7 +1096,7 @@ static int sam_rxbuffer(struct sam_dma_s *dmach, uint32_t paddr,
|
||||
ctrlb = sam_rxctrlb(dmach);
|
||||
}
|
||||
|
||||
ctrla = sam_rxctrla(dmach, regval, nbytes);
|
||||
ctrla = sam_rxctrla(dmach, regval, nbytes);
|
||||
|
||||
/* Add the new link list entry */
|
||||
|
||||
@@ -1131,7 +1157,8 @@ static inline int sam_single(struct sam_dma_s *dmach)
|
||||
|
||||
/* Both the DST and SRC DSCR bits should be '1' in CTRLB */
|
||||
|
||||
DEBUGASSERT((llhead->ctrlb & DMACHAN_CTRLB_BOTHDSCR) == DMACHAN_CTRLB_BOTHDSCR);
|
||||
DEBUGASSERT((llhead->ctrlb & DMACHAN_CTRLB_BOTHDSCR) ==
|
||||
DMACHAN_CTRLB_BOTHDSCR);
|
||||
|
||||
/* Set up the CFG register */
|
||||
|
||||
@@ -1142,8 +1169,8 @@ static inline int sam_single(struct sam_dma_s *dmach)
|
||||
putreg32(DMAC_CHER_ENA(dmach->chan), SAM_DMAC_CHER);
|
||||
|
||||
/* The DMA has been started. Once the transfer completes, hardware sets the
|
||||
* interrupts and disables the channel. We will received buffer complete and
|
||||
* transfer complete interrupts.
|
||||
* interrupts and disables the channel. We will received buffer complete
|
||||
* and transfer complete interrupts.
|
||||
*
|
||||
* Enable error, buffer complete and transfer complete interrupts.
|
||||
* (Since there is only a single buffer, we don't need the buffer complete
|
||||
@@ -1171,10 +1198,11 @@ static inline int sam_multiple(struct sam_dma_s *dmach)
|
||||
/* Check the first and last CTRLB values */
|
||||
|
||||
DEBUGASSERT((llhead->ctrlb & DMACHAN_CTRLB_BOTHDSCR) == 0);
|
||||
DEBUGASSERT((dmach->lltail->ctrlb & DMACHAN_CTRLB_BOTHDSCR) == DMACHAN_CTRLB_BOTHDSCR);
|
||||
DEBUGASSERT((dmach->lltail->ctrlb & DMACHAN_CTRLB_BOTHDSCR) ==
|
||||
DMACHAN_CTRLB_BOTHDSCR);
|
||||
|
||||
/* Clear any pending interrupts from any previous DMAC transfer by reading the
|
||||
* status register
|
||||
/* Clear any pending interrupts from any previous DMAC transfer by reading
|
||||
* the status register
|
||||
*
|
||||
* REVISIT: If DMAC interrupts are disabled at the NVIKC, then reading the
|
||||
* EBCISR register could cause a loss of interrupts!
|
||||
@@ -1202,12 +1230,13 @@ static inline int sam_multiple(struct sam_dma_s *dmach)
|
||||
|
||||
putreg32(DMAC_CHER_ENA(dmach->chan), SAM_DMAC_CHER);
|
||||
|
||||
/* As each buffer of data is transferred, the CTRLA register is written back
|
||||
* into the link list entry. The CTRLA contains updated BTSIZE and DONE bits.
|
||||
* Additionally, the CTRLA DONE bit is asserted when the buffer transfer has completed.
|
||||
/* As each buffer of data is transferred, the CTRLA register is written
|
||||
* back into the link list entry. The CTRLA contains updated BTSIZE and
|
||||
* DONE bits. Additionally, the CTRLA DONE bit is asserted when the buffer
|
||||
* transfer has completed.
|
||||
*
|
||||
* The DMAC transfer continues until the CTRLB register disables the descriptor
|
||||
* (DSCR bits) registers at the final buffer transfer.
|
||||
* The DMAC transfer continues until the CTRLB register disables the
|
||||
* descriptor (DSCR bits) registers at the final buffer transfer.
|
||||
*
|
||||
* Enable error, buffer complete and transfer complete interrupts. We
|
||||
* don't really need the buffer complete interrupts, but we will take them
|
||||
@@ -1394,6 +1423,7 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
struct sam_dma_s *dmach;
|
||||
unsigned int fifosize;
|
||||
unsigned int chndx;
|
||||
int ret;
|
||||
|
||||
/* Get the search parameters */
|
||||
|
||||
@@ -1404,7 +1434,11 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
*/
|
||||
|
||||
dmach = NULL;
|
||||
sam_takechsem();
|
||||
ret = sam_takechsem();
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chndx = 0; chndx < SAM34_NDMACHAN; chndx++)
|
||||
{
|
||||
@@ -1447,13 +1481,14 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
return (DMA_HANDLE)dmach;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sam_dmaconfig
|
||||
*
|
||||
* Description:
|
||||
* There are two channel usage models: (1) The channel is allocated and configured
|
||||
* in one step. This is the typical case where a DMA channel performs a constant
|
||||
* role. The alternative is (2) where the DMA channel is reconfigured on the fly.
|
||||
* There are two channel usage models: (1) The channel is allocated and
|
||||
* configured in one step. This is the typical case where a DMA channel
|
||||
* performs a constant role. The alternative is (2) where the DMA channel
|
||||
* is reconfigured on the fly.
|
||||
* In this case, the chflags provided to sam_dmachannel are not used and
|
||||
* sam_dmaconfig() is called before each DMA to configure the DMA channel
|
||||
* appropriately.
|
||||
@@ -1461,7 +1496,7 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags)
|
||||
{
|
||||
@@ -1512,7 +1547,8 @@ 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_dma_s *dmach = (struct sam_dma_s *)handle;
|
||||
ssize_t remaining = (ssize_t)nbytes;
|
||||
@@ -1543,8 +1579,8 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
* do do).
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* to do).
|
||||
*/
|
||||
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
|
||||
@@ -1580,7 +1616,8 @@ 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)
|
||||
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;
|
||||
@@ -1611,8 +1648,8 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
* do do).
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* to do).
|
||||
*/
|
||||
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
|
||||
@@ -1684,8 +1721,8 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After sam_dmastop() is called, the DMA channel is
|
||||
* reset and sam_dmarx/txsetup() must be called before sam_dmastart() can be
|
||||
* called again
|
||||
* reset and sam_dmarx/txsetup() must be called before sam_dmastart() can
|
||||
* be called again
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@@ -1773,12 +1810,18 @@ void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs,
|
||||
dmainfo(" EBCIMR[%08x]: %08x\n", SAM_DMAC_EBCIMR, regs->ebcimr);
|
||||
dmainfo(" CHSR[%08x]: %08x\n", SAM_DMAC_CHSR, regs->chsr);
|
||||
dmainfo(" DMA Channel Registers:\n");
|
||||
dmainfo(" SADDR[%08x]: %08x\n", dmach->base + SAM_DMACHAN_SADDR_OFFSET, regs->saddr);
|
||||
dmainfo(" DADDR[%08x]: %08x\n", dmach->base + SAM_DMACHAN_DADDR_OFFSET, regs->daddr);
|
||||
dmainfo(" DSCR[%08x]: %08x\n", dmach->base + SAM_DMACHAN_DSCR_OFFSET, regs->dscr);
|
||||
dmainfo(" CTRLA[%08x]: %08x\n", dmach->base + SAM_DMACHAN_CTRLA_OFFSET, regs->ctrla);
|
||||
dmainfo(" CTRLB[%08x]: %08x\n", dmach->base + SAM_DMACHAN_CTRLB_OFFSET, regs->ctrlb);
|
||||
dmainfo(" CFG[%08x]: %08x\n", dmach->base + SAM_DMACHAN_CFG_OFFSET, regs->cfg);
|
||||
dmainfo(" SADDR[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMACHAN_SADDR_OFFSET, regs->saddr);
|
||||
dmainfo(" DADDR[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMACHAN_DADDR_OFFSET, regs->daddr);
|
||||
dmainfo(" DSCR[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMACHAN_DSCR_OFFSET, regs->dscr);
|
||||
dmainfo(" CTRLA[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMACHAN_CTRLA_OFFSET, regs->ctrla);
|
||||
dmainfo(" CTRLB[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMACHAN_CTRLB_OFFSET, regs->ctrlb);
|
||||
dmainfo(" CFG[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMACHAN_CFG_OFFSET, regs->cfg);
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_DMA_INFO */
|
||||
#endif /* CONFIG_SAM34_DMAC0 */
|
||||
|
||||
+130
-78
@@ -110,6 +110,7 @@
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure maps a peripheral ID to an DMA channel */
|
||||
|
||||
struct sam_pidmap_s
|
||||
@@ -484,9 +485,9 @@ static struct sam_dmac_s g_dmac1 =
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takechsem(struct sam_dmac_s *dmac)
|
||||
static int sam_takechsem(struct sam_dmac_s *dmac)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&dmac->chsem);
|
||||
return nxsem_wait_uninterruptible(&dmac->chsem);
|
||||
}
|
||||
|
||||
static inline void sam_givechsem(struct sam_dmac_s *dmac)
|
||||
@@ -502,9 +503,9 @@ static inline void sam_givechsem(struct sam_dmac_s *dmac)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takedsem(struct sam_dmac_s *dmac)
|
||||
static int sam_takedsem(struct sam_dmac_s *dmac)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&dmac->dsem);
|
||||
return nxsem_wait_uninterruptible(&dmac->dsem);
|
||||
}
|
||||
|
||||
static inline void sam_givedsem(struct sam_dmac_s *dmac)
|
||||
@@ -605,7 +606,6 @@ 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
|
||||
*
|
||||
@@ -745,21 +745,25 @@ static inline uint32_t sam_txcfg(struct sam_dmach_s *dmach)
|
||||
|
||||
regval = DMAC_CH_CFG_SOD;
|
||||
|
||||
pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
|
||||
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);
|
||||
|
||||
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 |= ((pchan & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT - 4));
|
||||
regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ?
|
||||
DMAC_CH_CFG_SRCH2SEL : 0;
|
||||
|
||||
pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
|
||||
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 |= ((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;
|
||||
@@ -785,21 +789,25 @@ static inline uint32_t sam_rxcfg(struct sam_dmach_s *dmach)
|
||||
|
||||
regval = DMAC_CH_CFG_SOD;
|
||||
|
||||
pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
|
||||
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);
|
||||
|
||||
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 |= ((pchan & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT - 4));
|
||||
regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ?
|
||||
DMAC_CH_CFG_SRCH2SEL : 0;
|
||||
|
||||
pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
|
||||
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 |= ((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;
|
||||
@@ -824,11 +832,12 @@ static inline uint32_t sam_txctrlabits(struct sam_dmach_s *dmach)
|
||||
|
||||
DEBUGASSERT(dmach);
|
||||
|
||||
/* Since this is a transmit, the source is described by the memory selections.
|
||||
* Set the source width (memory width).
|
||||
/* Since this is a transmit, the source is described by the memory
|
||||
* selections. Set the source width (memory width).
|
||||
*/
|
||||
|
||||
ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
|
||||
ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >>
|
||||
DMACH_FLAG_MEMWIDTH_SHIFT;
|
||||
DEBUGASSERT(ndx < 4);
|
||||
regval = g_srcwidth[ndx];
|
||||
|
||||
@@ -838,11 +847,12 @@ static inline uint32_t sam_txctrlabits(struct sam_dmach_s *dmach)
|
||||
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
|
||||
regval |= chunksize << DMAC_CH_CTRLA_SCSIZE_SHIFT;
|
||||
|
||||
/* Since this is a transmit, the destination is described by the peripheral selections.
|
||||
* Set the destination width (peripheral width).
|
||||
/* Since this is a transmit, the destination is described by the peripheral
|
||||
* selections. Set the destination width (peripheral width).
|
||||
*/
|
||||
|
||||
ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT;
|
||||
ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >>
|
||||
DMACH_FLAG_PERIPHWIDTH_SHIFT;
|
||||
DEBUGASSERT(ndx < 4);
|
||||
regval |= g_destwidth[ndx];
|
||||
|
||||
@@ -1215,7 +1225,8 @@ static inline uint32_t sam_txctrlb(struct sam_dmach_s *dmach)
|
||||
|
||||
/* Destination ABH layer */
|
||||
|
||||
ahbif = (dmach->flags & DMACH_FLAG_PERIPHAHB_MASK) >> DMACH_FLAG_PERIPHAHB_SHIFT;
|
||||
ahbif = (dmach->flags & DMACH_FLAG_PERIPHAHB_MASK) >>
|
||||
DMACH_FLAG_PERIPHAHB_SHIFT;
|
||||
regval |= (ahbif << DMAC_CH_CTRLB_DIF_SHIFT);
|
||||
|
||||
/* Select destination address incrementing */
|
||||
@@ -1294,7 +1305,8 @@ static inline uint32_t sam_rxctrlb(struct sam_dmach_s *dmach)
|
||||
|
||||
/* Source ABH layer */
|
||||
|
||||
ahbif = (dmach->flags & DMACH_FLAG_PERIPHAHB_MASK) >> DMACH_FLAG_PERIPHAHB_SHIFT;
|
||||
ahbif = (dmach->flags & DMACH_FLAG_PERIPHAHB_MASK) >>
|
||||
DMACH_FLAG_PERIPHAHB_SHIFT;
|
||||
regval |= (ahbif << DMAC_CH_CTRLB_SIF_SHIFT);
|
||||
|
||||
/* Select source address incrementing */
|
||||
@@ -1340,6 +1352,7 @@ sam_allocdesc(struct sam_dmach_s *dmach, struct dma_linklist_s *prev,
|
||||
struct sam_dmac_s *dmac = sam_controller(dmach);
|
||||
struct dma_linklist_s *desc = NULL;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Sanity check -- saddr == 0 is the indication that the link is unused.
|
||||
* Obviously setting it to zero would break that usage.
|
||||
@@ -1349,19 +1362,29 @@ sam_allocdesc(struct sam_dmach_s *dmach, struct dma_linklist_s *prev,
|
||||
if (saddr != 0)
|
||||
#endif
|
||||
{
|
||||
/* 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.
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
sam_takedsem(dmac);
|
||||
ret = sam_takedsem(dmac);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Examine each link list entry to find an available one -- i.e., one
|
||||
* with saddr == 0. That saddr field is set to zero by the DMA transfer
|
||||
* complete interrupt handler. The following should be safe because
|
||||
* that is an atomic operation.
|
||||
* with saddr == 0. That saddr 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(dmac);
|
||||
ret = sam_takechsem(dmac);
|
||||
if (ret < 0)
|
||||
{
|
||||
sam_givedsem(dmac);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_SAMA5_NLLDESC; i++)
|
||||
{
|
||||
if (dmac->desc[i].saddr == 0)
|
||||
@@ -1383,12 +1406,14 @@ sam_allocdesc(struct sam_dmach_s *dmach, struct dma_linklist_s *prev,
|
||||
* the list
|
||||
*/
|
||||
|
||||
DEBUGASSERT(dmach->llhead == NULL && dmach->lltail == NULL);
|
||||
DEBUGASSERT(dmach->llhead == NULL &&
|
||||
dmach->lltail == NULL);
|
||||
dmach->llhead = desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGASSERT(dmach->llhead != NULL && dmach->lltail == prev);
|
||||
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.
|
||||
@@ -1402,26 +1427,28 @@ sam_allocdesc(struct sam_dmach_s *dmach, struct dma_linklist_s *prev,
|
||||
prev->ctrlb &= ~DMAC_CH_CTRLB_BOTHDSCR;
|
||||
|
||||
/* Link the previous tail to the new tail.
|
||||
* REVISIT: This assumes that the next description is fetched
|
||||
* via AHB IF0.
|
||||
* REVISIT: This assumes that the next description is
|
||||
* fetched via AHB IF0.
|
||||
*/
|
||||
|
||||
prev->dscr = (uint32_t)sam_physramaddr((uintptr_t)desc);
|
||||
}
|
||||
|
||||
/* In any event, this is the new tail of the list. The source
|
||||
* and destination descriptors must be disabled for the last entry
|
||||
* in the link list. */
|
||||
* and destination descriptors must be disabled for the last
|
||||
* entry in the link list.
|
||||
*/
|
||||
|
||||
desc->ctrlb |= DMAC_CH_CTRLB_BOTHDSCR;
|
||||
dmach->lltail = desc;
|
||||
|
||||
/* Assume that we will be doing multiple buffer transfers and that
|
||||
/* Assume that we will be doing multiple buffer transfers and
|
||||
* that hardware will be accessing the descriptor via DMA.
|
||||
*/
|
||||
|
||||
up_clean_dcache((uintptr_t)desc,
|
||||
(uintptr_t)desc + sizeof(struct dma_linklist_s));
|
||||
(uintptr_t)desc +
|
||||
sizeof(struct dma_linklist_s));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1565,7 +1592,7 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
ctrlb = sam_rxctrlb(dmach);
|
||||
}
|
||||
|
||||
ctrla = sam_rxctrla(dmach, regval, nbytes);
|
||||
ctrla = sam_rxctrla(dmach, regval, nbytes);
|
||||
|
||||
/* Add the new link list entry */
|
||||
|
||||
@@ -1800,10 +1827,10 @@ static int sam_dmac_interrupt(int irq, void *context, FAR void *arg)
|
||||
|
||||
if ((regval & DMAC_EBC_ERR(chndx)) != 0)
|
||||
{
|
||||
/* Yes... Terminate the transfer with an error? */
|
||||
/* Yes... Terminate the transfer with an error? */
|
||||
|
||||
dmaerr("ERROR: DMA failed: %08x\n", regval);
|
||||
sam_dmaterminate(dmach, -EIO);
|
||||
dmaerr("ERROR: DMA failed: %08x\n", regval);
|
||||
sam_dmaterminate(dmach, -EIO);
|
||||
}
|
||||
|
||||
/* Is the transfer complete? */
|
||||
@@ -1944,6 +1971,7 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
|
||||
struct sam_dmac_s *dmac;
|
||||
struct sam_dmach_s *dmach;
|
||||
unsigned int chndx;
|
||||
int ret;
|
||||
|
||||
/* Pick the DMA controller */
|
||||
|
||||
@@ -1974,7 +2002,12 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
|
||||
*/
|
||||
|
||||
dmach = NULL;
|
||||
sam_takechsem(dmac);
|
||||
ret = sam_takechsem(dmac);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chndx = 0; chndx < SAM_NDMACHAN; chndx++)
|
||||
{
|
||||
struct sam_dmach_s *candidate = &dmac->dmach[chndx];
|
||||
@@ -2019,21 +2052,21 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
|
||||
return (DMA_HANDLE)dmach;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sam_dmaconfig
|
||||
*
|
||||
* Description:
|
||||
* There are two channel usage models: (1) The channel is allocated and configured
|
||||
* in one step. This is the typical case where a DMA channel performs a constant
|
||||
* role. The alternative is (2) where the DMA channel is reconfigured on the fly.
|
||||
* In this case, the chflags provided to sam_dmachannel are not used and
|
||||
* sam_dmaconfig() is called before each DMA to configure the DMA channel
|
||||
* appropriately.
|
||||
* There are two channel usage models: (1) The channel is allocated and
|
||||
* configured in one step. This is the typical case where a DMA channel
|
||||
* performs a constant role. The alternative is (2) where the DMA channel
|
||||
* is reconfigured on the fly. In this case, the chflags provided to
|
||||
* sam_dmachannel are not used and sam_dmaconfig() is called before each
|
||||
* DMA to configure the DMA channel appropriately.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags)
|
||||
{
|
||||
@@ -2127,8 +2160,8 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
* do so).
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* to do so).
|
||||
*/
|
||||
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
|
||||
@@ -2206,8 +2239,8 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
* do so).
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* to do so).
|
||||
*/
|
||||
|
||||
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
|
||||
@@ -2235,7 +2268,8 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
|
||||
dmach->rx = true;
|
||||
dmach->rxaddr = maddr;
|
||||
dmach->rxsize = (dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0 ? nbytes : sizeof(uint32_t);
|
||||
dmach->rxsize = (dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0 ?
|
||||
nbytes : sizeof(uint32_t);
|
||||
|
||||
/* Clean caches associated with the DMA memory */
|
||||
|
||||
@@ -2290,8 +2324,8 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After sam_dmastop() is called, the DMA channel is
|
||||
* reset and sam_dmarx/txsetup() must be called before sam_dmastart() can be
|
||||
* called again
|
||||
* reset and sam_dmarx/txsetup() must be called before sam_dmastart() can
|
||||
* be called again
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@@ -2378,25 +2412,43 @@ void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs,
|
||||
|
||||
dmainfo("%s\n", msg);
|
||||
dmainfo(" DMA Global Registers:\n");
|
||||
dmainfo(" GCFG[%08x]: %08x\n", dmac->base + SAM_DMAC_GCFG_OFFSET, regs->gcfg);
|
||||
dmainfo(" EN[%08x]: %08x\n", dmac->base + SAM_DMAC_EN_OFFSET, regs->en);
|
||||
dmainfo(" SREQ[%08x]: %08x\n", dmac->base + SAM_DMAC_SREQ_OFFSET, regs->sreq);
|
||||
dmainfo(" CREQ[%08x]: %08x\n", dmac->base + SAM_DMAC_CREQ_OFFSET, regs->creq);
|
||||
dmainfo(" LAST[%08x]: %08x\n", dmac->base + SAM_DMAC_LAST_OFFSET, regs->last);
|
||||
dmainfo(" EBCIMR[%08x]: %08x\n", dmac->base + SAM_DMAC_EBCIMR_OFFSET, regs->ebcimr);
|
||||
dmainfo(" EBCISR[%08x]: %08x\n", dmac->base + SAM_DMAC_EBCISR_OFFSET, regs->ebcisr);
|
||||
dmainfo(" CHSR[%08x]: %08x\n", dmac->base + SAM_DMAC_CHSR_OFFSET, regs->chsr);
|
||||
dmainfo(" WPMR[%08x]: %08x\n", dmac->base + SAM_DMAC_WPMR_OFFSET, regs->wpmr);
|
||||
dmainfo(" WPSR[%08x]: %08x\n", dmac->base + SAM_DMAC_WPSR_OFFSET, regs->wpsr);
|
||||
dmainfo(" GCFG[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_GCFG_OFFSET, regs->gcfg);
|
||||
dmainfo(" EN[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_EN_OFFSET, regs->en);
|
||||
dmainfo(" SREQ[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_SREQ_OFFSET, regs->sreq);
|
||||
dmainfo(" CREQ[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_CREQ_OFFSET, regs->creq);
|
||||
dmainfo(" LAST[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_LAST_OFFSET, regs->last);
|
||||
dmainfo(" EBCIMR[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_EBCIMR_OFFSET, regs->ebcimr);
|
||||
dmainfo(" EBCISR[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_EBCISR_OFFSET, regs->ebcisr);
|
||||
dmainfo(" CHSR[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_CHSR_OFFSET, regs->chsr);
|
||||
dmainfo(" WPMR[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_WPMR_OFFSET, regs->wpmr);
|
||||
dmainfo(" WPSR[%08x]: %08x\n",
|
||||
dmac->base + SAM_DMAC_WPSR_OFFSET, regs->wpsr);
|
||||
dmainfo(" DMA Channel Registers:\n");
|
||||
dmainfo(" SADDR[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_SADDR_OFFSET, regs->saddr);
|
||||
dmainfo(" DADDR[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_DADDR_OFFSET, regs->daddr);
|
||||
dmainfo(" DSCR[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_DSCR_OFFSET, regs->dscr);
|
||||
dmainfo(" CTRLA[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_CTRLA_OFFSET, regs->ctrla);
|
||||
dmainfo(" CTRLB[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_CTRLB_OFFSET, regs->ctrlb);
|
||||
dmainfo(" CFG[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_CFG_OFFSET, regs->cfg);
|
||||
dmainfo(" SPIP[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_SPIP_OFFSET, regs->spip);
|
||||
dmainfo(" DPIP[%08x]: %08x\n", dmach->base + SAM_DMAC_CH_DPIP_OFFSET, regs->dpip);
|
||||
dmainfo(" SADDR[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_SADDR_OFFSET, regs->saddr);
|
||||
dmainfo(" DADDR[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_DADDR_OFFSET, regs->daddr);
|
||||
dmainfo(" DSCR[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_DSCR_OFFSET, regs->dscr);
|
||||
dmainfo(" CTRLA[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_CTRLA_OFFSET, regs->ctrla);
|
||||
dmainfo(" CTRLB[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_CTRLB_OFFSET, regs->ctrlb);
|
||||
dmainfo(" CFG[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_CFG_OFFSET, regs->cfg);
|
||||
dmainfo(" SPIP[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_SPIP_OFFSET, regs->spip);
|
||||
dmainfo(" DPIP[%08x]: %08x\n",
|
||||
dmach->base + SAM_DMAC_CH_DPIP_OFFSET, regs->dpip);
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_DMA */
|
||||
#endif /* CONFIG_SAMA5_DMAC0 || CONFIG_SAMA5_DMAC1 */
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Configuration ************************************************************/
|
||||
|
||||
/* Condition out the whole file unless DMA is selected in the configuration */
|
||||
|
||||
#ifdef CONFIG_SAMD2L2_DMAC
|
||||
@@ -80,6 +82,7 @@
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* The direction of the transfer */
|
||||
|
||||
enum sam_dmadir_e
|
||||
@@ -145,10 +148,10 @@ static sem_t g_dsem;
|
||||
|
||||
static struct sam_dmach_s g_dmach[SAMD2L2_NDMACHAN];
|
||||
|
||||
/* NOTE: Using the same address as the base descriptors for writeback descriptors
|
||||
* causes TERR and FERR interrupts to be raised immediately after starting DMA.
|
||||
* This was tested on SAMD21G18A, and it would appear that the writeback
|
||||
* buffer must be located at a different memory address.
|
||||
/* NOTE: Using the same address as the base descriptors for writeback
|
||||
* descriptors causes TERR and FERR interrupts to be raised immediately after
|
||||
* starting DMA. This was tested on SAMD21G18A, and it would appear that the
|
||||
* writeback buffer must be located at a different memory address.
|
||||
*
|
||||
* - Matt Thompson
|
||||
*/
|
||||
@@ -179,9 +182,9 @@ static struct dma_desc_s g_dma_desc[CONFIG_SAMD2L2_DMAC_NDESC]
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takechsem(void)
|
||||
static int sam_takechsem(void)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&g_chsem);
|
||||
return nxsem_wait_uninterruptible(&g_chsem);
|
||||
}
|
||||
|
||||
static inline void sam_givechsem(void)
|
||||
@@ -308,6 +311,7 @@ static int sam_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
else if ((intpend & DMAC_INTPEND_SUSP) != 0)
|
||||
{
|
||||
dmaerr("Channel suspended. Channel %d\n", chndx);
|
||||
|
||||
/* REVISIT: Do we want to do anything here? */
|
||||
}
|
||||
}
|
||||
@@ -626,17 +630,18 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
*
|
||||
* Other settings come from the channel configuration:
|
||||
*
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
*/
|
||||
|
||||
btctrl = LPSRAM_BTCTRL_VALID | LPSRAM_BTCTRL_EVOSEL_DISABLE |
|
||||
LPSRAM_BTCTRL_BLOCKACT_INT;
|
||||
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_BEATSIZE_MASK) >> DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_BEATSIZE_MASK) >>
|
||||
DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_BEATSIZE_SHIFT;
|
||||
|
||||
/* See Addressing on page 264 of the datasheet.
|
||||
@@ -665,7 +670,8 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
btctrl |= LPSRAM_BTCTRL_STEPSEL;
|
||||
}
|
||||
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_STEPSIZE_MASK) >> LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_STEPSIZE_MASK) >>
|
||||
LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
|
||||
/* Add the new descriptor list entry */
|
||||
@@ -709,17 +715,18 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
*
|
||||
* Other settings come from the channel configuration:
|
||||
*
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
*/
|
||||
|
||||
btctrl = LPSRAM_BTCTRL_VALID | LPSRAM_BTCTRL_EVOSEL_DISABLE |
|
||||
LPSRAM_BTCTRL_BLOCKACT_INT;
|
||||
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_BEATSIZE_MASK) >> DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_BEATSIZE_MASK) >>
|
||||
DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_BEATSIZE_SHIFT;
|
||||
|
||||
/* Set up the Block Transfer Count Register configuration */
|
||||
@@ -743,7 +750,8 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
btctrl |= LPSRAM_BTCTRL_STEPSEL;
|
||||
}
|
||||
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_STEPSIZE_MASK) >> LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
tmp = (dmach->dc_flags & DMACH_FLAG_STEPSIZE_MASK) >>
|
||||
LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
|
||||
/* Add the new descriptor list entry */
|
||||
@@ -855,11 +863,16 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
struct sam_dmach_s *dmach;
|
||||
irqstate_t flags;
|
||||
unsigned int chndx;
|
||||
int ret;
|
||||
|
||||
/* Search for an available DMA channel */
|
||||
|
||||
dmach = NULL;
|
||||
sam_takechsem();
|
||||
ret = sam_takechsem();
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chndx = 0; chndx < SAMD2L2_NDMACHAN; chndx++)
|
||||
{
|
||||
@@ -897,21 +910,21 @@ DMA_HANDLE sam_dmachannel(uint32_t chflags)
|
||||
return (DMA_HANDLE)dmach;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sam_dmaconfig
|
||||
*
|
||||
* Description:
|
||||
* There are two channel usage models: (1) The channel is allocated and
|
||||
* configured in one step. This is the typical case where a DMA channel performs
|
||||
* a constant role. The alternative is (2) where the DMA channel is reconfigured
|
||||
* on the fly. In this case, the chflags provided to sam_dmachannel are not used
|
||||
* and sam_dmaconfig() is called before each DMA to configure the DMA channel
|
||||
* appropriately.
|
||||
* configured in one step. This is the typical case where a DMA channel
|
||||
* performs a constant role. The alternative is (2) where the DMA channel
|
||||
* is reconfigured on the fly. In this case, the chflags provided to
|
||||
* sam_dmachannel are not used and sam_dmaconfig() is called before each
|
||||
* DMA to configure the DMA channel appropriately.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags)
|
||||
{
|
||||
@@ -997,7 +1010,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* do do).
|
||||
*
|
||||
* REVISIT: What if stepsize is not 1?
|
||||
@@ -1183,8 +1196,8 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
/* Setup the Quality of Service Control Register
|
||||
*
|
||||
* DMAC_QOSCTRL_WRBQOS_DISABLE - Background
|
||||
* DMAC_QOSCTRL_FQOS, DMAC_QOSCTRL_DQOS - Depend on DMACH_FLAG_PERIPH_QOS
|
||||
* and DMACH_FLAG_MEM_QOS
|
||||
* DMAC_QOSCTRL_FQOS, DMAC_QOSCTRL_DQOS - Depend on
|
||||
* DMACH_FLAG_PERIPH_QOS and DMACH_FLAG_MEM_QOS
|
||||
*/
|
||||
|
||||
periphqos = (dmach->dc_flags & DMACH_FLAG_PERIPH_QOS_MASK) >>
|
||||
@@ -1321,15 +1334,20 @@ void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs,
|
||||
|
||||
dmainfo("%s\n", msg);
|
||||
dmainfo(" DMAC Registers:\n");
|
||||
dmainfo(" CTRL: %04x CRCCTRL: %04x CRCDATAIN: %08x CRCCHKSUM: %08x\n",
|
||||
dmainfo(" CTRL: %04x CRCCTRL: %04x"
|
||||
" CRCDATAIN: %08x CRCCHKSUM: %08x\n",
|
||||
regs->ctrl, regs->crcctrl, regs->crcdatain, regs->crcchksum);
|
||||
dmainfo(" CRCSTATUS: %02x DBGCTRL: %02x QOSCTRL: %02x SWTRIGCTRL: %08x\n",
|
||||
dmainfo(" CRCSTATUS: %02x DBGCTRL: %02x"
|
||||
" QOSCTRL: %02x SWTRIGCTRL: %08x\n",
|
||||
regs->crcstatus, regs->dbgctrl, regs->qosctrl, regs->swtrigctrl);
|
||||
dmainfo(" PRICTRL0: %08x INTPEND: %04x INTSTATUS: %08x BUSYCH: %08x\n",
|
||||
dmainfo(" PRICTRL0: %08x INTPEND: %04x"
|
||||
" INTSTATUS: %08x BUSYCH: %08x\n",
|
||||
regs->prictrl0, regs->intpend, regs->intstatus, regs->busych);
|
||||
dmainfo(" PENDCH: %08x ACTIVE: %08x BASEADDR: %08x WRBADDR: %08x\n",
|
||||
dmainfo(" PENDCH: %08x ACTIVE: %08x"
|
||||
" BASEADDR: %08x WRBADDR: %08x\n",
|
||||
regs->pendch, regs->active, regs->baseaddr, regs->wrbaddr);
|
||||
dmainfo(" CHID: %02x CHCRTRLA: %02x CHCRTRLB: %08x CHINFLAG: %02x\n",
|
||||
dmainfo(" CHID: %02x CHCRTRLA: %02x"
|
||||
" CHCRTRLB: %08x CHINFLAG: %02x\n",
|
||||
regs->chid, regs->chctrla, regs->chctrlb, regs->chintflag);
|
||||
dmainfo(" CHSTATUS: %02x\n",
|
||||
regs->chstatus);
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Configuration ************************************************************/
|
||||
|
||||
/* Condition out the whole file unless DMA is selected in the configuration */
|
||||
|
||||
#ifdef CONFIG_SAMD5E5_DMAC
|
||||
@@ -80,6 +82,7 @@
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* The direction of the transfer */
|
||||
|
||||
enum sam_dmadir_e
|
||||
@@ -111,7 +114,7 @@ struct sam_dmach_s
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takechsem(void);
|
||||
static int sam_takechsem(void);
|
||||
static inline void sam_givechsem(void);
|
||||
#if CONFIG_SAMD5E5_DMAC_NDESC > 0
|
||||
static void sam_takedsem(void);
|
||||
@@ -147,8 +150,9 @@ static sem_t g_dsem;
|
||||
|
||||
static struct sam_dmach_s g_dmach[SAMD5E5_NDMACHAN];
|
||||
|
||||
/* NOTE: Using the same address as the base descriptors for writeback descriptors
|
||||
* causes TERR and FERR interrupts to be raised immediately after starting DMA.
|
||||
/* NOTE: Using the same address as the base descriptors for writeback
|
||||
* descriptors causes TERR and FERR interrupts to be raised immediately after
|
||||
* starting DMA.
|
||||
*/
|
||||
|
||||
static struct dma_desc_s g_base_desc[SAMD5E5_NDMACHAN]
|
||||
@@ -177,9 +181,9 @@ static struct dma_desc_s g_dma_desc[CONFIG_SAMD5E5_DMAC_NDESC]
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takechsem(void)
|
||||
static int sam_takechsem(void)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&g_chsem);
|
||||
return nxsem_wait_uninterruptible(&g_chsem);
|
||||
}
|
||||
|
||||
static inline void sam_givechsem(void)
|
||||
@@ -310,6 +314,7 @@ static int sam_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
else if ((intpend & DMAC_INTPEND_SUSP) != 0)
|
||||
{
|
||||
dmaerr("Channel suspended. Channel %d\n", chndx);
|
||||
|
||||
/* REVISIT: Do we want to do anything here? */
|
||||
}
|
||||
}
|
||||
@@ -532,7 +537,8 @@ static size_t sam_maxtransfer(struct sam_dmach_s *dmach, uint32_t dmaflags)
|
||||
|
||||
/* The number of bytes per beat is 2**BEATSIZE */
|
||||
|
||||
beatsize = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >> LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
beatsize = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >>
|
||||
LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
|
||||
/* Maximum beats is UINT16_MAX */
|
||||
|
||||
@@ -556,7 +562,8 @@ static uint16_t sam_bytes2beats(struct sam_dmach_s *dmach, uint32_t dmaflags,
|
||||
|
||||
/* The number of bytes per beat is 2**BEATSIZE */
|
||||
|
||||
beatsize = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >> LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
beatsize = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >>
|
||||
LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
|
||||
/* The number of beats is then the ceiling of the division */
|
||||
|
||||
@@ -596,17 +603,18 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
*
|
||||
* Other settings come from the channel configuration:
|
||||
*
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
*/
|
||||
|
||||
btctrl = LPSRAM_BTCTRL_VALID | LPSRAM_BTCTRL_EVOSEL_DISABLE |
|
||||
LPSRAM_BTCTRL_BLOCKACT_INT;
|
||||
|
||||
tmp = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >> DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
tmp = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >>
|
||||
DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_BEATSIZE_SHIFT;
|
||||
|
||||
/* See Addressing on page 264 of the datasheet.
|
||||
@@ -635,7 +643,8 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
btctrl |= LPSRAM_BTCTRL_STEPSEL;
|
||||
}
|
||||
|
||||
tmp = (dmaflags & DMACH_FLAG_STEPSIZE_MASK) >> LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
tmp = (dmaflags & DMACH_FLAG_STEPSIZE_MASK) >>
|
||||
LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
|
||||
/* Add the new descriptor list entry */
|
||||
@@ -679,17 +688,18 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
*
|
||||
* Other settings come from the channel configuration:
|
||||
*
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
* LPSRAM_BTCTRL_BEATSIZE - Determined by DMACH_FLAG_BEATSIZE
|
||||
* LPSRAM_BTCTRL_SRCINC - Determined by DMACH_FLAG_PERIPH_INCREMENT
|
||||
* LPSRAM_BTCTRL_DSTINC - Determined by DMACH_FLAG_MEM_INCREMENT
|
||||
* LPSRAM_BTCTRL_STEPSEL - Determined by DMACH_FLAG_STEPSEL
|
||||
* LPSRAM_BTCTRL_STEPSIZE - Determined by DMACH_FLAG_STEPSIZE
|
||||
*/
|
||||
|
||||
btctrl = LPSRAM_BTCTRL_VALID | LPSRAM_BTCTRL_EVOSEL_DISABLE |
|
||||
LPSRAM_BTCTRL_BLOCKACT_INT;
|
||||
|
||||
tmp = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >> DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
tmp = (dmaflags & DMACH_FLAG_BEATSIZE_MASK) >>
|
||||
DMACH_FLAG_BEATSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_BEATSIZE_SHIFT;
|
||||
|
||||
/* Set up the Block Transfer Count Register configuration */
|
||||
@@ -713,7 +723,8 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
|
||||
btctrl |= LPSRAM_BTCTRL_STEPSEL;
|
||||
}
|
||||
|
||||
tmp = (dmaflags & DMACH_FLAG_STEPSIZE_MASK) >> LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
tmp = (dmaflags & DMACH_FLAG_STEPSIZE_MASK) >>
|
||||
LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
btctrl |= tmp << LPSRAM_BTCTRL_STEPSIZE_SHIFT;
|
||||
|
||||
/* Add the new descriptor list entry */
|
||||
@@ -836,11 +847,16 @@ DMA_HANDLE sam_dmachannel(uint32_t txflags, uint32_t rxflags)
|
||||
struct sam_dmach_s *dmach;
|
||||
irqstate_t flags;
|
||||
unsigned int chndx;
|
||||
int ret;
|
||||
|
||||
/* Search for an available DMA channel */
|
||||
|
||||
dmach = NULL;
|
||||
sam_takechsem();
|
||||
ret = sam_takechsem();
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chndx = 0; chndx < SAMD5E5_NDMACHAN; chndx++)
|
||||
{
|
||||
@@ -878,21 +894,21 @@ DMA_HANDLE sam_dmachannel(uint32_t txflags, uint32_t rxflags)
|
||||
return (DMA_HANDLE)dmach;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sam_dmaconfig
|
||||
*
|
||||
* Description:
|
||||
* There are two channel usage models: (1) The channel is allocated and
|
||||
* configured in one step. This is the typical case where a DMA channel performs
|
||||
* a constant role. The alternative is (2) where the DMA channel is reconfigured
|
||||
* on the fly. In this case, the chflags provided to sam_dmachannel are not used
|
||||
* and sam_dmaconfig() is called before each DMA to configure the DMA channel
|
||||
* appropriately.
|
||||
* configured in one step. This is the typical case where a DMA channel
|
||||
* performs a constant role. The alternative is (2) where the DMA channel
|
||||
* is reconfigured on the fly. In this case, the chflags provided to
|
||||
* sam_dmachannel are not usedand sam_dmaconfig() is called before each DMA
|
||||
* to configure the DMA channel appropriately.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
void sam_dmaconfig(DMA_HANDLE handle, uint32_t txflags, uint32_t rxflags)
|
||||
{
|
||||
@@ -975,14 +991,15 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
{
|
||||
/* Set up the maximum size transfer */
|
||||
|
||||
ret = sam_txbuffer(dmach, paddr, maddr, dmach->dc_txflags, maxtransfer);
|
||||
ret = sam_txbuffer(dmach, paddr, maddr, dmach->dc_txflags,
|
||||
maxtransfer);
|
||||
if (ret == OK)
|
||||
{
|
||||
/* Decrement the number of bytes left to transfer */
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* do do).
|
||||
*
|
||||
* REVISIT: What if stepsize is not 1?
|
||||
@@ -1049,7 +1066,8 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
{
|
||||
/* Set up the maximum size transfer */
|
||||
|
||||
ret = sam_rxbuffer(dmach, paddr, maddr, dmach->dc_rxflags, maxtransfer);
|
||||
ret = sam_rxbuffer(dmach, paddr, maddr, dmach->dc_rxflags,
|
||||
maxtransfer);
|
||||
if (ret == OK)
|
||||
{
|
||||
/* Decrement the number of bytes left to transfer */
|
||||
@@ -1161,22 +1179,26 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
|
||||
/* Trigger source */
|
||||
|
||||
regval32 = (dmaflags & DMACH_FLAG_PERIPH_TRIGSRC_MASK) >> DMACH_FLAG_PERIPH_TRIGSRC_SHIFT;
|
||||
regval32 = (dmaflags & DMACH_FLAG_PERIPH_TRIGSRC_MASK) >>
|
||||
DMACH_FLAG_PERIPH_TRIGSRC_SHIFT;
|
||||
ctrla |= DMAC_CHCTRLA_TRIGSRC(regval32) ;
|
||||
|
||||
/* Trigger action */
|
||||
|
||||
regval32 = (dmaflags & DMAC_CHCTRLA_TRIGACT_MASK) >> DMAC_CHCTRLA_TRIGACT_SHIFT;
|
||||
regval32 = (dmaflags & DMAC_CHCTRLA_TRIGACT_MASK) >>
|
||||
DMAC_CHCTRLA_TRIGACT_SHIFT;
|
||||
ctrla |= DMAC_CHCTRLA_TRIGACT(regval32) ;
|
||||
|
||||
/* Burst length */
|
||||
|
||||
regval32 = ((dmaflags & DMACH_FLAG_BURSTLEN_MASK) >> DMACH_FLAG_BURSTLEN_SHIFT) + 1;
|
||||
regval32 = ((dmaflags & DMACH_FLAG_BURSTLEN_MASK) >>
|
||||
DMACH_FLAG_BURSTLEN_SHIFT) + 1;
|
||||
ctrla |= DMAC_CHCTRLA_BURSTLEN(regval32) ;
|
||||
|
||||
/* Threshold */
|
||||
|
||||
regval32 = ((dmaflags & DMACH_FLAG_BURSTLEN_MASK) >> DMACH_FLAG_BURSTLEN_SHIFT) + 1;
|
||||
regval32 = ((dmaflags & DMACH_FLAG_BURSTLEN_MASK) >>
|
||||
DMACH_FLAG_BURSTLEN_SHIFT) + 1;
|
||||
ctrla |= DMAC_CHCTRLA_THRESHOLD(regval32) ;
|
||||
|
||||
putreg32(ctrla, SAM_DMAC_CHCTRLA(chan));
|
||||
@@ -1193,7 +1215,8 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
|
||||
/* Set up the channel priority register */
|
||||
|
||||
regval8 = (dmaflags & DMACH_FLAG_PRIORITY_MASK) >> DMACH_FLAG_PRIORITY_SHIFT;
|
||||
regval8 = (dmaflags & DMACH_FLAG_PRIORITY_MASK) >>
|
||||
DMACH_FLAG_PRIORITY_SHIFT;
|
||||
putreg8(DMAC_CHPRILVL(regval8), SAM_DMAC_CHPRILVL(chan));
|
||||
|
||||
/* Setup channel event control register
|
||||
@@ -1320,17 +1343,21 @@ void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs,
|
||||
flags = enter_critical_section();
|
||||
dmainfo("%s\n", msg);
|
||||
dmainfo(" DMAC Global Registers:\n");
|
||||
dmainfo(" CTRL: %04x CRCCTRL: %04x CRCDATAIN: %08x CRCCHKSUM: %08x\n",
|
||||
dmainfo(" CTRL: %04x CRCCTRL: %04x "
|
||||
"CRCDATAIN: %08x CRCCHKSUM: %08x\n",
|
||||
regs->ctrl, regs->crcctrl, regs->crcdatain, regs->crcchksum);
|
||||
dmainfo(" CRCSTATUS: %02x DBGCTRL: %02x SWTRIGCTRL: %08x PRICTRL0: %08x\n",
|
||||
dmainfo(" CRCSTATUS: %02x DBGCTRL: %02x "
|
||||
"SWTRIGCTRL: %08x PRICTRL0: %08x\n",
|
||||
regs->crcstatus, regs->dbgctrl, regs->swtrigctrl, regs->prictrl0);
|
||||
dmainfo(" INTPEND: %04x INTSTATUS: %08x BUSYCH: %08x PENDCH: %08x\n",
|
||||
dmainfo(" INTPEND: %04x INTSTATUS: %08x "
|
||||
"BUSYCH: %08x PENDCH: %08x\n",
|
||||
regs->intpend, regs->intstatus, regs->busych, regs->pendch);
|
||||
dmainfo(" ACTIVE: %08x BASEADDR: %08x WRBADDR: %08x\n",
|
||||
regs->active, regs->baseaddr, regs->wrbaddr);
|
||||
|
||||
dmainfo(" DMAC Channel %u Registers:\n", regs->chan);
|
||||
dmainfo(" CHCRTRLA: %08x CHCRTRLB: %02x CHPRILVL: %02x CHPRILVL: %02x\n",
|
||||
dmainfo(" CHCRTRLA: %08x CHCRTRLB: %02x "
|
||||
"CHPRILVL: %02x CHPRILVL: %02x\n",
|
||||
regs->chctrla, regs->chctrlb, regs->chprilvl, priv->chprilvl);
|
||||
dmainfo(" CHINFLAG: %02x CHSTATUS: %02x\n",
|
||||
regs->chintflag, regs->chstatus);
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure maps a peripheral ID to an DMA channel */
|
||||
|
||||
struct sam_pidmap_s
|
||||
@@ -168,6 +169,7 @@ static const struct sam_pidmap_s g_xdmac_rxchan[] =
|
||||
{ SAM_PID_TC2, XDMACH_TC2_RX }, /* TC2 Receive */
|
||||
{ SAM_PID_TC3, XDMACH_TC3_RX } /* TC3 Receive */
|
||||
};
|
||||
|
||||
#define NXDMAC_RXCHANNELS (sizeof(g_xdmac_rxchan) / sizeof(struct sam_pidmap_s))
|
||||
|
||||
/* TX DMA: */
|
||||
@@ -195,6 +197,7 @@ static const struct sam_pidmap_s g_xdmac_txchan[] =
|
||||
{ SAM_PID_AES, XDMACH_AES_TX }, /* AES Transmit */
|
||||
{ SAM_PID_PWM1, XDMACH_PWM1_TX } /* PWM01Transmit */
|
||||
};
|
||||
|
||||
#define NXDMAC_TXCHANNELS (sizeof(g_xdmac_txchan) / sizeof(struct sam_pidmap_s))
|
||||
|
||||
/* This array describes the available link list descriptors */
|
||||
@@ -367,9 +370,9 @@ static struct sam_xdmac_s g_xdmac;
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takechsem(struct sam_xdmac_s *xdmac)
|
||||
static int sam_takechsem(struct sam_xdmac_s *xdmac)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&xdmac->chsem);
|
||||
return nxsem_wait_uninterruptible(&xdmac->chsem);
|
||||
}
|
||||
|
||||
static inline void sam_givechsem(struct sam_xdmac_s *xdmac)
|
||||
@@ -385,9 +388,9 @@ static inline void sam_givechsem(struct sam_xdmac_s *xdmac)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sam_takedsem(struct sam_xdmac_s *xdmac)
|
||||
static int sam_takedsem(struct sam_xdmac_s *xdmac)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&xdmac->dsem);
|
||||
return nxsem_wait_uninterruptible(&xdmac->dsem);
|
||||
}
|
||||
|
||||
static inline void sam_givedsem(struct sam_xdmac_s *xdmac)
|
||||
@@ -773,7 +776,8 @@ static inline uint32_t sam_txcc(struct sam_xdmach_s *xdmach)
|
||||
|
||||
/* TX -> Destination is peripheral */
|
||||
|
||||
if ((xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) == DMACH_FLAG_PERIPHAHB_AHB_IF1)
|
||||
if ((xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) ==
|
||||
DMACH_FLAG_PERIPHAHB_AHB_IF1)
|
||||
{
|
||||
regval |= XDMACH_CC_DIF;
|
||||
}
|
||||
@@ -924,7 +928,8 @@ static inline uint32_t sam_rxcc(struct sam_xdmach_s *xdmach)
|
||||
* RX -> Source is peripheral
|
||||
*/
|
||||
|
||||
if ((xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) == DMACH_FLAG_PERIPHAHB_AHB_IF1)
|
||||
if ((xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) ==
|
||||
DMACH_FLAG_PERIPHAHB_AHB_IF1)
|
||||
{
|
||||
regval |= XDMACH_CC_SIF;
|
||||
}
|
||||
@@ -987,6 +992,7 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct chnext_view1_s *prev,
|
||||
struct sam_xdmac_s *xdmac = sam_controller(xdmach);
|
||||
struct chnext_view1_s *descr = NULL;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Sanity check -- csa == 0 is the indication that the link is unused.
|
||||
* Obviously setting it to zero would break that usage.
|
||||
@@ -996,11 +1002,15 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct chnext_view1_s *prev,
|
||||
if (csa != 0)
|
||||
#endif
|
||||
{
|
||||
/* 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.
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
sam_takedsem(xdmac);
|
||||
ret = sam_takedsem(xdmac);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Examine each link list entry to find an available one -- i.e., one
|
||||
* with csa == 0. That csa field is set to zero by the DMA transfer
|
||||
@@ -1008,7 +1018,13 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct chnext_view1_s *prev,
|
||||
* that is an atomic operation.
|
||||
*/
|
||||
|
||||
sam_takechsem(xdmac);
|
||||
ret = sam_takechsem(xdmac);
|
||||
if (ret < 0)
|
||||
{
|
||||
sam_givedsem(xdmac);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_SAMV7_NLLDESC; i++)
|
||||
{
|
||||
if (g_lldesc[i].csa == 0)
|
||||
@@ -1029,12 +1045,14 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct chnext_view1_s *prev,
|
||||
* the list
|
||||
*/
|
||||
|
||||
DEBUGASSERT(xdmach->llhead == NULL && xdmach->lltail == NULL);
|
||||
DEBUGASSERT(xdmach->llhead == NULL &&
|
||||
xdmach->lltail == NULL);
|
||||
xdmach->llhead = descr;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGASSERT(xdmach->llhead != NULL && xdmach->lltail == prev);
|
||||
DEBUGASSERT(xdmach->llhead != NULL &&
|
||||
xdmach->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.
|
||||
@@ -1046,8 +1064,8 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct chnext_view1_s *prev,
|
||||
prev->cubc |= CHNEXT_UBC_NDE;
|
||||
|
||||
/* Link the previous tail to the new tail.
|
||||
* REVISIT: This assumes that the next description is fetched
|
||||
* via AHB IF0.
|
||||
* REVISIT: This assumes that the next description is
|
||||
* fetched via AHB IF0.
|
||||
*/
|
||||
|
||||
prev->cnda = (uint32_t)sam_physramaddr((uintptr_t)descr);
|
||||
@@ -1057,12 +1075,13 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct chnext_view1_s *prev,
|
||||
|
||||
xdmach->lltail = descr;
|
||||
|
||||
/* Assume that we will be doing multiple buffer transfers and that
|
||||
/* Assume that we will be doing multiple buffer transfers and
|
||||
* that hardware will be accessing the descriptor via DMA.
|
||||
*/
|
||||
|
||||
up_clean_dcache((uintptr_t)descr,
|
||||
(uintptr_t)descr + sizeof(struct chnext_view1_s));
|
||||
(uintptr_t)descr +
|
||||
sizeof(struct chnext_view1_s));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1635,13 +1654,19 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
|
||||
struct sam_xdmac_s *xdmac = &g_xdmac;
|
||||
struct sam_xdmach_s *xdmach;
|
||||
unsigned int chndx;
|
||||
int ret;
|
||||
|
||||
/* Search for an available DMA channel with at least the requested FIFO
|
||||
* size.
|
||||
*/
|
||||
|
||||
xdmach = NULL;
|
||||
sam_takechsem(xdmac);
|
||||
ret = sam_takechsem(xdmac);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chndx = 0; chndx < SAMV7_NDMACHAN; chndx++)
|
||||
{
|
||||
struct sam_xdmach_s *candidate = &g_xdmach[chndx];
|
||||
@@ -1686,13 +1711,14 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
|
||||
return (DMA_HANDLE)xdmach;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sam_dmaconfig
|
||||
*
|
||||
* Description:
|
||||
* There are two channel usage models: (1) The channel is allocated and configured
|
||||
* in one step. This is the typical case where a DMA channel performs a constant
|
||||
* role. The alternative is (2) where the DMA channel is reconfigured on the fly.
|
||||
* There are two channel usage models: (1) The channel is allocated and
|
||||
* configured in one step. This is the typical case where a DMA channel
|
||||
* performs a constant role. The alternative is (2) where the DMA channel
|
||||
* is reconfigured on the fly.
|
||||
* In this case, the chflags provided to sam_dmachannel are not used and
|
||||
* sam_dmaconfig() is called before each DMA to configure the DMA channel
|
||||
* appropriately.
|
||||
@@ -1700,7 +1726,7 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags)
|
||||
{
|
||||
@@ -1793,8 +1819,8 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
* do so).
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* to do so).
|
||||
*/
|
||||
|
||||
if ((xdmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
|
||||
@@ -1872,8 +1898,8 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
|
||||
remaining -= maxtransfer;
|
||||
|
||||
/* Increment the memory & peripheral address (if it is appropriate to
|
||||
* do so).
|
||||
/* Increment the memory & peripheral address (if it is appropriate
|
||||
* to do so).
|
||||
*/
|
||||
|
||||
if ((xdmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
|
||||
@@ -1901,7 +1927,8 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
|
||||
xdmach->rx = true;
|
||||
xdmach->rxaddr = maddr;
|
||||
xdmach->rxsize = (xdmach->flags & DMACH_FLAG_MEMINCREMENT) != 0 ? nbytes : sizeof(uint32_t);
|
||||
xdmach->rxsize = (xdmach->flags & DMACH_FLAG_MEMINCREMENT) != 0 ?
|
||||
nbytes : sizeof(uint32_t);
|
||||
|
||||
/* Clean caches associated with the DMA memory */
|
||||
|
||||
@@ -1966,8 +1993,8 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After sam_dmastop() is called, the DMA channel is
|
||||
* reset and sam_dmarx/txsetup() must be called before sam_dmastart() can be
|
||||
* called again
|
||||
* reset and sam_dmarx/txsetup() must be called before sam_dmastart() can
|
||||
* be called again.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@@ -2065,17 +2092,28 @@ void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs,
|
||||
dmainfo(" GWS[%08x]: %08x\n", SAM_XDMAC_GWS, regs->gws);
|
||||
dmainfo(" GSWS[%08x]: %08x\n", SAM_XDMAC_GSWS, regs->gsws);
|
||||
dmainfo(" DMA Channel Registers:\n");
|
||||
dmainfo(" CIM[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CIM_OFFSET, regs->cim);
|
||||
dmainfo(" CSA[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CSA_OFFSET, regs->csa);
|
||||
dmainfo(" CDA[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CDA_OFFSET, regs->cda);
|
||||
dmainfo(" CNDA[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CNDA_OFFSET, regs->cnda);
|
||||
dmainfo(" CNDC[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CNDC_OFFSET, regs->cndc);
|
||||
dmainfo(" CUBC[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CUBC_OFFSET, regs->cubc);
|
||||
dmainfo(" CBC[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CBC_OFFSET, regs->cbc);
|
||||
dmainfo(" CC[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CC_OFFSET, regs->cc);
|
||||
dmainfo(" CDSMSP[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CDSMSP_OFFSET, regs->cdsmsp);
|
||||
dmainfo(" CSUS[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CSUS_OFFSET, regs->csus);
|
||||
dmainfo(" CDUS[%08x]: %08x\n", xdmach->base + SAM_XDMACH_CDUS_OFFSET, regs->cdus);
|
||||
dmainfo(" CIM[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CIM_OFFSET, regs->cim);
|
||||
dmainfo(" CSA[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CSA_OFFSET, regs->csa);
|
||||
dmainfo(" CDA[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CDA_OFFSET, regs->cda);
|
||||
dmainfo(" CNDA[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CNDA_OFFSET, regs->cnda);
|
||||
dmainfo(" CNDC[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CNDC_OFFSET, regs->cndc);
|
||||
dmainfo(" CUBC[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CUBC_OFFSET, regs->cubc);
|
||||
dmainfo(" CBC[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CBC_OFFSET, regs->cbc);
|
||||
dmainfo(" CC[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CC_OFFSET, regs->cc);
|
||||
dmainfo(" CDSMSP[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CDSMSP_OFFSET, regs->cdsmsp);
|
||||
dmainfo(" CSUS[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CSUS_OFFSET, regs->csus);
|
||||
dmainfo(" CDUS[%08x]: %08x\n",
|
||||
xdmach->base + SAM_XDMACH_CDUS_OFFSET, regs->cdus);
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_DMA_INFO */
|
||||
#endif /* CONFIG_SAMV7_XDMAC */
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/stm32/stm32_dma_v1.c
|
||||
*
|
||||
* Copyright (C) 2009, 2011-2013, 2016-2017 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2009, 2011-2013, 2016-2017 Gregory Nutt.
|
||||
* All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -55,7 +56,8 @@
|
||||
#include "stm32_dma.h"
|
||||
#include "stm32.h"
|
||||
|
||||
/* This file supports the STM32 DMA IP core version 1 - F0, F1, F3, L0, L1, L4
|
||||
/* This file supports the STM32 DMA IP core version 1 - F0, F1, F3, L0, L1,
|
||||
* L4.
|
||||
*
|
||||
* F0, L0 and L4 have the additional CSELR register which is used to remap
|
||||
* the DMA requests for each channel.
|
||||
@@ -157,7 +159,8 @@ static struct stm32_dma_s g_dma[DMA_NCHANNELS] =
|
||||
},
|
||||
{
|
||||
.chan = 3,
|
||||
#if defined(CONFIG_STM32_CONNECTIVITYLINE) || defined(CONFIG_STM32_STM32F30XX) || \
|
||||
#if defined(CONFIG_STM32_CONNECTIVITYLINE) || \
|
||||
defined(CONFIG_STM32_STM32F30XX) || \
|
||||
defined(CONFIG_STM32_STM32F37XX) || defined(CONFIG_STM32_STM32L15XX)
|
||||
.irq = STM32_IRQ_DMA2CH4,
|
||||
#else
|
||||
@@ -167,7 +170,8 @@ static struct stm32_dma_s g_dma[DMA_NCHANNELS] =
|
||||
},
|
||||
{
|
||||
.chan = 4,
|
||||
#if defined(CONFIG_STM32_CONNECTIVITYLINE) || defined(CONFIG_STM32_STM32F30XX) || \
|
||||
#if defined(CONFIG_STM32_CONNECTIVITYLINE) || \
|
||||
defined(CONFIG_STM32_STM32F30XX) || \
|
||||
defined(CONFIG_STM32_STM32F37XX) || defined(CONFIG_STM32_STM32L15XX)
|
||||
.irq = STM32_IRQ_DMA2CH5,
|
||||
#else
|
||||
@@ -188,43 +192,47 @@ static struct stm32_dma_s g_dma[DMA_NCHANNELS] =
|
||||
|
||||
/* Get non-channel register from DMA1 or DMA2 */
|
||||
|
||||
static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmach, uint32_t offset)
|
||||
static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmach,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(DMA_BASE(dmach->base) + offset);
|
||||
}
|
||||
|
||||
/* Write to non-channel register in DMA1 or DMA2 */
|
||||
|
||||
static inline void dmabase_putreg(struct stm32_dma_s *dmach, uint32_t offset, uint32_t value)
|
||||
static inline void dmabase_putreg(struct stm32_dma_s *dmach,
|
||||
uint32_t offset, uint32_t value)
|
||||
{
|
||||
putreg32(value, DMA_BASE(dmach->base) + offset);
|
||||
}
|
||||
|
||||
/* Get channel register from DMA1 or DMA2 */
|
||||
|
||||
static inline uint32_t dmachan_getreg(struct stm32_dma_s *dmach, uint32_t offset)
|
||||
static inline uint32_t dmachan_getreg(struct stm32_dma_s *dmach,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(dmach->base + offset);
|
||||
}
|
||||
|
||||
/* Write to channel register in DMA1 or DMA2 */
|
||||
|
||||
static inline void dmachan_putreg(struct stm32_dma_s *dmach, uint32_t offset, uint32_t value)
|
||||
static inline void dmachan_putreg(struct stm32_dma_s *dmach,
|
||||
uint32_t offset, uint32_t value)
|
||||
{
|
||||
putreg32(value, dmach->base + offset);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmatake() and stm32_dmagive()
|
||||
*
|
||||
* Description:
|
||||
* Used to get exclusive access to a DMA channel.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmatake(FAR struct stm32_dma_s *dmach)
|
||||
static int stm32_dmatake(FAR struct stm32_dma_s *dmach)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&dmach->sem);
|
||||
return nxsem_wait_uninterruptible(&dmach->sem);
|
||||
}
|
||||
|
||||
static inline void stm32_dmagive(FAR struct stm32_dma_s *dmach)
|
||||
@@ -232,13 +240,13 @@ static inline void stm32_dmagive(FAR struct stm32_dma_s *dmach)
|
||||
nxsem_post(&dmach->sem);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmachandisable
|
||||
*
|
||||
* Description:
|
||||
* Disable the DMA channel
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmachandisable(struct stm32_dma_s *dmach)
|
||||
{
|
||||
@@ -256,16 +264,17 @@ static void stm32_dmachandisable(struct stm32_dma_s *dmach)
|
||||
|
||||
/* Clear pending channel interrupts */
|
||||
|
||||
dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, DMA_ISR_CHAN_MASK(dmach->chan));
|
||||
dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET,
|
||||
DMA_ISR_CHAN_MASK(dmach->chan));
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmainterrupt
|
||||
*
|
||||
* Description:
|
||||
* DMA interrupt handler
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static int stm32_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
{
|
||||
@@ -295,11 +304,13 @@ static int stm32_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
{
|
||||
DEBUGPANIC();
|
||||
}
|
||||
|
||||
dmach = &g_dma[chndx];
|
||||
|
||||
/* Get the interrupt status (for this channel only) */
|
||||
|
||||
isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan);
|
||||
isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) &
|
||||
DMA_ISR_CHAN_MASK(dmach->chan);
|
||||
|
||||
/* Clear the interrupts we are handling */
|
||||
|
||||
@@ -309,8 +320,10 @@ static int stm32_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
|
||||
if (dmach->callback)
|
||||
{
|
||||
dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(dmach->chan), dmach->arg);
|
||||
dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(dmach->chan),
|
||||
dmach->arg);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -396,6 +409,7 @@ DMA_HANDLE stm32_dmachannel(unsigned int chndef)
|
||||
{
|
||||
int chndx = 0;
|
||||
struct stm32_dma_s *dmach = NULL;
|
||||
int ret;
|
||||
|
||||
#ifdef DMA_HAVE_CSELR
|
||||
chndx = (chndef & DMACHAN_SETTING_CHANNEL_MASK) >>
|
||||
@@ -412,7 +426,11 @@ DMA_HANDLE stm32_dmachannel(unsigned int chndef)
|
||||
* is available if it is currently being used by another driver
|
||||
*/
|
||||
|
||||
stm32_dmatake(dmach);
|
||||
ret = stm32_dmatake(dmach);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The caller now has exclusive use of the DMA channel */
|
||||
|
||||
@@ -432,7 +450,7 @@ DMA_HANDLE stm32_dmachannel(unsigned int chndef)
|
||||
* Name: stm32_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* in a call to stm32_dmachannel, then this function will re-assign the
|
||||
* DMA channel to that thread and wake it up. NOTE: The 'handle' used
|
||||
* in this argument must NEVER be used again until stm32_dmachannel() is
|
||||
@@ -500,18 +518,18 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
dmachan_putreg(dmach, STM32_DMACHAN_CNDTR_OFFSET, ntransfers);
|
||||
|
||||
/* Configure the channel priority using the PL[1:0] bits in the DMA_CCRx
|
||||
* register. Configure data transfer direction, circular mode, peripheral & memory
|
||||
* incremented mode, peripheral & memory data size, and interrupt after
|
||||
* half and/or full transfer in the DMA_CCRx register.
|
||||
* register. Configure data transfer direction, circular mode,
|
||||
* peripheral & memory incremented mode, peripheral & memory data size,
|
||||
* and interrupt after half and/or full transfer in the DMA_CCRx register.
|
||||
*/
|
||||
|
||||
regval = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET);
|
||||
regval &= ~(DMA_CCR_MEM2MEM | DMA_CCR_PL_MASK | DMA_CCR_MSIZE_MASK |
|
||||
DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC |
|
||||
DMA_CCR_DIR);
|
||||
DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC |
|
||||
DMA_CCR_CIRC | DMA_CCR_DIR);
|
||||
ccr &= (DMA_CCR_MEM2MEM | DMA_CCR_PL_MASK | DMA_CCR_MSIZE_MASK |
|
||||
DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC |
|
||||
DMA_CCR_DIR);
|
||||
DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC |
|
||||
DMA_CCR_CIRC | DMA_CCR_DIR);
|
||||
regval |= ccr;
|
||||
dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, regval);
|
||||
|
||||
@@ -558,27 +576,29 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback,
|
||||
ccr = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET);
|
||||
ccr |= DMA_CCR_EN;
|
||||
|
||||
/* In normal mode, interrupt at either half or full completion. In circular mode,
|
||||
* always interrupt on buffer wrap, and optionally interrupt at the halfway point.
|
||||
/* In normal mode, interrupt at either half or full completion. In circular
|
||||
* mode, always interrupt on buffer wrap, and optionally interrupt at the
|
||||
* halfway point.
|
||||
*/
|
||||
|
||||
if ((ccr & DMA_CCR_CIRC) == 0)
|
||||
{
|
||||
/* Once half of the bytes are transferred, the half-transfer flag (HTIF) is
|
||||
* set and an interrupt is generated if the Half-Transfer Interrupt Enable
|
||||
* bit (HTIE) is set. At the end of the transfer, the Transfer Complete Flag
|
||||
* (TCIF) is set and an interrupt is generated if the Transfer Complete
|
||||
* Interrupt Enable bit (TCIE) is set.
|
||||
/* Once half of the bytes are transferred, the half-transfer flag
|
||||
* (HTIF) is set and an interrupt is generated if the Half-Transfer
|
||||
* Interrupt Enable bit (HTIE) is set. At the end of the transfer, the
|
||||
* Transfer Complete Flag (TCIF) is set and an interrupt is generated
|
||||
* if the Transfer Complete Interrupt Enable bit (TCIE) is set.
|
||||
*/
|
||||
|
||||
ccr |= (half ? (DMA_CCR_HTIE | DMA_CCR_TEIE) : (DMA_CCR_TCIE | DMA_CCR_TEIE));
|
||||
ccr |= (half ?
|
||||
(DMA_CCR_HTIE | DMA_CCR_TEIE) : (DMA_CCR_TCIE | DMA_CCR_TEIE));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In nonstop mode, when the transfer completes it immediately resets
|
||||
* and starts again. The transfer-complete interrupt is thus always
|
||||
* enabled, and the half-complete interrupt can be used in circular
|
||||
* mode to determine when the buffer is half-full, or in double-buffered
|
||||
* mode to determine when the buffer is half-full or in double-buffered
|
||||
* mode to determine when one of the two buffers is full.
|
||||
*/
|
||||
|
||||
@@ -698,11 +718,13 @@ bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
#endif
|
||||
case STM32_SRAM_BASE:
|
||||
case STM32_CODE_BASE:
|
||||
|
||||
/* All RAM and flash is supported */
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
||||
/* Everything else is unsupported by DMA */
|
||||
|
||||
return false;
|
||||
@@ -759,14 +781,20 @@ void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs,
|
||||
uint32_t dmabase = DMA_BASE(dmach->base);
|
||||
|
||||
dmainfo("DMA Registers: %s\n", msg);
|
||||
dmainfo(" ISRC[%08x]: %08x\n", dmabase + STM32_DMA_ISR_OFFSET, regs->isr);
|
||||
dmainfo(" ISRC[%08x]: %08x\n",
|
||||
dmabase + STM32_DMA_ISR_OFFSET, regs->isr);
|
||||
#ifdef DMA_HAVE_CSELR
|
||||
dmainfo(" CSELR[%08x]: %08x\n", dmabase + STM32_DMA_CSELR_OFFSET, regs->cselr);
|
||||
dmainfo(" CSELR[%08x]: %08x\n",
|
||||
dmabase + STM32_DMA_CSELR_OFFSET, regs->cselr);
|
||||
#endif
|
||||
dmainfo(" CCR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CCR_OFFSET, regs->ccr);
|
||||
dmainfo(" CNDTR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CNDTR_OFFSET, regs->cndtr);
|
||||
dmainfo(" CPAR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CPAR_OFFSET, regs->cpar);
|
||||
dmainfo(" CMAR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CMAR_OFFSET, regs->cmar);
|
||||
dmainfo(" CCR[%08x]: %08x\n",
|
||||
dmach->base + STM32_DMACHAN_CCR_OFFSET, regs->ccr);
|
||||
dmainfo(" CNDTR[%08x]: %08x\n",
|
||||
dmach->base + STM32_DMACHAN_CNDTR_OFFSET, regs->cndtr);
|
||||
dmainfo(" CPAR[%08x]: %08x\n",
|
||||
dmach->base + STM32_DMACHAN_CPAR_OFFSET, regs->cpar);
|
||||
dmainfo(" CMAR[%08x]: %08x\n",
|
||||
dmach->base + STM32_DMACHAN_CMAR_OFFSET, regs->cmar);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -799,6 +827,7 @@ uint32_t stm32_dma_intget(unsigned int chndx)
|
||||
{
|
||||
struct stm32_dma_s *dmach = &g_dma[chndx];
|
||||
|
||||
return dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan);
|
||||
return dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) &
|
||||
DMA_ISR_CHAN_MASK(dmach->chan);
|
||||
}
|
||||
#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */
|
||||
|
||||
@@ -211,43 +211,47 @@ static struct stm32_dma_s g_dma[DMA_NSTREAMS] =
|
||||
|
||||
/* Get non-channel register from DMA1 or DMA2 */
|
||||
|
||||
static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmast, uint32_t offset)
|
||||
static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmast,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(DMA_BASE(dmast->base) + offset);
|
||||
}
|
||||
|
||||
/* Write to non-channel register in DMA1 or DMA2 */
|
||||
|
||||
static inline void dmabase_putreg(struct stm32_dma_s *dmast, uint32_t offset, uint32_t value)
|
||||
static inline void dmabase_putreg(struct stm32_dma_s *dmast, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
putreg32(value, DMA_BASE(dmast->base) + offset);
|
||||
}
|
||||
|
||||
/* Get channel register from DMA1 or DMA2 */
|
||||
|
||||
static inline uint32_t dmast_getreg(struct stm32_dma_s *dmast, uint32_t offset)
|
||||
static inline uint32_t dmast_getreg(struct stm32_dma_s *dmast,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(dmast->base + offset);
|
||||
}
|
||||
|
||||
/* Write to channel register in DMA1 or DMA2 */
|
||||
|
||||
static inline void dmast_putreg(struct stm32_dma_s *dmast, uint32_t offset, uint32_t value)
|
||||
static inline void dmast_putreg(struct stm32_dma_s *dmast, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
putreg32(value, dmast->base + offset);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmatake() and stm32_dmagive()
|
||||
*
|
||||
* Description:
|
||||
* Used to get exclusive access to a DMA channel.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmatake(FAR struct stm32_dma_s *dmast)
|
||||
static int stm32_dmatake(FAR struct stm32_dma_s *dmast)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&dmast->sem);
|
||||
return nxsem_wait_uninterruptible(&dmast->sem);
|
||||
}
|
||||
|
||||
static inline void stm32_dmagive(FAR struct stm32_dma_s *dmast)
|
||||
@@ -255,23 +259,24 @@ static inline void stm32_dmagive(FAR struct stm32_dma_s *dmast)
|
||||
nxsem_post(&dmast->sem);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastream
|
||||
*
|
||||
* Description:
|
||||
* Get the g_dma table entry associated with a DMA controller and a stream number
|
||||
* Get the g_dma table entry associated with a DMA controller and a stream
|
||||
* number
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct stm32_dma_s *stm32_dmastream(unsigned int stream,
|
||||
unsigned int controller)
|
||||
unsigned int controller)
|
||||
{
|
||||
int index;
|
||||
|
||||
DEBUGASSERT(stream < DMA_NSTREAMS && controller < STM32_NDMA);
|
||||
|
||||
/* Convert the controller + stream based on the fact that there are 8 streams
|
||||
* per controller.
|
||||
/* Convert the controller + stream based on the fact that there are
|
||||
* 8 streams per controller.
|
||||
*/
|
||||
|
||||
#if STM32_NDMA > 1
|
||||
@@ -285,13 +290,13 @@ static inline FAR struct stm32_dma_s *stm32_dmastream(unsigned int stream,
|
||||
return &g_dma[index];
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmamap
|
||||
*
|
||||
* Description:
|
||||
* Get the g_dma table entry associated with a bit-encoded DMA selection
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct stm32_dma_s *stm32_dmamap(unsigned long dmamap)
|
||||
{
|
||||
@@ -308,13 +313,13 @@ static inline FAR struct stm32_dma_s *stm32_dmamap(unsigned long dmamap)
|
||||
return stm32_dmastream(stream, controller);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastreamdisable
|
||||
*
|
||||
* Description:
|
||||
* Disable the DMA stream
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmastreamdisable(struct stm32_dma_s *dmast)
|
||||
{
|
||||
@@ -331,8 +336,8 @@ static void stm32_dmastreamdisable(struct stm32_dma_s *dmast)
|
||||
regval &= ~DMA_SCR_EN;
|
||||
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
|
||||
|
||||
/* Clear pending stream interrupts by setting bits in the upper or lower IFCR
|
||||
* register
|
||||
/* Clear pending stream interrupts by setting bits in the upper or lower
|
||||
* IFCR register.
|
||||
*/
|
||||
|
||||
if (dmast->stream < 4)
|
||||
@@ -347,13 +352,13 @@ static void stm32_dmastreamdisable(struct stm32_dma_s *dmast)
|
||||
dmabase_putreg(dmast, regoffset, (DMA_STREAM_MASK << dmast->shift));
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmainterrupt
|
||||
*
|
||||
* Description:
|
||||
* DMA interrupt handler
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static int stm32_dmainterrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
@@ -412,10 +417,11 @@ static int stm32_dmainterrupt(int irq, void *context, void *arg)
|
||||
|
||||
/* Get the interrupt status for this stream */
|
||||
|
||||
status = (dmabase_getreg(dmast, regoffset) >> dmast->shift) & DMA_STREAM_MASK;
|
||||
status = (dmabase_getreg(dmast, regoffset) >> dmast->shift) &
|
||||
DMA_STREAM_MASK;
|
||||
|
||||
/* Clear fetched stream interrupts by setting bits in the upper or lower IFCR
|
||||
* register
|
||||
/* Clear fetched stream interrupts by setting bits in the upper or lower
|
||||
* IFCR register.
|
||||
*/
|
||||
|
||||
if (stream < 4)
|
||||
@@ -435,6 +441,7 @@ static int stm32_dmainterrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
dmast->callback(dmast, status, dmast->arg);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -505,7 +512,7 @@ void weak_function up_dma_initialize(void)
|
||||
* in chip/stm32f40xxx_dma.h
|
||||
*
|
||||
* Returned Value:
|
||||
* Provided that 'dmamap' is valid, this function ALWAYS returns a non-NULL,
|
||||
* Provided that 'dmamap' is valid, this function ALWAYS returns a non-NULL
|
||||
* void* DMA channel handle. (If 'dmamap' is invalid, the function will
|
||||
* assert if debug is enabled or do something ignorant otherwise).
|
||||
*
|
||||
@@ -519,6 +526,7 @@ void weak_function up_dma_initialize(void)
|
||||
DMA_HANDLE stm32_dmachannel(unsigned int dmamap)
|
||||
{
|
||||
FAR struct stm32_dma_s *dmast;
|
||||
int ret;
|
||||
|
||||
/* Get the stream index from the bit-encoded channel value */
|
||||
|
||||
@@ -529,7 +537,11 @@ DMA_HANDLE stm32_dmachannel(unsigned int dmamap)
|
||||
* is available if it is currently being used by another driver
|
||||
*/
|
||||
|
||||
stm32_dmatake(dmast);
|
||||
ret = stm32_dmatake(dmast);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The caller now has exclusive use of the DMA channel. Assign the
|
||||
* channel to the stream and return an opaque reference to the stream
|
||||
@@ -544,9 +556,9 @@ DMA_HANDLE stm32_dmachannel(unsigned int dmamap)
|
||||
* Name: stm32_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* in a call to stm32_dmachannel, then this function will re-assign the
|
||||
* DMA channel to that thread and wake it up. NOTE: The 'handle' used
|
||||
* Release a DMA channel. If another thread is waiting for this DMA
|
||||
* channel in a call to stm32_dmachannel, then this function will re-assign
|
||||
* the DMA channel to that thread and wake it up. NOTE: The 'handle' used
|
||||
* in this argument must NEVER be used again until stm32_dmachannel() is
|
||||
* called again to re-gain access to the channel.
|
||||
*
|
||||
@@ -593,22 +605,23 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
#endif
|
||||
|
||||
/* "If the stream is enabled, disable it by resetting the EN bit in the
|
||||
* DMA_SxCR register, then read this bit in order to confirm that there is no
|
||||
* ongoing stream operation. Writing this bit to 0 is not immediately
|
||||
* effective since it is actually written to 0 once all the current transfers
|
||||
* have finished. When the EN bit is read as 0, this means that the stream is
|
||||
* ready to be configured. It is therefore necessary to wait for the EN bit
|
||||
* to be cleared before starting any stream configuration. ..."
|
||||
* DMA_SxCR register, then read this bit in order to confirm that there is
|
||||
* no ongoing stream operation. Writing this bit to 0 is not immediately
|
||||
* effective since it is actually written to 0 once all the current
|
||||
* transfers have finished. When the EN bit is read as 0, this means that
|
||||
* the stream is ready to be configured. It is therefore necessary to wait
|
||||
* for the EN bit to be cleared before starting any stream
|
||||
* configuration. ..."
|
||||
*/
|
||||
|
||||
while ((dmast_getreg(dmast, STM32_DMA_SCR_OFFSET) & DMA_SCR_EN) != 0);
|
||||
|
||||
/* "... All the stream dedicated bits set in the status register (DMA_LISR
|
||||
* and DMA_HISR) from the previous data block DMA transfer should be cleared
|
||||
* before the stream can be re-enabled."
|
||||
* and DMA_HISR) from the previous data block DMA transfer should be
|
||||
* cleared before the stream can be re-enabled."
|
||||
*
|
||||
* Clear pending stream interrupts by setting bits in the upper or lower IFCR
|
||||
* register
|
||||
* Clear pending stream interrupts by setting bits in the upper or lower
|
||||
* IFCR register.
|
||||
*/
|
||||
|
||||
if (dmast->stream < 4)
|
||||
@@ -632,8 +645,8 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
/* "Set the memory address in the DMA_SM0ARx ... register. The data will be
|
||||
* written to or read from this memory after the peripheral event."
|
||||
*
|
||||
* Note that in double-buffered mode it is explicitly assumed that the second
|
||||
* buffer immediately follows the first.
|
||||
* Note that in double-buffered mode it is explicitly assumed that the
|
||||
* second buffer immediately follows the first.
|
||||
*/
|
||||
|
||||
dmast_putreg(dmast, STM32_DMA_SM0AR_OFFSET, maddr);
|
||||
@@ -646,15 +659,16 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
* DMA_SNDTRx register. After each peripheral event, this value will be
|
||||
* decremented."
|
||||
*
|
||||
* "When the peripheral flow controller is used for a given stream, the value
|
||||
* written into the DMA_SxNDTR has no effect on the DMA transfer. Actually,
|
||||
* whatever the value written, it will be forced by hardware to 0xFFFF as soon
|
||||
* as the stream is enabled..."
|
||||
* "When the peripheral flow controller is used for a given stream,
|
||||
* the value written into the DMA_SxNDTR has no effect on the DMA
|
||||
* transfer. Actually, whatever the value written, it will be forced by
|
||||
* hardware to 0xFFFF as soon as the stream is enabled..."
|
||||
*/
|
||||
|
||||
dmast_putreg(dmast, STM32_DMA_SNDTR_OFFSET, ntransfers);
|
||||
|
||||
/* "Select the DMA channel (request) using CHSEL[2:0] in the DMA_SxCR register."
|
||||
/* "Select the DMA channel (request) using CHSEL[2:0] in the DMA_SxCR
|
||||
* register."
|
||||
*
|
||||
* "Configure the stream priority using the PL[1:0] bits in the DMA_SCRx"
|
||||
* register."
|
||||
@@ -666,33 +680,36 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
regval |= (uint32_t)dmast->channel << DMA_SCR_CHSEL_SHIFT;
|
||||
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
|
||||
|
||||
/* "Configure the FIFO usage (enable or disable, threshold in transmission and
|
||||
* reception)"
|
||||
/* "Configure the FIFO usage (enable or disable, threshold in transmission
|
||||
* and reception)"
|
||||
*
|
||||
* "Caution is required when choosing the FIFO threshold (bits FTH[1:0] of the
|
||||
* DMA_SxFCR register) and the size of the memory burst (MBURST[1:0] of the
|
||||
* DMA_SxCR register): The content pointed by the FIFO threshold must exactly
|
||||
* match to an integer number of memory burst transfers. If this is not in the
|
||||
* case, a FIFO error (flag FEIFx of the DMA_HISR or DMA_LISR register) will be
|
||||
* generated when the stream is enabled, then the stream will be automatically
|
||||
* disabled."
|
||||
* "Caution is required when choosing the FIFO threshold (bits FTH[1:0] of
|
||||
* the DMA_SxFCR register) and the size of the memory burst (MBURST[1:0]
|
||||
* of the DMA_SxCR register): The content pointed by the FIFO threshold
|
||||
* must exactly match to an integer number of memory burst transfers.
|
||||
* If this is not in the case, a FIFO error (flag FEIFx of the DMA_HISR
|
||||
* or DMA_LISR register) will be generated when the stream is enabled,
|
||||
* then the stream will be automatically disabled."
|
||||
*
|
||||
* The FIFO is disabled in circular mode when transferring data from a
|
||||
* peripheral to memory, as in this case it is usually desirable to know that
|
||||
* every byte from the peripheral is transferred immediately to memory. It is
|
||||
* not practical to flush the DMA FIFO, as this requires disabling the channel
|
||||
* which triggers the transfer-complete interrupt.
|
||||
* peripheral to memory, as in this case it is usually desirable to know
|
||||
* that every byte from the peripheral is transferred immediately to memory
|
||||
* It is not practical to flush the DMA FIFO, as this requires disabling
|
||||
* the channel which triggers the transfer-complete interrupt.
|
||||
*
|
||||
* NOTE: The FEIFx error interrupt is not enabled because the FEIFx seems to
|
||||
* be reported spuriously causing good transfers to be marked as failures.
|
||||
* NOTE: The FEIFx error interrupt is not enabled because the FEIFx seems
|
||||
* to be reported spuriously causing good transfers to be marked as
|
||||
* failures.
|
||||
*/
|
||||
|
||||
regval = dmast_getreg(dmast, STM32_DMA_SFCR_OFFSET);
|
||||
regval &= ~(DMA_SFCR_FTH_MASK | DMA_SFCR_FS_MASK | DMA_SFCR_FEIE);
|
||||
if (!((scr & (DMA_SCR_CIRC | DMA_SCR_DIR_MASK)) == (DMA_SCR_CIRC | DMA_SCR_DIR_P2M)))
|
||||
if (!((scr & (DMA_SCR_CIRC | DMA_SCR_DIR_MASK)) ==
|
||||
(DMA_SCR_CIRC | DMA_SCR_DIR_P2M)))
|
||||
{
|
||||
regval |= (DMA_SFCR_FTH_FULL | DMA_SFCR_DMDIS);
|
||||
}
|
||||
|
||||
dmast_putreg(dmast, STM32_DMA_SFCR_OFFSET, regval);
|
||||
|
||||
/* "Configure data transfer direction, circular mode, peripheral & memory
|
||||
@@ -703,13 +720,13 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
*/
|
||||
|
||||
regval = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET);
|
||||
regval &= ~(DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC | DMA_SCR_MINC |
|
||||
DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK | DMA_SCR_PINCOS |
|
||||
DMA_SCR_CIRC | DMA_SCR_DBM | DMA_SCR_CT |
|
||||
regval &= ~(DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC |
|
||||
DMA_SCR_MINC | DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK |
|
||||
DMA_SCR_PINCOS | DMA_SCR_CIRC | DMA_SCR_DBM | DMA_SCR_CT |
|
||||
DMA_SCR_PBURST_MASK | DMA_SCR_MBURST_MASK);
|
||||
scr &= (DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC | DMA_SCR_MINC |
|
||||
DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK | DMA_SCR_PINCOS |
|
||||
DMA_SCR_DBM | DMA_SCR_CIRC |
|
||||
scr &= (DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC |
|
||||
DMA_SCR_MINC | DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK |
|
||||
DMA_SCR_PINCOS | DMA_SCR_DBM | DMA_SCR_CIRC |
|
||||
DMA_SCR_PBURST_MASK | DMA_SCR_MBURST_MASK);
|
||||
regval |= scr;
|
||||
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
|
||||
@@ -727,7 +744,8 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool half)
|
||||
void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg,
|
||||
bool half)
|
||||
{
|
||||
struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle;
|
||||
uint32_t scr;
|
||||
@@ -748,27 +766,29 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool
|
||||
scr |= DMA_SCR_EN;
|
||||
|
||||
/* In normal mode, interrupt at either half or full completion. In circular
|
||||
* and double-buffered modes, always interrupt on buffer wrap, and optionally
|
||||
* interrupt at the halfway point.
|
||||
* and double-buffered modes, always interrupt on buffer wrap, and
|
||||
* optionally interrupt at the halfway point.
|
||||
*/
|
||||
|
||||
if ((scr & (DMA_SCR_DBM | DMA_SCR_CIRC)) == 0)
|
||||
{
|
||||
/* Once half of the bytes are transferred, the half-transfer flag (HTIF) is
|
||||
* set and an interrupt is generated if the Half-Transfer Interrupt Enable
|
||||
* bit (HTIE) is set. At the end of the transfer, the Transfer Complete Flag
|
||||
* (TCIF) is set and an interrupt is generated if the Transfer Complete
|
||||
* Interrupt Enable bit (TCIE) is set.
|
||||
/* Once half of the bytes are transferred, the half-transfer flag
|
||||
* (HTIF) is set and an interrupt is generated if the Half-Transfer
|
||||
* Interrupt Enable bit (HTIE) is set. At the end of the transfer,
|
||||
* the Transfer Complete Flag (TCIF) is set and an interrupt is
|
||||
* generated if the Transfer Complete Interrupt Enable bit (TCIE)
|
||||
* is set.
|
||||
*/
|
||||
|
||||
scr |= (half ? (DMA_SCR_HTIE | DMA_SCR_TEIE) : (DMA_SCR_TCIE | DMA_SCR_TEIE));
|
||||
scr |= (half ?
|
||||
(DMA_SCR_HTIE | DMA_SCR_TEIE) : (DMA_SCR_TCIE | DMA_SCR_TEIE));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In non-stop modes, when the transfer completes it immediately resets
|
||||
* and starts again. The transfer-complete interrupt is thus always
|
||||
* enabled, and the half-complete interrupt can be used in circular
|
||||
* mode to determine when the buffer is half-full, or in double-buffered
|
||||
* mode to determine when the buffer is half-full or in double-buffered
|
||||
* mode to determine when one of the two buffers is full.
|
||||
*/
|
||||
|
||||
@@ -846,7 +866,8 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
|
||||
#ifdef CONFIG_STM32_DMACAPABLE
|
||||
bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
{
|
||||
uint32_t transfer_size, burst_length;
|
||||
uint32_t transfer_size;
|
||||
uint32_t burst_length;
|
||||
uint32_t mend;
|
||||
|
||||
dmainfo("stm32_dmacapable: 0x%08x/%u 0x%08x\n", maddr, count, ccr);
|
||||
@@ -943,11 +964,13 @@ bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
case STM32_FSMC_BANK3:
|
||||
case STM32_FSMC_BANK4:
|
||||
case STM32_SRAM_BASE:
|
||||
|
||||
/* All RAM is supported */
|
||||
|
||||
break;
|
||||
|
||||
case STM32_CODE_BASE:
|
||||
|
||||
/* Everything except the CCM ram is supported */
|
||||
|
||||
if (maddr >= STM32_CCMRAM_BASE &&
|
||||
@@ -956,12 +979,15 @@ bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
dmainfo("stm32_dmacapable: transfer targets CCMRAM\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Everything else is unsupported by DMA */
|
||||
|
||||
dmainfo("stm32_dmacapable: transfer targets unknown/unsupported region\n");
|
||||
dmainfo("stm32_dmacapable:"
|
||||
" transfer targets unknown/unsupported region\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1019,14 +1045,22 @@ void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs,
|
||||
uint32_t dmabase = DMA_BASE(dmast->base);
|
||||
|
||||
dmainfo("DMA Registers: %s\n", msg);
|
||||
dmainfo(" LISR[%08x]: %08x\n", dmabase + STM32_DMA_LISR_OFFSET, regs->lisr);
|
||||
dmainfo(" HISR[%08x]: %08x\n", dmabase + STM32_DMA_HISR_OFFSET, regs->hisr);
|
||||
dmainfo(" SCR[%08x]: %08x\n", dmast->base + STM32_DMA_SCR_OFFSET, regs->scr);
|
||||
dmainfo(" SNDTR[%08x]: %08x\n", dmast->base + STM32_DMA_SNDTR_OFFSET, regs->sndtr);
|
||||
dmainfo(" SPAR[%08x]: %08x\n", dmast->base + STM32_DMA_SPAR_OFFSET, regs->spar);
|
||||
dmainfo(" SM0AR[%08x]: %08x\n", dmast->base + STM32_DMA_SM0AR_OFFSET, regs->sm0ar);
|
||||
dmainfo(" SM1AR[%08x]: %08x\n", dmast->base + STM32_DMA_SM1AR_OFFSET, regs->sm1ar);
|
||||
dmainfo(" SFCR[%08x]: %08x\n", dmast->base + STM32_DMA_SFCR_OFFSET, regs->sfcr);
|
||||
dmainfo(" LISR[%08x]: %08x\n",
|
||||
dmabase + STM32_DMA_LISR_OFFSET, regs->lisr);
|
||||
dmainfo(" HISR[%08x]: %08x\n",
|
||||
dmabase + STM32_DMA_HISR_OFFSET, regs->hisr);
|
||||
dmainfo(" SCR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SCR_OFFSET, regs->scr);
|
||||
dmainfo(" SNDTR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SNDTR_OFFSET, regs->sndtr);
|
||||
dmainfo(" SPAR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SPAR_OFFSET, regs->spar);
|
||||
dmainfo(" SM0AR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SM0AR_OFFSET, regs->sm0ar);
|
||||
dmainfo(" SM1AR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SM1AR_OFFSET, regs->sm1ar);
|
||||
dmainfo(" SFCR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SFCR_OFFSET, regs->sfcr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
#include "stm32_dma.h"
|
||||
#include "stm32.h"
|
||||
|
||||
/* This file supports the STM32 DMA IP core version 1 - F0, F1, F3, L0, L1, L4
|
||||
/* This file supports the STM32 DMA IP core version 1 - F0, F1, F3, L0, L1,
|
||||
* L4
|
||||
*
|
||||
* F0, L0 and L4 have the additional CSELR register which is used to remap
|
||||
* the DMA requests for each channel.
|
||||
@@ -224,9 +225,9 @@ static inline void dmachan_putreg(struct stm32_dma_s *dmach,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmatake(FAR struct stm32_dma_s *dmach)
|
||||
static int stm32_dmatake(FAR struct stm32_dma_s *dmach)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&dmach->sem);
|
||||
return nxsem_wait_uninterruptible(&dmach->sem);
|
||||
}
|
||||
|
||||
static inline void stm32_dmagive(FAR struct stm32_dma_s *dmach)
|
||||
@@ -293,6 +294,7 @@ static int stm32_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
{
|
||||
DEBUGPANIC();
|
||||
}
|
||||
|
||||
dmach = &g_dma[chndx];
|
||||
|
||||
/* Get the interrupt status (for this channel only) */
|
||||
@@ -311,6 +313,7 @@ static int stm32_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(dmach->chan),
|
||||
dmach->arg);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -396,6 +399,7 @@ DMA_HANDLE stm32_dmachannel(unsigned int chndef)
|
||||
{
|
||||
int chndx = 0;
|
||||
struct stm32_dma_s *dmach = NULL;
|
||||
int ret;
|
||||
|
||||
#ifdef DMA_HAVE_CSELR
|
||||
chndx = (chndef & DMACHAN_SETTING_CHANNEL_MASK) >>
|
||||
@@ -412,7 +416,11 @@ DMA_HANDLE stm32_dmachannel(unsigned int chndef)
|
||||
* is available if it is currently being used by another driver
|
||||
*/
|
||||
|
||||
stm32_dmatake(dmach);
|
||||
ret = stm32_dmatake(dmach);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The caller now has exclusive use of the DMA channel */
|
||||
|
||||
@@ -432,9 +440,9 @@ DMA_HANDLE stm32_dmachannel(unsigned int chndef)
|
||||
* Name: stm32_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* in a call to stm32_dmachannel, then this function will re-assign the
|
||||
* DMA channel to that thread and wake it up. NOTE: The 'handle' used
|
||||
* Release a DMA channel. If another thread is waiting for this DMA
|
||||
* channel in a call to stm32_dmachannel, then this function will re-assign
|
||||
* the DMA channel to that thread and wake it up. NOTE: The 'handle' used
|
||||
* in this argument must NEVER be used again until stm32_dmachannel() is
|
||||
* called again to re-gain access to the channel.
|
||||
*
|
||||
@@ -580,7 +588,7 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback,
|
||||
/* In nonstop mode, when the transfer completes it immediately resets
|
||||
* and starts again. The transfer-complete interrupt is thus always
|
||||
* enabled, and the half-complete interrupt can be used in circular
|
||||
* mode to determine when the buffer is half-full, or in double-buffered
|
||||
* mode to determine when the buffer is half-full or in double-buffered
|
||||
* mode to determine when one of the two buffers is full.
|
||||
*/
|
||||
|
||||
@@ -694,11 +702,13 @@ bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
{
|
||||
case STM32_SRAM_BASE:
|
||||
case STM32_CODE_BASE:
|
||||
|
||||
/* All RAM and flash is supported */
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
||||
/* Everything else is unsupported by DMA */
|
||||
|
||||
return false;
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure describes one DMA channel */
|
||||
|
||||
struct stm32_dma_s
|
||||
@@ -214,43 +215,47 @@ static struct stm32_dma_s g_dma[DMA_NSTREAMS] =
|
||||
|
||||
/* Get non-channel register from DMA1 or DMA2 */
|
||||
|
||||
static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmast, uint32_t offset)
|
||||
static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmast,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(DMA_BASE(dmast->base) + offset);
|
||||
}
|
||||
|
||||
/* Write to non-channel register in DMA1 or DMA2 */
|
||||
|
||||
static inline void dmabase_putreg(struct stm32_dma_s *dmast, uint32_t offset, uint32_t value)
|
||||
static inline void dmabase_putreg(struct stm32_dma_s *dmast, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
putreg32(value, DMA_BASE(dmast->base) + offset);
|
||||
}
|
||||
|
||||
/* Get channel register from DMA1 or DMA2 */
|
||||
|
||||
static inline uint32_t dmast_getreg(struct stm32_dma_s *dmast, uint32_t offset)
|
||||
static inline uint32_t dmast_getreg(struct stm32_dma_s *dmast,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(dmast->base + offset);
|
||||
}
|
||||
|
||||
/* Write to channel register in DMA1 or DMA2 */
|
||||
|
||||
static inline void dmast_putreg(struct stm32_dma_s *dmast, uint32_t offset, uint32_t value)
|
||||
static inline void dmast_putreg(struct stm32_dma_s *dmast, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
putreg32(value, dmast->base + offset);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmatake() and stm32_dmagive()
|
||||
*
|
||||
* Description:
|
||||
* Used to get exclusive access to a DMA channel.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmatake(FAR struct stm32_dma_s *dmast)
|
||||
static int stm32_dmatake(FAR struct stm32_dma_s *dmast)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&dmast->sem);
|
||||
return nxsem_wait_uninterruptible(&dmast->sem);
|
||||
}
|
||||
|
||||
static inline void stm32_dmagive(FAR struct stm32_dma_s *dmast)
|
||||
@@ -258,23 +263,24 @@ static inline void stm32_dmagive(FAR struct stm32_dma_s *dmast)
|
||||
nxsem_post(&dmast->sem);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastream
|
||||
*
|
||||
* Description:
|
||||
* Get the g_dma table entry associated with a DMA controller and a stream number
|
||||
* Get the g_dma table entry associated with a DMA controller and a stream
|
||||
* number
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct stm32_dma_s *stm32_dmastream(unsigned int stream,
|
||||
unsigned int controller)
|
||||
unsigned int controller)
|
||||
{
|
||||
int index;
|
||||
|
||||
DEBUGASSERT(stream < DMA_NSTREAMS && controller < STM32F7_NDMA);
|
||||
|
||||
/* Convert the controller + stream based on the fact that there are 8 streams
|
||||
* per controller.
|
||||
/* Convert the controller + stream based on the fact that there are
|
||||
* 8 streams per controller.
|
||||
*/
|
||||
|
||||
#if STM32F7_NDMA > 1
|
||||
@@ -288,13 +294,13 @@ static inline FAR struct stm32_dma_s *stm32_dmastream(unsigned int stream,
|
||||
return &g_dma[index];
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmamap
|
||||
*
|
||||
* Description:
|
||||
* Get the g_dma table entry associated with a bit-encoded DMA selection
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct stm32_dma_s *stm32_dmamap(unsigned long dmamap)
|
||||
{
|
||||
@@ -311,13 +317,13 @@ static inline FAR struct stm32_dma_s *stm32_dmamap(unsigned long dmamap)
|
||||
return stm32_dmastream(stream, controller);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastreamdisable
|
||||
*
|
||||
* Description:
|
||||
* Disable the DMA stream
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmastreamdisable(struct stm32_dma_s *dmast)
|
||||
{
|
||||
@@ -334,8 +340,8 @@ static void stm32_dmastreamdisable(struct stm32_dma_s *dmast)
|
||||
regval &= ~DMA_SCR_EN;
|
||||
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
|
||||
|
||||
/* Clear pending stream interrupts by setting bits in the upper or lower IFCR
|
||||
* register
|
||||
/* Clear pending stream interrupts by setting bits in the upper or lower
|
||||
* IFCR register
|
||||
*/
|
||||
|
||||
if (dmast->stream < 4)
|
||||
@@ -350,13 +356,13 @@ static void stm32_dmastreamdisable(struct stm32_dma_s *dmast)
|
||||
dmabase_putreg(dmast, regoffset, (DMA_STREAM_MASK << dmast->shift));
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmainterrupt
|
||||
*
|
||||
* Description:
|
||||
* DMA interrupt handler
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static int stm32_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
{
|
||||
@@ -415,10 +421,11 @@ static int stm32_dmainterrupt(int irq, void *context, FAR void *arg)
|
||||
|
||||
/* Get the interrupt status for this stream */
|
||||
|
||||
status = (dmabase_getreg(dmast, regoffset) >> dmast->shift) & DMA_STREAM_MASK;
|
||||
status = (dmabase_getreg(dmast, regoffset) >> dmast->shift) &
|
||||
DMA_STREAM_MASK;
|
||||
|
||||
/* Clear fetched stream interrupts by setting bits in the upper or lower IFCR
|
||||
* register
|
||||
/* Clear fetched stream interrupts by setting bits in the upper or lower
|
||||
* IFCR register
|
||||
*/
|
||||
|
||||
if (stream < 4)
|
||||
@@ -509,7 +516,7 @@ void weak_function up_dma_initialize(void)
|
||||
* in chip/stm32f7xxxxxxx_dma.h
|
||||
*
|
||||
* Returned Value:
|
||||
* Provided that 'dmamap' is valid, this function ALWAYS returns a non-NULL,
|
||||
* Provided that 'dmamap' is valid, this function ALWAYS returns a non-NULL
|
||||
* void* DMA channel handle. (If 'dmamap' is invalid, the function will
|
||||
* assert if debug is enabled or do something ignorant otherwise).
|
||||
*
|
||||
@@ -523,6 +530,7 @@ void weak_function up_dma_initialize(void)
|
||||
DMA_HANDLE stm32_dmachannel(unsigned int dmamap)
|
||||
{
|
||||
FAR struct stm32_dma_s *dmast;
|
||||
int ret;
|
||||
|
||||
/* Get the stream index from the bit-encoded channel value */
|
||||
|
||||
@@ -533,7 +541,11 @@ DMA_HANDLE stm32_dmachannel(unsigned int dmamap)
|
||||
* is available if it is currently being used by another driver
|
||||
*/
|
||||
|
||||
stm32_dmatake(dmast);
|
||||
ret = stm32_dmatake(dmast);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The caller now has exclusive use of the DMA channel. Assign the
|
||||
* channel to the stream and return an opaque reference to the stream
|
||||
@@ -548,7 +560,7 @@ DMA_HANDLE stm32_dmachannel(unsigned int dmamap)
|
||||
* Name: stm32_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* Release a DMA channel. If another thread is waiting for this DMA channel
|
||||
* in a call to stm32_dmachannel, then this function will re-assign the
|
||||
* DMA channel to that thread and wake it up. NOTE: The 'handle' used
|
||||
* in this argument must NEVER be used again until stm32_dmachannel() is
|
||||
@@ -597,22 +609,23 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
#endif
|
||||
|
||||
/* "If the stream is enabled, disable it by resetting the EN bit in the
|
||||
* DMA_SxCR register, then read this bit in order to confirm that there is no
|
||||
* ongoing stream operation. Writing this bit to 0 is not immediately
|
||||
* effective since it is actually written to 0 once all the current transfers
|
||||
* have finished. When the EN bit is read as 0, this means that the stream is
|
||||
* ready to be configured. It is therefore necessary to wait for the EN bit
|
||||
* to be cleared before starting any stream configuration. ..."
|
||||
* DMA_SxCR register, then read this bit in order to confirm that there
|
||||
* is no ongoing stream operation. Writing this bit to 0 is not immediately
|
||||
* effective since it is actually written to 0 once all the current
|
||||
* transfers have finished. When the EN bit is read as 0, this means that
|
||||
* the stream is ready to be configured. It is therefore necessary to wait
|
||||
* for the EN bit to be cleared before starting any stream
|
||||
* configuration..."
|
||||
*/
|
||||
|
||||
while ((dmast_getreg(dmast, STM32_DMA_SCR_OFFSET) & DMA_SCR_EN) != 0);
|
||||
|
||||
/* "... All the stream dedicated bits set in the status register (DMA_LISR
|
||||
* and DMA_HISR) from the previous data block DMA transfer should be cleared
|
||||
* before the stream can be re-enabled."
|
||||
* and DMA_HISR) from the previous data block DMA transfer should be
|
||||
* cleared before the stream can be re-enabled."
|
||||
*
|
||||
* Clear pending stream interrupts by setting bits in the upper or lower IFCR
|
||||
* register
|
||||
* Clear pending stream interrupts by setting bits in the upper or lower
|
||||
* IFCR register
|
||||
*/
|
||||
|
||||
if (dmast->stream < 4)
|
||||
@@ -636,8 +649,8 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
/* "Set the memory address in the DMA_SM0ARx ... register. The data will be
|
||||
* written to or read from this memory after the peripheral event."
|
||||
*
|
||||
* Note that in double-buffered mode it is explicitly assumed that the second
|
||||
* buffer immediately follows the first.
|
||||
* Note that in double-buffered mode it is explicitly assumed that the
|
||||
* second buffer immediately follows the first.
|
||||
*/
|
||||
|
||||
dmast_putreg(dmast, STM32_DMA_SM0AR_OFFSET, maddr);
|
||||
@@ -650,15 +663,16 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
* DMA_SNDTRx register. After each peripheral event, this value will be
|
||||
* decremented."
|
||||
*
|
||||
* "When the peripheral flow controller is used for a given stream, the value
|
||||
* written into the DMA_SxNDTR has no effect on the DMA transfer. Actually,
|
||||
* whatever the value written, it will be forced by hardware to 0xFFFF as soon
|
||||
* as the stream is enabled..."
|
||||
* "When the peripheral flow controller is used for a given stream, the
|
||||
* value written into the DMA_SxNDTR has no effect on the DMA transfer.
|
||||
* Actually, whatever the value written, it will be forced by hardware
|
||||
* to 0xFFFF as soon as the stream is enabled..."
|
||||
*/
|
||||
|
||||
dmast_putreg(dmast, STM32_DMA_SNDTR_OFFSET, ntransfers);
|
||||
|
||||
/* "Select the DMA channel (request) using CHSEL[2:0] in the DMA_SxCR register."
|
||||
/* "Select the DMA channel (request) using CHSEL[2:0] in the DMA_SxCR
|
||||
* register."
|
||||
*
|
||||
* "Configure the stream priority using the PL[1:0] bits in the DMA_SCRx"
|
||||
* register."
|
||||
@@ -670,30 +684,32 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
regval |= (uint32_t)dmast->channel << DMA_SCR_CHSEL_SHIFT;
|
||||
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
|
||||
|
||||
/* "Configure the FIFO usage (enable or disable, threshold in transmission and
|
||||
* reception)"
|
||||
/* "Configure the FIFO usage (enable or disable, threshold in transmission
|
||||
* and reception)"
|
||||
*
|
||||
* "Caution is required when choosing the FIFO threshold (bits FTH[1:0] of the
|
||||
* DMA_SxFCR register) and the size of the memory burst (MBURST[1:0] of the
|
||||
* DMA_SxCR register): The content pointed by the FIFO threshold must exactly
|
||||
* match to an integer number of memory burst transfers. If this is not in the
|
||||
* case, a FIFO error (flag FEIFx of the DMA_HISR or DMA_LISR register) will be
|
||||
* generated when the stream is enabled, then the stream will be automatically
|
||||
* disabled."
|
||||
* "Caution is required when choosing the FIFO threshold (bits FTH[1:0]
|
||||
* of the DMA_SxFCR register) and the size of the memory burst
|
||||
* (MBURST[1:0] of the DMA_SxCR register): The content pointed by the FIFO
|
||||
* threshold must exactly match to an integer number of memory burst
|
||||
* transfers. If this is not in the case, a FIFO error (flag FEIFx of the
|
||||
* DMA_HISR or DMA_LISR register) will be generated when the stream is
|
||||
* enabled, then the stream will be automatically disabled."
|
||||
*
|
||||
* The FIFO is disabled in circular mode when transferring data from a
|
||||
* peripheral to memory, as in this case it is usually desirable to know that
|
||||
* every byte from the peripheral is transferred immediately to memory. It is
|
||||
* not practical to flush the DMA FIFO, as this requires disabling the channel
|
||||
* which triggers the transfer-complete interrupt.
|
||||
* peripheral to memory, as in this case it is usually desirable to know
|
||||
* that every byte from the peripheral is transferred immediately to
|
||||
* memory. It is not practical to flush the DMA FIFO, as this requires
|
||||
* disabling the channel which triggers the transfer-complete interrupt.
|
||||
*
|
||||
* NOTE: The FEIFx error interrupt is not enabled because the FEIFx seems to
|
||||
* be reported spuriously causing good transfers to be marked as failures.
|
||||
* NOTE: The FEIFx error interrupt is not enabled because the FEIFx seems
|
||||
* to be reported spuriously causing good transfers to be marked as
|
||||
* failures.
|
||||
*/
|
||||
|
||||
regval = dmast_getreg(dmast, STM32_DMA_SFCR_OFFSET);
|
||||
regval &= ~(DMA_SFCR_FTH_MASK | DMA_SFCR_FS_MASK | DMA_SFCR_FEIE);
|
||||
if (!((scr & (DMA_SCR_CIRC | DMA_SCR_DIR_MASK)) == (DMA_SCR_CIRC | DMA_SCR_DIR_P2M)))
|
||||
if (!((scr & (DMA_SCR_CIRC | DMA_SCR_DIR_MASK)) ==
|
||||
(DMA_SCR_CIRC | DMA_SCR_DIR_P2M)))
|
||||
{
|
||||
regval |= (DMA_SFCR_FTH_FULL | DMA_SFCR_DMDIS);
|
||||
}
|
||||
@@ -708,13 +724,13 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
*/
|
||||
|
||||
regval = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET);
|
||||
regval &= ~(DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC | DMA_SCR_MINC |
|
||||
DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK | DMA_SCR_PINCOS |
|
||||
DMA_SCR_CIRC | DMA_SCR_DBM | DMA_SCR_CT |
|
||||
regval &= ~(DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC |
|
||||
DMA_SCR_MINC | DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK |
|
||||
DMA_SCR_PINCOS | DMA_SCR_CIRC | DMA_SCR_DBM | DMA_SCR_CT |
|
||||
DMA_SCR_PBURST_MASK | DMA_SCR_MBURST_MASK);
|
||||
scr &= (DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC | DMA_SCR_MINC |
|
||||
DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK | DMA_SCR_PINCOS |
|
||||
DMA_SCR_DBM | DMA_SCR_CIRC |
|
||||
scr &= (DMA_SCR_PFCTRL | DMA_SCR_DIR_MASK | DMA_SCR_PINC |
|
||||
DMA_SCR_MINC | DMA_SCR_PSIZE_MASK | DMA_SCR_MSIZE_MASK |
|
||||
DMA_SCR_PINCOS | DMA_SCR_DBM | DMA_SCR_CIRC |
|
||||
DMA_SCR_PBURST_MASK | DMA_SCR_MBURST_MASK);
|
||||
regval |= scr;
|
||||
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
|
||||
@@ -732,7 +748,8 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool half)
|
||||
void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg,
|
||||
bool half)
|
||||
{
|
||||
struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle;
|
||||
uint32_t scr;
|
||||
@@ -753,27 +770,29 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool
|
||||
scr |= DMA_SCR_EN;
|
||||
|
||||
/* In normal mode, interrupt at either half or full completion. In circular
|
||||
* and double-buffered modes, always interrupt on buffer wrap, and optionally
|
||||
* interrupt at the halfway point.
|
||||
* and double-buffered modes, always interrupt on buffer wrap, and
|
||||
* optionally interrupt at the halfway point.
|
||||
*/
|
||||
|
||||
if ((scr & (DMA_SCR_DBM | DMA_SCR_CIRC)) == 0)
|
||||
{
|
||||
/* Once half of the bytes are transferred, the half-transfer flag (HTIF) is
|
||||
* set and an interrupt is generated if the Half-Transfer Interrupt Enable
|
||||
* bit (HTIE) is set. At the end of the transfer, the Transfer Complete Flag
|
||||
* (TCIF) is set and an interrupt is generated if the Transfer Complete
|
||||
* Interrupt Enable bit (TCIE) is set.
|
||||
/* Once half of the bytes are transferred, the half-transfer flag
|
||||
* (HTIF) is set and an interrupt is generated if the Half-Transfer
|
||||
* Interrupt Enable bit (HTIE) is set. At the end of the transfer,
|
||||
* the Transfer Complete Flag (TCIF) is set and an interrupt is
|
||||
* generated if the Transfer Complete Interrupt Enable bit (TCIE)
|
||||
* is set.
|
||||
*/
|
||||
|
||||
scr |= (half ? (DMA_SCR_HTIE | DMA_SCR_TEIE) : (DMA_SCR_TCIE | DMA_SCR_TEIE));
|
||||
scr |= (half ?
|
||||
(DMA_SCR_HTIE | DMA_SCR_TEIE) : (DMA_SCR_TCIE | DMA_SCR_TEIE));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In non-stop modes, when the transfer completes it immediately resets
|
||||
* and starts again. The transfer-complete interrupt is thus always
|
||||
* enabled, and the half-complete interrupt can be used in circular
|
||||
* mode to determine when the buffer is half-full, or in double-buffered
|
||||
* mode to determine when the buffer is half-full or in double-buffered
|
||||
* mode to determine when one of the two buffers is full.
|
||||
*/
|
||||
|
||||
@@ -858,7 +877,8 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
|
||||
#ifdef CONFIG_STM32F7_DMACAPABLE
|
||||
bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
{
|
||||
uint32_t transfer_size, burst_length;
|
||||
uint32_t transfer_size;
|
||||
uint32_t burst_length;
|
||||
uint32_t mend;
|
||||
|
||||
dmainfo("stm32_dmacapable: 0x%08x/%u 0x%08x\n", maddr, count, ccr);
|
||||
@@ -910,10 +930,11 @@ bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
* ARMV7M_DCACHE_LINESIZE boundaries.
|
||||
*/
|
||||
|
||||
if ((maddr & (ARMV7M_DCACHE_LINESIZE-1)) != 0 ||
|
||||
((mend + 1) & (ARMV7M_DCACHE_LINESIZE-1)) != 0)
|
||||
if ((maddr & (ARMV7M_DCACHE_LINESIZE - 1)) != 0 ||
|
||||
((mend + 1) & (ARMV7M_DCACHE_LINESIZE - 1)) != 0)
|
||||
{
|
||||
dmainfo("stm32_dmacapable: dcache unaligned maddr:0x%08x mend:0x%08x\n",
|
||||
dmainfo("stm32_dmacapable:"
|
||||
" dcache unaligned maddr:0x%08x mend:0x%08x\n",
|
||||
maddr, mend);
|
||||
return false;
|
||||
}
|
||||
@@ -997,7 +1018,9 @@ bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
|
||||
|
||||
/* Everything else is unsupported by DMA */
|
||||
|
||||
dmainfo("stm32_dmacapable: transfer targets unknown/unsupported region\n");
|
||||
dmainfo("stm32_dmacapable: transfer targets unknown/unsupported"
|
||||
" region\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1055,14 +1078,22 @@ void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs,
|
||||
uint32_t dmabase = DMA_BASE(dmast->base);
|
||||
|
||||
dmainfo("DMA Registers: %s\n", msg);
|
||||
dmainfo(" LISR[%08x]: %08x\n", dmabase + STM32_DMA_LISR_OFFSET, regs->lisr);
|
||||
dmainfo(" HISR[%08x]: %08x\n", dmabase + STM32_DMA_HISR_OFFSET, regs->hisr);
|
||||
dmainfo(" SCR[%08x]: %08x\n", dmast->base + STM32_DMA_SCR_OFFSET, regs->scr);
|
||||
dmainfo(" SNDTR[%08x]: %08x\n", dmast->base + STM32_DMA_SNDTR_OFFSET, regs->sndtr);
|
||||
dmainfo(" SPAR[%08x]: %08x\n", dmast->base + STM32_DMA_SPAR_OFFSET, regs->spar);
|
||||
dmainfo(" SM0AR[%08x]: %08x\n", dmast->base + STM32_DMA_SM0AR_OFFSET, regs->sm0ar);
|
||||
dmainfo(" SM1AR[%08x]: %08x\n", dmast->base + STM32_DMA_SM1AR_OFFSET, regs->sm1ar);
|
||||
dmainfo(" SFCR[%08x]: %08x\n", dmast->base + STM32_DMA_SFCR_OFFSET, regs->sfcr);
|
||||
dmainfo(" LISR[%08x]: %08x\n",
|
||||
dmabase + STM32_DMA_LISR_OFFSET, regs->lisr);
|
||||
dmainfo(" HISR[%08x]: %08x\n",
|
||||
dmabase + STM32_DMA_HISR_OFFSET, regs->hisr);
|
||||
dmainfo(" SCR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SCR_OFFSET, regs->scr);
|
||||
dmainfo(" SNDTR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SNDTR_OFFSET, regs->sndtr);
|
||||
dmainfo(" SPAR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SPAR_OFFSET, regs->spar);
|
||||
dmainfo(" SM0AR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SM0AR_OFFSET, regs->sm0ar);
|
||||
dmainfo(" SM1AR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SM1AR_OFFSET, regs->sm1ar);
|
||||
dmainfo(" SFCR[%08x]: %08x\n",
|
||||
dmast->base + STM32_DMA_SFCR_OFFSET, regs->sfcr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ struct pic32mz_dmac_s
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void pic32mz_dma_takesem(struct pic32mz_dmac_s *dmac);
|
||||
static int pic32mz_dma_takesem(struct pic32mz_dmac_s *dmac);
|
||||
static inline void pic32mz_dma_givesem(struct pic32mz_dmac_s *dmac);
|
||||
|
||||
static inline uint32_t pic32mz_dma_getreg(FAR struct pic32mz_dmach_s *dmach,
|
||||
@@ -211,9 +211,9 @@ static struct pic32mz_dmac_s g_dmac =
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pic32mz_dma_takesem(struct pic32mz_dmac_s *dmac)
|
||||
static int pic32mz_dma_takesem(struct pic32mz_dmac_s *dmac)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&dmac->chsem);
|
||||
return nxsem_wait_uninterruptible(&dmac->chsem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -582,7 +582,8 @@ static void pic32mz_dma_mode(FAR struct pic32mz_dmach_s *dmach,
|
||||
|
||||
if (mode & PIC32MZ_DMA_MODE_AUTOEN)
|
||||
{
|
||||
pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_CONSET_OFFSET, DMACH_CON_CHAEN);
|
||||
pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_CONSET_OFFSET,
|
||||
DMACH_CON_CHAEN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,8 +691,9 @@ void pic32mz_dma_sample(DMA_HANDLE handle, struct pic32mz_dmaregs_s *regs)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA
|
||||
void pic32mz_dma_dump(DMA_HANDLE handle, const struct pic32mz_dmaregs_s *regs,
|
||||
const char *msg)
|
||||
void pic32mz_dma_dump(DMA_HANDLE handle,
|
||||
const struct pic32mz_dmaregs_s *regs,
|
||||
const char *msg)
|
||||
{
|
||||
struct pic32mz_dmach_s *dmach = (struct pic32mz_dmach_s *)handle;
|
||||
|
||||
@@ -790,8 +792,8 @@ void weak_function up_dma_initialize(void)
|
||||
* Name: pic32mz_dma_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate a DMA channel. This function sets aside a DMA channel and gives
|
||||
* the caller exclusive access to the DMA channel.
|
||||
* Allocate a DMA channel. This function sets aside a DMA channel and
|
||||
* gives the caller exclusive access to the DMA channel.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, this function returns a non-NULL, void* DMA channel handle.
|
||||
@@ -804,10 +806,16 @@ DMA_HANDLE pic32mz_dma_alloc(const struct pic32mz_dma_chcfg_s *cfg)
|
||||
{
|
||||
struct pic32mz_dmach_s *dmach = NULL;
|
||||
unsigned int chndx;
|
||||
int ret;
|
||||
|
||||
/* Search for an available DMA channel */
|
||||
|
||||
pic32mz_dma_takesem(&g_dmac);
|
||||
ret = pic32mz_dma_takesem(&g_dmac);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chndx = 0; chndx < CHIP_NDMACH; chndx++)
|
||||
{
|
||||
struct pic32mz_dmach_s *candidate = &g_dmac.dmachs[chndx];
|
||||
|
||||
Reference in New Issue
Block a user