diff --git a/arch/arm/src/efm32/efm32_dma.c b/arch/arm/src/efm32/efm32_dma.c index 64db22d0a63..a6d62bd0a0c 100644 --- a/arch/arm/src/efm32/efm32_dma.c +++ b/arch/arm/src/efm32/efm32_dma.c @@ -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); diff --git a/arch/arm/src/imxrt/imxrt_edma.c b/arch/arm/src/imxrt/imxrt_edma.c index d4e2ec67755..2b59999838e 100644 --- a/arch/arm/src/imxrt/imxrt_edma.c +++ b/arch/arm/src/imxrt/imxrt_edma.c @@ -4,8 +4,8 @@ * Copyright (C) 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * - * 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() diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_gpdma.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_gpdma.c index 15c69b0267f..77cfef37751 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_gpdma.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_gpdma.c @@ -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; diff --git a/arch/arm/src/lpc43xx/lpc43_gpdma.c b/arch/arm/src/lpc43xx/lpc43_gpdma.c index 784dca3bdf0..5ef6d006d25 100644 --- a/arch/arm/src/lpc43xx/lpc43_gpdma.c +++ b/arch/arm/src/lpc43xx/lpc43_gpdma.c @@ -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; diff --git a/arch/arm/src/sam34/sam_dmac.c b/arch/arm/src/sam34/sam_dmac.c index 50ea4053933..cee2d4aa801 100644 --- a/arch/arm/src/sam34/sam_dmac.c +++ b/arch/arm/src/sam34/sam_dmac.c @@ -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 */ diff --git a/arch/arm/src/sama5/sam_dmac.c b/arch/arm/src/sama5/sam_dmac.c index 23d84189719..59b3b6dcaf0 100644 --- a/arch/arm/src/sama5/sam_dmac.c +++ b/arch/arm/src/sama5/sam_dmac.c @@ -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 */ diff --git a/arch/arm/src/samd2l2/sam_dmac.c b/arch/arm/src/samd2l2/sam_dmac.c index 5ee49f98b85..67fe988c81f 100644 --- a/arch/arm/src/samd2l2/sam_dmac.c +++ b/arch/arm/src/samd2l2/sam_dmac.c @@ -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); diff --git a/arch/arm/src/samd5e5/sam_dmac.c b/arch/arm/src/samd5e5/sam_dmac.c index cdbf6fe586a..d02cc6ac0cc 100644 --- a/arch/arm/src/samd5e5/sam_dmac.c +++ b/arch/arm/src/samd5e5/sam_dmac.c @@ -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); diff --git a/arch/arm/src/samv7/sam_xdmac.c b/arch/arm/src/samv7/sam_xdmac.c index 65537cb103d..d1082df46e4 100644 --- a/arch/arm/src/samv7/sam_xdmac.c +++ b/arch/arm/src/samv7/sam_xdmac.c @@ -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 */ diff --git a/arch/arm/src/stm32/stm32_dma_v1.c b/arch/arm/src/stm32/stm32_dma_v1.c index d6f4a0b333c..25fa5fcd7ba 100644 --- a/arch/arm/src/stm32/stm32_dma_v1.c +++ b/arch/arm/src/stm32/stm32_dma_v1.c @@ -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 * * 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 */ diff --git a/arch/arm/src/stm32/stm32_dma_v2.c b/arch/arm/src/stm32/stm32_dma_v2.c index 903faaca6b2..14c82d31584 100644 --- a/arch/arm/src/stm32/stm32_dma_v2.c +++ b/arch/arm/src/stm32/stm32_dma_v2.c @@ -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 diff --git a/arch/arm/src/stm32f0l0g0/stm32_dma_v1.c b/arch/arm/src/stm32f0l0g0/stm32_dma_v1.c index 0beac4f1ef1..e48fc2b342c 100644 --- a/arch/arm/src/stm32f0l0g0/stm32_dma_v1.c +++ b/arch/arm/src/stm32f0l0g0/stm32_dma_v1.c @@ -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; diff --git a/arch/arm/src/stm32f7/stm32_dma.c b/arch/arm/src/stm32f7/stm32_dma.c index 46a7d5ed446..63b1994a37c 100644 --- a/arch/arm/src/stm32f7/stm32_dma.c +++ b/arch/arm/src/stm32f7/stm32_dma.c @@ -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 diff --git a/arch/mips/src/pic32mz/pic32mz-dma.c b/arch/mips/src/pic32mz/pic32mz-dma.c index be4da4c8e49..f97e86ed369 100644 --- a/arch/mips/src/pic32mz/pic32mz-dma.c +++ b/arch/mips/src/pic32mz/pic32mz-dma.c @@ -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];