From 4c84325d5ee5dc36bfe9758ad0e552d0a88f2d78 Mon Sep 17 00:00:00 2001 From: edolomb Date: Thu, 24 Aug 2017 16:14:05 +0000 Subject: [PATCH] Added XDMAC driver git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10477 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/SAMA/LLD/DMAv1/driver.mk | 2 + os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c | 315 +++++++++++++++++++++++ os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h | 276 ++++++++++++++++++++ 3 files changed, 593 insertions(+) create mode 100644 os/hal/ports/SAMA/LLD/DMAv1/driver.mk create mode 100644 os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c create mode 100644 os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h diff --git a/os/hal/ports/SAMA/LLD/DMAv1/driver.mk b/os/hal/ports/SAMA/LLD/DMAv1/driver.mk new file mode 100644 index 000000000..98442df22 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/DMAv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c +PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1 diff --git a/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c new file mode 100644 index 000000000..6fc51c1f9 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c @@ -0,0 +1,315 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file DMAv1/sama_xdmac.c + * @brief Enhanced DMA helper driver code. + * + * @addtogroup SAMA_DMA + * @details DMA sharing helper driver. In the SAMA the DMA channels are a + * dedicated resource, this driver allows to allocate and free DMA + * channels at runtime. + * @{ + */ + +#include "hal.h" + +/* The following macro is only defined if some driver requiring DMA services + has been enabled.*/ +#if defined(SAMA_DMA_REQUIRED) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ +sama_dma_channel_t _sama_dma_channel_t[XDMAC_CHANNELS_TOT]; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local macros. */ +/*===========================================================================*/ + +/** + * @brief Associates a controller to a DMA channel. + * + * @param[in] index index of the channel + * @return xdmacp pointer to DMA controller + * + * @notapi + */ +#define dmaControllerSelect(index) \ + index < (XDMAC_CONTROLLERS - 1) ? XDMAC0 : XDMAC1 \ + +/** + * @brief Associates ID number to controller. + * + * @param[in] xdmacp pointer to DMA controller + * @return ID_XDMACx peripheral ID of DMA controller + * + * @notapi + */ + #define dmaGetControllerId(xdmacp) \ + (Xdmac *) xdmacp == XDMAC0 ? ID_XDMAC0 : ID_XDMAC1 + +/** + * @brief Get content of Global Status register. + * + * @param[in] xdmacp pointer to DMA controller + * @return XDMAC_GS content of Global Status register + * + * @notapi + */ + #define dmaGetGlobal(xdmacp) xdmacp->XDMAC_GS + +/** + * @brief Get content of Global Interrupt Status register. + * + * @param[in] xdmacp pointer to DMA controller + * @return XDMAC_GIS content of Global Interrupt Status register + * + * @notapi + */ + #define dmaGetGlobalInt(xdmacp) xdmacp->XDMAC_GIS + +/** + * @brief Get content of Channel Interrupt Status register. + * @note Reading interrupt is equivalent to clearing interrupt. + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * @return XDMAC_CISx content of Channel Interrupt Status register + * + * @notapi + */ +#define dmaGetChannelInt(dmachp) \ + (dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CIS + +/** + * @brief Get content of Channel Interrupt Mask register. + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * @return XDMAC_CIMx content of Channel Interrupt Mask register + * + * @notapi + */ +#define dmaGetChannelIntMask(dmachp) \ + (dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CIM + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief XDMAC interrupt handler + */ +OSAL_IRQ_HANDLER(dmaHandler) { + uint32_t cont; + + OSAL_IRQ_PROLOGUE(); + for (cont = 0; cont < XDMAC_CONTROLLERS; cont++) { + uint32_t chan, gis, gcs, cis; + + Xdmac *xdmac = dmaControllerSelect(cont); + + /* Read Global Interrupt Status Register */ + gis = dmaGetGlobalInt(xdmac); + + if ((gis & 0xFFFF) == 0) + /* There is no interrupt pending for this xdmac controller */ + continue; + + /* Read Global Status Register */ + gcs = dmaGetGlobal(xdmac); + for (chan = 0; chan < XDMAC_CHANNELS; chan++) { + sama_dma_channel_t *channel = &_sama_dma_channel_t[(cont * XDMAC_CHANNELS) + chan]; + bool pendingInt = false; + + if (!(gis & (0x1 << chan))) + /* There is no pending interrupt for this channel */ + continue; + + if (channel->state == SAMA_DMA_FREE) + /* Channel is free */ + continue; + + if (!(gcs & (0x1 << chan))) { + cis = dmaGetChannelInt(channel); + + if (cis & XDMAC_CIS_BIS) { + if (!(dmaGetChannelIntMask(channel) & XDMAC_CIM_LIM)) { + pendingInt = true; + } + } + + if (cis & XDMAC_CIS_LIS) { + pendingInt = true; + } + + if (cis & XDMAC_CIS_DIS) { + pendingInt = true;; + } + } + /* Execute callback */ + //if (pendingInt && channel->dma_func) { + channel->dma_func(channel->dma_param,cis); + //} + } + } + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief SAMA DMA helper initialization. + * + * @init + */ +void dmaInit(void) { + + uint8_t cont, chan; + + for (cont = 0; cont < XDMAC_CONTROLLERS; cont++) { + + Xdmac *xdmac = dmaControllerSelect(cont); + + for (chan = 0; chan < XDMAC_CHANNELS; chan++) { + sama_dma_channel_t *channel = &_sama_dma_channel_t[(cont * XDMAC_CHANNELS) + chan]; + + /* Initialization of the specific channel */ + channel->xdmac = xdmac; + channel->chid = chan; + channel->state = SAMA_DMA_FREE; + channel->dma_func = NULL; + + /* Clear interrupts */ + dmaGetChannelInt(channel); + } + + uint32_t id = dmaGetControllerId(xdmac); + /* set aic source handler */ + aicSetSourceHandler(id, dmaHandler); + } +} + +/** + * @brief Assigns a DMA channel. + * @details The channel is assigned and, if required, the DMA clock enabled. + * The function also enables the IRQ vector associated to the channel + * and initializes its priority. + * @pre The channel must not be already in use or an error is returned. + * @post The channel is allocated and the default ISR handler redirected + * to the specified function. + * @post The channel ISR vector is enabled and its priority configured. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] priority IRQ priority mask for the DMA stream + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return A pointer to sama_dma_channel_t structure if channel is + * assigned or NULL. + * + * @special + */ +sama_dma_channel_t* dmaChannelAllocate(uint32_t priority, + sama_dmaisr_t func, + void *param) { + + sama_dma_channel_t *channel = NULL; + uint8_t id; + uint8_t chan; + for (chan = 0; chan < XDMAC_CHANNELS_TOT; chan++) { + channel = &_sama_dma_channel_t[chan]; + if (channel->state != SAMA_DMA_FREE) { + channel = NULL; + } + else { + break; + } + } + + if (channel != NULL) { + /* Marks the channel as allocated.*/ + channel->state = SAMA_DMA_NOT_FREE; + channel->dma_func = func; + channel->dma_param = param; + id = dmaGetControllerId(channel->xdmac); + + /* Setting aic */ + aicSetSourcePriority(id, priority); + aicEnableInt(id); + /* Enabling DMA clocks required by the current channel set.*/ + if (id == ID_XDMAC0) { + pmcEnableXDMAC0(); + } + else { + pmcEnableXDMAC1(); + } + + /* Enable channel interrupt */ + /* Only works for single block transfer */ + channel->xdmac->XDMAC_CHID[channel->chid].XDMAC_CIE = XDMAC_CIE_BIE; + channel->xdmac->XDMAC_GIE = XDMAC_GIE_IE0 << (channel->chid); + } + return channel; +} + +/** + * @brief Releases a DMA channel. + * @details The stream is channel and, if required, the DMA clock disabled. + * Trying to release a unallocated channel is an illegal operation + * and is trapped if assertions are enabled. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post The channel is again available. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * + * @special + */ +void dmaChannelRelease(sama_dma_channel_t *dmachp) { + + osalDbgCheck(dmachp != NULL); + uint8_t id; + /* Check if the channel is free.*/ + osalDbgAssert(dmachp->state != SAMA_DMA_NOT_FREE, + "not allocated"); + id = dmaGetControllerId(dmachp->xdmac); + /* Disables the associated IRQ vector.*/ + aicDisableInt(id); + + /* Disables channel */ + dmaChannelDisable(dmachp); + + /* Marks the stream as not allocated.*/ + (dmachp)->state = SAMA_DMA_FREE; + +} + +#endif /* SAMA_DMA_REQUIRED */ + +/** @} */ diff --git a/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h new file mode 100644 index 000000000..52c3dc2d3 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h @@ -0,0 +1,276 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file DMAv1/sama_xdmac.h + * @brief Enhanced-DMA helper driver header. + * + * @addtogroup SAMA_XDMAC + * @{ + */ + +#ifndef SAMA_XDMAC_H +#define SAMA_XDMAC_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief DMA capability. + * @details if @p TRUE then the DMA is able of burst transfers, FIFOs, + * scatter gather and other advanced features. + */ +#define SAMA_XDMAC_ADVANCED TRUE + +/** + * @brief Total number of DMA controllers. + * @details This is the total number of DMA controllers. + */ +#define XDMAC_CONTROLLERS 2 + +/** + * @brief Number of DMA channels. + * @details This is the number of DMA channel for each controller. + */ +#define XDMAC_CHANNELS (XDMACCHID_NUMBER) + +/** + * @brief Total number of DMA channels. + * @details This is the total number of channels among all the DMA units. + */ +#define XDMAC_CHANNELS_TOT (XDMACCHID_NUMBER * XDMAC_CONTROLLERS) + +/** + * @brief Max single transfer size. + * @details This is the maximum single transfer size supported. + */ +#define XDMAC_MAX_BT_SIZE 0xFFFFFF + +/** + * @brief Max DMA length of the block. + * @details This is the maximum length of the block supported. + */ +#define XDMAC_MAX_BLOCK_LEN 0xFFF + +/** + * @brief States of the channel. + */ +#define SAMA_DMA_FREE 0U +#define SAMA_DMA_NOT_FREE 1U + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ +/** + * @brief SAMA5D2 DMA ISR function type. + * + * @param[in] p parameter for the registered function + * @param[in] flags content of the CIS register. + */ +typedef void (*sama_dmaisr_t)(void *p, uint32_t flags); + +/** + * @brief SAMA5D2 DMA channel descriptor structure. + */ +typedef struct { + Xdmac *xdmac; /**< @brief Associated DMA + controller. */ + uint8_t chid; /**< @brief ID channel */ + uint8_t state; /**< @brief State channel */ + sama_dmaisr_t dma_func; + void *dma_param; +} sama_dma_channel_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ +/** + * @name Macro Functions + * @{ + */ + +/** + * @brief Associates a source to a DMA channel. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * @param[in] addr value to be written in the SA register + * + * @special + */ +#define dmaChannelSetSource(dmachp, addr) { \ + (dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CSA = XDMAC_CSA_SA((uint32_t)addr); \ +} + +/** + * @brief Associates a destination to a DMA channel. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * @param[in] addr value to be written in the DA register + * + * @special + */ +#define dmaChannelSetDestination(dmachp, addr) { \ + (dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CDA = XDMAC_CDA_DA((uint32_t)addr); \ +} + +/** + * @brief Sets the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmastp pointer to a sama_dma_channel_t structure + * @param[in] size value to be written in the XDMAC_CUBC register + * + * @special + */ +#define dmaChannelSetTransactionSize(dmachp, size) { \ + (dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CUBC = XDMAC_CUBC_UBLEN(size); \ +} + +/** + * @brief Sets the channel mode settings. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * @param[in] mode value to be written in the XDMAC_CC register + * + * @special + */ +#define dmaChannelSetMode(dmachp, mode) { \ + (dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CC = mode; \ +} + +/** + * @brief DMA channel enable. + * @note This function can be invoked in both ISR or thread context. + * The hardware disables a channel on transfer completion by clearing + * bit XDMAC_GS.STx. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * + * @special + */ +#define dmaChannelEnable(dmachp) { \ + (dmachp)->xdmac->XDMAC_GE |= (XDMAC_GE_EN0 << ((dmachp)->chid)); \ +} + +/** + * @brief DMA channel disable. + * @details The function disables the specified channel, waits for the disable + * operation to complete and then clears any pending interrupt. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * + * @special + */ +#define dmaChannelDisable(dmachp) { \ + (dmachp)->xdmac->XDMAC_GD |= XDMAC_GD_DI0 << ((dmachp)->chid); \ + dmaGetChannelInt(dmachp); \ +} + +/** + * @brief Starts a memory to memory operation using the specified channel. + * @note The default transfer data mode is "byte to byte" but it can be + * changed by specifying extra options in the @p mode parameter. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + * @param[in] mode value to be written in the CC register, this value + * is implicitly ORed with: + * - @p XDMAC_CC_TYPE_MEM_TRAN + * - @p XDMAC_CC_SAM_INCREMENTED_AM + * - @p XDMAC_CC_DAM_INCREMENTED_AM + * - @p XDMAC_CC_SWREQ_SWR_CONNECTED + * - @p XDMAC_CC_SIF_AHB_IF0 + * - @p XDMAC_CC_DIF_AHB_IF0 + * - @p XDMAC_GE + * . + * @param[in] src source address + * @param[in] dst destination address + * @param[in] n number of data units to copy + */ +#define dmaStartMemCopy(dmachp, mode, src, dst, n) { \ + dmaChannelSetSource(dmachp, src); \ + dmaChannelSetDestination(dmachp, dst); \ + dmaChannelSetTransactionSize(dmachp, n); \ + dmaChannelSetMode(dmachp, (mode) | \ + XDMAC_CC_TYPE_MEM_TRAN | XDMAC_CC_SAM_INCREMENTED_AM | \ + XDMAC_CC_DAM_INCREMENTED_AM | XDMAC_CC_SWREQ_SWR_CONNECTED | \ + XDMAC_CC_SIF_AHB_IF0 | XDMAC_CC_DIF_AHB_IF0); \ + dmaChannelEnable(dmachp); \ +} + +/** + * @brief Polled wait for DMA transfer end. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmachp pointer to a sama_dma_channel_t structure + */ +#define dmaWaitCompletion(dmachp) { \ + (dmachp)->xdmac->XDMAC_GID |= XDMAC_GID_ID0 << ((dmachp)->chid)); \ + while ((dmachp)->xdmac->XDMAC_GS & (XDMAC_GS_ST0 << ((dmachp)->chid)))) \ + ; \ + dmaGetChannelInt(dmachp); \ +} +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern sama_dma_channel_t _sama_dma_channel_t[XDMAC_CHANNELS_TOT]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void dmaInit(void); + sama_dma_channel_t* dmaChannelAllocate(uint32_t priority, + sama_dmaisr_t func, + void *param); + void dmaChannelRelease(sama_dma_channel_t *dmachp); +#ifdef __cplusplus +} +#endif + +#endif /* SAMA_DMA_H */ + +/** @} */