File indexing completed on 2025-05-11 08:23:56
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
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
0181 edma->CERQR.B.CERQ = 0x40;
0182
0183
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
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
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
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 }