aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--os/hal/ports/SAMA/LLD/DMAv1/driver.mk2
-rw-r--r--os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c315
-rw-r--r--os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h276
3 files changed, 593 insertions, 0 deletions
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 */
+
+/** @} */