summaryrefslogtreecommitdiffstats
path: root/bsps/shared/dev
diff options
context:
space:
mode:
authorChristian Mauderer <christian.mauderer@embedded-brains.de>2020-11-24 17:22:38 +0100
committerChristian Mauderer <christian.mauderer@embedded-brains.de>2021-01-21 10:17:31 +0100
commita434cc80cb00e2f15a51205d6b813fc8c58803ac (patch)
tree529175a1921562532778e3adc7dc7a53ee518788 /bsps/shared/dev
parentbsps/shared: Copy fsl-edma from mpc55xx (diff)
downloadrtems-a434cc80cb00e2f15a51205d6b813fc8c58803ac.tar.bz2
bsps/shared: Adapt fsl-edma driver for imxrt
Note: The changes have been done with portability in mind. The driver should (in theory) be able to replace the original one in the MPC BSPs too. For full compatibility an adaption layer and especially a test would be necessary. Because both are missing, don't integrate it into the MPC BSP now. Update #4180
Diffstat (limited to 'bsps/shared/dev')
-rw-r--r--bsps/shared/dev/dma/fsl-edma.c349
1 files changed, 245 insertions, 104 deletions
diff --git a/bsps/shared/dev/dma/fsl-edma.c b/bsps/shared/dev/dma/fsl-edma.c
index c34624ed10..b3e1bb2fc5 100644
--- a/bsps/shared/dev/dma/fsl-edma.c
+++ b/bsps/shared/dev/dma/fsl-edma.c
@@ -1,33 +1,47 @@
/**
* @file
*
- * @ingroup RTEMSBSPsPowerPCMPC55XX
+ * @ingroup RTEMSBSPsSharedFslEDMA
*
- * @brief Enhanced Direct Memory Access (eDMA).
+ * @brief Freescale / NXP Enhanced Direct Memory Access (eDMA).
*/
/*
- * Copyright (c) 2008-2013 embedded brains GmbH. All rights reserved.
+ * Copyright (C) 2008-2020 embedded brains GmbH (http://www.embedded-brains.de)
*
- * embedded brains GmbH
- * Dornierstr. 4
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
-#include <mpc55xx/edma.h>
-#include <mpc55xx/mpc55xx.h>
+#include <fsl/edma.h>
+#include <fsl/regs-edma.h>
#include <assert.h>
#include <bsp.h>
#include <bsp/fatal.h>
#include <bsp/irq.h>
+#ifdef LIBBSP_ARM_IMXRT_BSP_H
+#include <MIMXRT1052.h>
+#endif
#define EDMA_CHANNELS_PER_GROUP 32U
@@ -43,32 +57,67 @@ static uint32_t edma_channel_occupation [EDMA_GROUP_COUNT];
static RTEMS_CHAIN_DEFINE_EMPTY(edma_channel_chain);
-static unsigned edma_channel_index_of_tcd(volatile struct tcd_t *edma_tcd)
+volatile struct fsl_edma *edma_inst[EDMA_MODULE_COUNT] = {
+#ifdef LIBBSP_ARM_IMXRT_BSP_H
+ (volatile struct fsl_edma *) DMA0,
+#else /* ! LIBBSP_ARM_IMXRT_BSP_H */
+ #if EDMA_MODULE_COUNT == 1
+ (volatile struct fsl_edma *) &EDMA,
+ #elif EDMA_MODULE_COUNT == 2
+ (volatile struct fsl_edma *) &EDMA_A,
+ (volatile struct fsl_edma *) &EDMA_B,
+ #else
+ #error "unsupported module count"
+ #endif
+#endif /* LIBBSP_ARM_IMXRT_BSP_H */
+};
+
+unsigned fsl_edma_channel_index_of_tcd(
+ volatile struct fsl_edma_tcd *edma_tcd
+)
{
- volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd);
+ volatile struct fsl_edma *edma = fsl_edma_by_tcd(edma_tcd);
unsigned channel = edma_tcd - &edma->TCD[0];
-#if EDMA_MODULE_COUNT == 1
- return channel;
-#elif EDMA_MODULE_COUNT == 2
- return channel + (&EDMA_A == edma ? 0 : EDMA_CHANNELS_PER_MODULE);
-#else
+#if EDMA_MODULE_COUNT == 2
+ if (edma_inst[1] == edma) {
+ channel += EDMA_CHANNELS_PER_MODULE;
+ }
+#elif EDMA_MODULE_COUNT > 2
#error "unsupported module count"
#endif
+
+ return channel;
}
-static volatile struct EDMA_tag *edma_get_regs_by_module(unsigned module)
+volatile struct fsl_edma_tcd *fsl_edma_tcd_of_channel_index(unsigned index)
{
-#if EDMA_MODULE_COUNT == 1
- return &EDMA;
-#elif EDMA_MODULE_COUNT == 2
- return module == 0 ? &EDMA_A : &EDMA_B;
-#else
- #error "unsupported module count"
-#endif
+ unsigned module = index / EDMA_CHANNELS_PER_MODULE;
+ unsigned channel = index % EDMA_CHANNELS_PER_MODULE;
+
+ return &edma_inst[module]->TCD[channel];
}
-static uint32_t edma_bit_array_set(unsigned channel, uint32_t *bit_array)
+static volatile struct fsl_edma *fsl_edma_get_regs_by_module(unsigned module)
+{
+ return edma_inst[module];
+}
+
+static uint32_t fsl_edma_bit_array_get_lowest_0(uint32_t *bit_array)
+{
+ unsigned array;
+
+ for (array = 0; array < EDMA_MODULE_COUNT; ++array) {
+ uint32_t first_0 = __builtin_ffs(~(bit_array[array]));
+ if (first_0 > 0) {
+ return (first_0 - 1) + array * 32;
+ }
+ }
+
+ return UINT32_MAX;
+}
+
+static uint32_t fsl_edma_bit_array_set(unsigned channel, uint32_t *bit_array)
{
unsigned array = channel / 32;
uint32_t bit = 1U << (channel % 32);
@@ -79,7 +128,7 @@ static uint32_t edma_bit_array_set(unsigned channel, uint32_t *bit_array)
return previous;
}
-static uint32_t edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
+static uint32_t fsl_edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
{
unsigned array = channel / 32;
uint32_t bit = 1U << (channel % 32);
@@ -90,11 +139,11 @@ static uint32_t edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
return previous;
}
-static void edma_interrupt_handler(void *arg)
+static void fsl_edma_interrupt_handler(void *arg)
{
- edma_channel_context *ctx = arg;
+ fsl_edma_channel_context *ctx = arg;
- mpc55xx_edma_clear_interrupts(ctx->edma_tcd);
+ fsl_edma_clear_interrupts(ctx->edma_tcd);
(*ctx->done)(ctx, 0);
}
@@ -103,39 +152,40 @@ static void edma_interrupt_error_handler(void *arg)
{
rtems_chain_control *chain = &edma_channel_chain;
rtems_chain_node *node = rtems_chain_first(chain);
+
uint32_t error_channels [] = {
#if EDMA_GROUP_COUNT >= 1
- EDMA.ERL.R
+ edma_inst[0]->ERL,
#endif
#if EDMA_GROUP_COUNT >= 2
- , EDMA.ERH.R
+ edma_inst[0]->ERH,
#endif
#if EDMA_GROUP_COUNT >= 3
- , EDMA_B.ERL.R
+ edma_inst[1]->ERL,
#endif
};
uint32_t error_status [] = {
#if EDMA_GROUP_COUNT >= 1
- EDMA.ESR.R
+ edma_inst[0]->ESR,
#endif
#if EDMA_GROUP_COUNT >= 3
- , EDMA_B.ESR.R
+ edma_inst[1]->ESR,
#endif
};
#if EDMA_GROUP_COUNT >= 1
- EDMA.ERL.R = error_channels [0];
+ edma_inst[0]->ERL = error_channels [0];
#endif
#if EDMA_GROUP_COUNT >= 2
- EDMA.ERH.R = error_channels [1];
+ edma_inst[0]->ERH = error_channels [1];
#endif
#if EDMA_GROUP_COUNT >= 3
- EDMA_B.ERL.R = error_channels [2];
+ edma_inst[1]->ERL = error_channels [2];
#endif
while (!rtems_chain_is_tail(chain, node)) {
- edma_channel_context *ctx = (edma_channel_context *) node;
- unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
+ fsl_edma_channel_context *ctx = (fsl_edma_channel_context *) node;
+ unsigned channel_index = fsl_edma_channel_index_of_tcd(ctx->edma_tcd);
unsigned group_index = EDMA_GROUP_INDEX(channel_index);
unsigned group_bit = EDMA_GROUP_BIT(channel_index);
@@ -149,7 +199,7 @@ static void edma_interrupt_error_handler(void *arg)
}
}
-void mpc55xx_edma_init(void)
+void fsl_edma_init(void)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
unsigned channel_remaining = EDMA_CHANNEL_COUNT;
@@ -157,7 +207,7 @@ void mpc55xx_edma_init(void)
unsigned group = 0;
for (module = 0; module < EDMA_MODULE_COUNT; ++module) {
- volatile struct EDMA_tag *edma = edma_get_regs_by_module(module);
+ volatile struct fsl_edma *edma = fsl_edma_get_regs_by_module(module);
unsigned channel_count = channel_remaining < EDMA_CHANNELS_PER_MODULE ?
channel_remaining : EDMA_CHANNELS_PER_MODULE;
unsigned channel = 0;
@@ -165,32 +215,36 @@ void mpc55xx_edma_init(void)
channel_remaining -= channel_count;
/* Disable requests */
- edma->CERQR.B.CERQ = 0x40;
+ edma->CERQR = EDMA_CERQR_CAER;
/* Arbitration mode: group round robin, channel fixed */
- edma->CR.B.ERGA = 1;
- edma->CR.B.ERCA = 0;
+ edma->CR |= EDMA_CR_ERGA;
+ edma->CR &= ~EDMA_CR_ERCA;
+#if defined(BSP_FSL_EDMA_EMLM)
+ edma->CR |= EDMA_CR_EMLM;
+#endif
for (channel = 0; channel < channel_count; ++channel) {
- volatile struct tcd_t *tcd = &edma->TCD [channel];
- edma->CPR [channel].R = 0x80U | (channel & 0xfU);
+ volatile struct fsl_edma_tcd *tcd = &edma->TCD [channel];
+ edma->CPR [channel] = EDMA_CPR_ECP | EDMA_CPR_CHPRI(channel);
/* Initialize TCD, stop channel first */
- tcd->BMF.R = 0;
+ tcd->BMF = 0;
tcd->SADDR = 0;
- tcd->SDF.R = 0;
+ tcd->SDF = 0;
tcd->NBYTES = 0;
tcd->SLAST = 0;
tcd->DADDR = 0;
- tcd->CDF.R = 0;
+ tcd->CDF = 0;
tcd->DLAST_SGA = 0;
}
/* Clear interrupt requests */
- edma->CIRQR.B.CINT = 0x40;
- edma->CER.B.CERR = 0x40;
+ edma->CIRQR = EDMA_CIRQR_CAIR;
+ edma->CER = EDMA_CER_CAEI;
}
for (group = 0; group < EDMA_GROUP_COUNT; ++group) {
+#if defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
sc = mpc55xx_interrupt_handler_install(
MPC55XX_IRQ_EDMA_ERROR(group),
"eDMA Error",
@@ -199,23 +253,61 @@ void mpc55xx_edma_init(void)
edma_interrupt_error_handler,
NULL
);
+#elif defined(LIBBSP_ARM_IMXRT_BSP_H)
+ sc = rtems_interrupt_handler_install(
+ DMA_ERROR_IRQn,
+ "eDMA Error",
+ RTEMS_INTERRUPT_UNIQUE,
+ edma_interrupt_error_handler,
+ NULL
+ );
+#else
+ #error "Unknown chip"
+#endif
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_INSTALL);
}
}
}
-rtems_status_code mpc55xx_edma_obtain_channel_by_tcd(
- volatile struct tcd_t *edma_tcd
+static rtems_status_code fsl_edma_obtain_next_free_channel_and_get_tcd(
+ volatile struct fsl_edma_tcd **edma_tcd
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned channel_index;
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+ channel_index = fsl_edma_bit_array_get_lowest_0(&edma_channel_occupation [0]);
+ if (channel_index > EDMA_CHANNEL_COUNT) {
+ sc = RTEMS_RESOURCE_IN_USE;
+ } else {
+ fsl_edma_bit_array_set(
+ channel_index,
+ &edma_channel_occupation [0]
+ );
+ }
+ rtems_interrupt_enable(level);
+
+ if (sc == RTEMS_SUCCESSFUL) {
+ *edma_tcd = fsl_edma_tcd_of_channel_index(channel_index);
+ }
+
+ return sc;
+}
+
+rtems_status_code fsl_edma_obtain_channel_by_tcd(
+ volatile struct fsl_edma_tcd *edma_tcd
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
- unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
+ unsigned channel_index = fsl_edma_channel_index_of_tcd(edma_tcd);
rtems_interrupt_level level;
uint32_t channel_occupation;
rtems_interrupt_disable(level);
- channel_occupation = edma_bit_array_set(
+ channel_occupation = fsl_edma_bit_array_set(
channel_index,
&edma_channel_occupation [0]
);
@@ -228,59 +320,108 @@ rtems_status_code mpc55xx_edma_obtain_channel_by_tcd(
return sc;
}
-void mpc55xx_edma_release_channel_by_tcd(volatile struct tcd_t *edma_tcd)
+void fsl_edma_release_channel_by_tcd(volatile struct fsl_edma_tcd *edma_tcd)
{
- unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
+ unsigned channel_index = fsl_edma_channel_index_of_tcd(edma_tcd);
rtems_interrupt_level level;
rtems_interrupt_disable(level);
- edma_bit_array_clear(channel_index, &edma_channel_occupation [0]);
+ fsl_edma_bit_array_clear(channel_index, &edma_channel_occupation [0]);
rtems_interrupt_enable(level);
- mpc55xx_edma_disable_hardware_requests(edma_tcd);
- mpc55xx_edma_disable_error_interrupts(edma_tcd);
+ fsl_edma_disable_hardware_requests(edma_tcd);
+ fsl_edma_disable_error_interrupts(edma_tcd);
}
-rtems_status_code mpc55xx_edma_obtain_channel(
- edma_channel_context *ctx,
+static rtems_status_code fsl_edma_install_obtained_channel(
+ fsl_edma_channel_context *ctx,
unsigned irq_priority
)
{
- rtems_status_code sc = mpc55xx_edma_obtain_channel_by_tcd(ctx->edma_tcd);
+ unsigned channel_index = fsl_edma_channel_index_of_tcd(ctx->edma_tcd);
+ rtems_status_code sc;
+
+#if defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
+ sc = fsl_interrupt_handler_install(
+ MPC55XX_IRQ_EDMA(channel_index),
+ "eDMA Channel",
+ RTEMS_INTERRUPT_SHARED,
+ irq_priority,
+ fsl_edma_interrupt_handler,
+ ctx
+ );
+#elif defined(LIBBSP_ARM_IMXRT_BSP_H)
+ sc = rtems_interrupt_handler_install(
+ DMA0_DMA16_IRQn + (channel_index % 16),
+ "eDMA Channel",
+ RTEMS_INTERRUPT_SHARED,
+ fsl_edma_interrupt_handler,
+ ctx
+ );
+#else
+ #error "Unknown chip"
+#endif
if (sc == RTEMS_SUCCESSFUL) {
- unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
+ rtems_chain_prepend(&edma_channel_chain, &ctx->node);
+ fsl_edma_enable_error_interrupts(ctx->edma_tcd);
+ } else {
+ fsl_edma_release_channel_by_tcd(ctx->edma_tcd);
+ sc = RTEMS_IO_ERROR;
+ }
- sc = mpc55xx_interrupt_handler_install(
- MPC55XX_IRQ_EDMA(channel_index),
- "eDMA Channel",
- RTEMS_INTERRUPT_SHARED,
- irq_priority,
- edma_interrupt_handler,
- ctx
+ return sc;
+}
+
+rtems_status_code fsl_edma_obtain_channel(
+ fsl_edma_channel_context *ctx,
+ unsigned irq_priority
+)
+{
+ rtems_status_code sc = fsl_edma_obtain_channel_by_tcd(ctx->edma_tcd);
+ if (sc == RTEMS_SUCCESSFUL) {
+ sc = fsl_edma_install_obtained_channel(ctx, irq_priority);
+ }
+
+ return sc;
+}
+
+rtems_status_code fsl_edma_obtain_next_free_channel(
+ fsl_edma_channel_context *ctx
+)
+{
+ rtems_status_code sc;
+
+ sc = fsl_edma_obtain_next_free_channel_and_get_tcd(&ctx->edma_tcd);
+ if (sc == RTEMS_SUCCESSFUL) {
+ sc = fsl_edma_install_obtained_channel(ctx,
+#ifdef LIBBSP_POWERPC_MPC55XXEVB_BSP_H
+ MPC55XX_INTC_DEFAULT_PRIORITY
+#else
+ 0
+#endif
);
- if (sc == RTEMS_SUCCESSFUL) {
- rtems_chain_prepend(&edma_channel_chain, &ctx->node);
- mpc55xx_edma_enable_error_interrupts(ctx->edma_tcd);
- } else {
- mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
- sc = RTEMS_IO_ERROR;
- }
}
return sc;
}
-void mpc55xx_edma_release_channel(edma_channel_context *ctx)
+void fsl_edma_release_channel(fsl_edma_channel_context *ctx)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
- unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
+ unsigned channel_index = fsl_edma_channel_index_of_tcd(ctx->edma_tcd);
- mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
+ fsl_edma_release_channel_by_tcd(ctx->edma_tcd);
rtems_chain_extract(&ctx->node);
sc = rtems_interrupt_handler_remove(
+#if defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
MPC55XX_IRQ_EDMA(channel_index),
- edma_interrupt_handler,
+#elif defined(LIBBSP_ARM_IMXRT_BSP_H)
+ DMA0_DMA16_IRQn + (channel_index % 16),
+#else
+ #error "Unknown chip"
+#endif
+ fsl_edma_interrupt_handler,
ctx
);
if (sc != RTEMS_SUCCESSFUL) {
@@ -288,42 +429,42 @@ void mpc55xx_edma_release_channel(edma_channel_context *ctx)
}
}
-void mpc55xx_edma_copy(
- volatile struct tcd_t *edma_tcd,
- const struct tcd_t *source_tcd
+void fsl_edma_copy(
+ volatile struct fsl_edma_tcd *edma_tcd,
+ const struct fsl_edma_tcd *source_tcd
)
{
/* Clear DONE flag */
- edma_tcd->BMF.R = 0;
+ edma_tcd->BMF = 0;
edma_tcd->SADDR = source_tcd->SADDR;
- edma_tcd->SDF.R = source_tcd->SDF.R;
+ edma_tcd->SDF = source_tcd->SDF;
edma_tcd->NBYTES = source_tcd->NBYTES;
edma_tcd->SLAST = source_tcd->SLAST;
edma_tcd->DADDR = source_tcd->DADDR;
- edma_tcd->CDF.R = source_tcd->CDF.R;
+ edma_tcd->CDF = source_tcd->CDF;
edma_tcd->DLAST_SGA = source_tcd->DLAST_SGA;
- edma_tcd->BMF.R = source_tcd->BMF.R;
+ edma_tcd->BMF = source_tcd->BMF;
}
-void mpc55xx_edma_copy_and_enable_hardware_requests(
- volatile struct tcd_t *edma_tcd,
- const struct tcd_t *source_tcd
+void fsl_edma_copy_and_enable_hardware_requests(
+ volatile struct fsl_edma_tcd *edma_tcd,
+ const struct fsl_edma_tcd *source_tcd
)
{
- mpc55xx_edma_copy(edma_tcd, source_tcd);
- mpc55xx_edma_enable_hardware_requests(edma_tcd);
+ fsl_edma_copy(edma_tcd, source_tcd);
+ fsl_edma_enable_hardware_requests(edma_tcd);
}
-void mpc55xx_edma_sg_link(
- volatile struct tcd_t *edma_tcd,
- const struct tcd_t *source_tcd
+void fsl_edma_sg_link(
+ volatile struct fsl_edma_tcd *edma_tcd,
+ const struct fsl_edma_tcd *source_tcd
)
{
edma_tcd->DLAST_SGA = (int32_t) source_tcd;
- edma_tcd->BMF.B.E_SG = 1;
+ edma_tcd->BMF |= EDMA_TCD_BMF_E_SG;
- if (!edma_tcd->BMF.B.E_SG) {
- mpc55xx_edma_copy(edma_tcd, source_tcd);
+ if ((edma_tcd->BMF & EDMA_TCD_BMF_E_SG) == 0) {
+ fsl_edma_copy(edma_tcd, source_tcd);
}
}