Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:56

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsPowerPCMPC55XX
0007  *
0008  * @brief Enhanced Direct Memory Access (eDMA).
0009  */
0010 
0011 /*
0012  * Copyright (C) 2008, 2013 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <mpc55xx/edma.h>
0037 #include <mpc55xx/mpc55xx.h>
0038 
0039 #include <assert.h>
0040 
0041 #include <bsp.h>
0042 #include <bsp/fatal.h>
0043 #include <bsp/irq.h>
0044 
0045 #define EDMA_CHANNELS_PER_GROUP 32U
0046 
0047 #define EDMA_GROUP_COUNT ((EDMA_CHANNEL_COUNT + 31U) / 32U)
0048 
0049 #define EDMA_GROUP_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_GROUP)
0050 
0051 #define EDMA_GROUP_BIT(channel) (1U << ((channel) % EDMA_CHANNELS_PER_GROUP))
0052 
0053 #define EDMA_MODULE_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_MODULE)
0054 
0055 static uint32_t edma_channel_occupation [EDMA_GROUP_COUNT];
0056 
0057 static RTEMS_CHAIN_DEFINE_EMPTY(edma_channel_chain);
0058 
0059 static unsigned edma_channel_index_of_tcd(volatile struct tcd_t *edma_tcd)
0060 {
0061   volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd);
0062   unsigned channel = edma_tcd - &edma->TCD[0];
0063 
0064 #if EDMA_MODULE_COUNT == 1
0065   return channel;
0066 #elif EDMA_MODULE_COUNT == 2
0067   return channel + (&EDMA_A == edma ? 0 : EDMA_CHANNELS_PER_MODULE);
0068 #else
0069   #error "unsupported module count"
0070 #endif
0071 }
0072 
0073 static volatile struct EDMA_tag *edma_get_regs_by_module(unsigned module)
0074 {
0075 #if EDMA_MODULE_COUNT == 1
0076   return &EDMA;
0077 #elif EDMA_MODULE_COUNT == 2
0078   return module == 0 ? &EDMA_A : &EDMA_B;
0079 #else
0080   #error "unsupported module count"
0081 #endif
0082 }
0083 
0084 static uint32_t edma_bit_array_set(unsigned channel, uint32_t *bit_array)
0085 {
0086   unsigned array = channel / 32;
0087   uint32_t bit = 1U << (channel % 32);
0088   uint32_t previous = bit_array [array];
0089 
0090   bit_array [array] = previous | bit;
0091 
0092   return previous;
0093 }
0094 
0095 static uint32_t edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
0096 {
0097   unsigned array = channel / 32;
0098   uint32_t bit = 1U << (channel % 32);
0099   uint32_t previous = bit_array [array];
0100 
0101   bit_array [array] = previous & ~bit;
0102 
0103   return previous;
0104 }
0105 
0106 static void edma_interrupt_handler(void *arg)
0107 {
0108   edma_channel_context *ctx = arg;
0109 
0110   mpc55xx_edma_clear_interrupts(ctx->edma_tcd);
0111 
0112   (*ctx->done)(ctx, 0);
0113 }
0114 
0115 static void edma_interrupt_error_handler(void *arg)
0116 {
0117   rtems_chain_control *chain = &edma_channel_chain;
0118   rtems_chain_node *node = rtems_chain_first(chain);
0119   uint32_t error_channels [] = {
0120 #if EDMA_GROUP_COUNT >= 1
0121     EDMA.ERL.R
0122 #endif
0123 #if EDMA_GROUP_COUNT >= 2
0124     , EDMA.ERH.R
0125 #endif
0126 #if EDMA_GROUP_COUNT >= 3
0127     , EDMA_B.ERL.R
0128 #endif
0129   };
0130   uint32_t error_status [] = {
0131 #if EDMA_GROUP_COUNT >= 1
0132     EDMA.ESR.R
0133 #endif
0134 #if EDMA_GROUP_COUNT >= 3
0135     , EDMA_B.ESR.R
0136 #endif
0137   };
0138 
0139 #if EDMA_GROUP_COUNT >= 1
0140   EDMA.ERL.R = error_channels [0];
0141 #endif
0142 #if EDMA_GROUP_COUNT >= 2
0143   EDMA.ERH.R = error_channels [1];
0144 #endif
0145 #if EDMA_GROUP_COUNT >= 3
0146   EDMA_B.ERL.R = error_channels [2];
0147 #endif
0148 
0149   while (!rtems_chain_is_tail(chain, node)) {
0150     edma_channel_context *ctx = (edma_channel_context *) node;
0151     unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
0152     unsigned group_index = EDMA_GROUP_INDEX(channel_index);
0153     unsigned group_bit = EDMA_GROUP_BIT(channel_index);
0154 
0155     if ((error_channels [group_index] & group_bit) != 0) {
0156       unsigned module_index = EDMA_MODULE_INDEX(channel_index);
0157 
0158       (*ctx->done)(ctx, error_status [module_index]);
0159     }
0160 
0161     node = rtems_chain_next(node);
0162   }
0163 }
0164 
0165 void mpc55xx_edma_init(void)
0166 {
0167   rtems_status_code sc = RTEMS_SUCCESSFUL;
0168   unsigned channel_remaining = EDMA_CHANNEL_COUNT;
0169   unsigned module = 0;
0170   unsigned group = 0;
0171 
0172   for (module = 0; module < EDMA_MODULE_COUNT; ++module) {
0173     volatile struct EDMA_tag *edma = edma_get_regs_by_module(module);
0174     unsigned channel_count = channel_remaining < EDMA_CHANNELS_PER_MODULE ?
0175       channel_remaining : EDMA_CHANNELS_PER_MODULE;
0176     unsigned channel = 0;
0177 
0178     channel_remaining -= channel_count;
0179 
0180     /* Disable requests */
0181     edma->CERQR.B.CERQ = 0x40;
0182 
0183     /* Arbitration mode: group round robin, channel fixed */
0184     edma->CR.B.ERGA = 1;
0185     edma->CR.B.ERCA = 0;
0186     for (channel = 0; channel < channel_count; ++channel) {
0187       volatile struct tcd_t *tcd = &edma->TCD [channel];
0188       edma->CPR [channel].R = 0x80U | (channel & 0xfU);
0189 
0190       /* Initialize TCD, stop channel first */
0191       tcd->BMF.R = 0;
0192       tcd->SADDR = 0;
0193       tcd->SDF.R = 0;
0194       tcd->NBYTES = 0;
0195       tcd->SLAST = 0;
0196       tcd->DADDR = 0;
0197       tcd->CDF.R = 0;
0198       tcd->DLAST_SGA = 0;
0199     }
0200 
0201     /* Clear interrupt requests */
0202     edma->CIRQR.B.CINT = 0x40;
0203     edma->CER.B.CERR = 0x40;
0204   }
0205 
0206   for (group = 0; group < EDMA_GROUP_COUNT; ++group) {
0207     sc = mpc55xx_interrupt_handler_install(
0208       MPC55XX_IRQ_EDMA_ERROR(group),
0209       "eDMA Error",
0210       RTEMS_INTERRUPT_UNIQUE,
0211       MPC55XX_INTC_DEFAULT_PRIORITY,
0212       edma_interrupt_error_handler,
0213       NULL
0214     );
0215     if (sc != RTEMS_SUCCESSFUL) {
0216       bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_INSTALL);
0217     }
0218   }
0219 }
0220 
0221 rtems_status_code mpc55xx_edma_obtain_channel_by_tcd(
0222   volatile struct tcd_t *edma_tcd
0223 )
0224 {
0225   rtems_status_code sc = RTEMS_SUCCESSFUL;
0226   unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
0227   rtems_interrupt_level level;
0228   uint32_t channel_occupation;
0229 
0230   rtems_interrupt_disable(level);
0231   channel_occupation = edma_bit_array_set(
0232     channel_index,
0233     &edma_channel_occupation [0]
0234   );
0235   rtems_interrupt_enable(level);
0236 
0237   if ((channel_occupation & EDMA_GROUP_BIT(channel_index)) != 0) {
0238     sc = RTEMS_RESOURCE_IN_USE;
0239   }
0240 
0241   return sc;
0242 }
0243 
0244 void mpc55xx_edma_release_channel_by_tcd(volatile struct tcd_t *edma_tcd)
0245 {
0246   unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
0247   rtems_interrupt_level level;
0248 
0249   rtems_interrupt_disable(level);
0250   edma_bit_array_clear(channel_index, &edma_channel_occupation [0]);
0251   rtems_interrupt_enable(level);
0252 
0253   mpc55xx_edma_disable_hardware_requests(edma_tcd);
0254   mpc55xx_edma_disable_error_interrupts(edma_tcd);
0255 }
0256 
0257 rtems_status_code mpc55xx_edma_obtain_channel(
0258   edma_channel_context *ctx,
0259   unsigned irq_priority
0260 )
0261 {
0262   rtems_status_code sc = mpc55xx_edma_obtain_channel_by_tcd(ctx->edma_tcd);
0263   if (sc == RTEMS_SUCCESSFUL) {
0264     unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
0265 
0266     sc = mpc55xx_interrupt_handler_install(
0267       MPC55XX_IRQ_EDMA(channel_index),
0268       "eDMA Channel",
0269       RTEMS_INTERRUPT_SHARED,
0270       irq_priority,
0271       edma_interrupt_handler,
0272       ctx
0273     );
0274     if (sc == RTEMS_SUCCESSFUL) {
0275       rtems_chain_prepend(&edma_channel_chain, &ctx->node);
0276       mpc55xx_edma_enable_error_interrupts(ctx->edma_tcd);
0277     } else {
0278       mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
0279       sc = RTEMS_IO_ERROR;
0280     }
0281   }
0282 
0283   return sc;
0284 }
0285 
0286 void mpc55xx_edma_release_channel(edma_channel_context *ctx)
0287 {
0288   rtems_status_code sc = RTEMS_SUCCESSFUL;
0289   unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
0290 
0291   mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
0292   rtems_chain_extract(&ctx->node);
0293 
0294   sc = rtems_interrupt_handler_remove(
0295     MPC55XX_IRQ_EDMA(channel_index),
0296     edma_interrupt_handler,
0297     ctx
0298   );
0299   if (sc != RTEMS_SUCCESSFUL) {
0300     bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_REMOVE);
0301   }
0302 }
0303 
0304 void mpc55xx_edma_copy(
0305   volatile struct tcd_t *edma_tcd,
0306   const struct tcd_t *source_tcd
0307 )
0308 {
0309   /* Clear DONE flag */
0310   edma_tcd->BMF.R = 0;
0311 
0312   edma_tcd->SADDR = source_tcd->SADDR;
0313   edma_tcd->SDF.R = source_tcd->SDF.R;
0314   edma_tcd->NBYTES = source_tcd->NBYTES;
0315   edma_tcd->SLAST = source_tcd->SLAST;
0316   edma_tcd->DADDR = source_tcd->DADDR;
0317   edma_tcd->CDF.R = source_tcd->CDF.R;
0318   edma_tcd->DLAST_SGA = source_tcd->DLAST_SGA;
0319   edma_tcd->BMF.R = source_tcd->BMF.R;
0320 }
0321 
0322 void mpc55xx_edma_copy_and_enable_hardware_requests(
0323   volatile struct tcd_t *edma_tcd,
0324   const struct tcd_t *source_tcd
0325 )
0326 {
0327   mpc55xx_edma_copy(edma_tcd, source_tcd);
0328   mpc55xx_edma_enable_hardware_requests(edma_tcd);
0329 }
0330 
0331 void mpc55xx_edma_sg_link(
0332   volatile struct tcd_t *edma_tcd,
0333   const struct tcd_t *source_tcd
0334 )
0335 {
0336   edma_tcd->DLAST_SGA = (int32_t) source_tcd;
0337   edma_tcd->BMF.B.E_SG = 1;
0338 
0339   if (!edma_tcd->BMF.B.E_SG) {
0340     mpc55xx_edma_copy(edma_tcd, source_tcd);
0341   }
0342 }