File indexing completed on 2025-05-11 08:24:04
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 #include <fsl/edma.h>
0035 #include <fsl/regs-edma.h>
0036
0037 #include <assert.h>
0038
0039 #include <bsp.h>
0040 #include <bsp/fatal.h>
0041 #include <bsp/irq.h>
0042 #ifdef LIBBSP_ARM_IMXRT_BSP_H
0043 #include <fsl_device_registers.h>
0044 #endif
0045
0046 #define EDMA_CHANNELS_PER_GROUP 32U
0047
0048 #define EDMA_GROUP_COUNT ((EDMA_CHANNEL_COUNT + 31U) / 32U)
0049
0050 #define EDMA_GROUP_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_GROUP)
0051
0052 #define EDMA_GROUP_BIT(channel) (1U << ((channel) % EDMA_CHANNELS_PER_GROUP))
0053
0054 #define EDMA_MODULE_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_MODULE)
0055
0056 static uint32_t edma_channel_occupation [EDMA_GROUP_COUNT];
0057
0058 static RTEMS_CHAIN_DEFINE_EMPTY(edma_channel_chain);
0059
0060 volatile struct fsl_edma *edma_inst[EDMA_MODULE_COUNT] = {
0061 #ifdef LIBBSP_ARM_IMXRT_BSP_H
0062 (volatile struct fsl_edma *) DMA0,
0063 #else
0064 #if EDMA_MODULE_COUNT == 1
0065 (volatile struct fsl_edma *) &EDMA,
0066 #elif EDMA_MODULE_COUNT == 2
0067 (volatile struct fsl_edma *) &EDMA_A,
0068 (volatile struct fsl_edma *) &EDMA_B,
0069 #else
0070 #error "unsupported module count"
0071 #endif
0072 #endif
0073 };
0074
0075 unsigned fsl_edma_channel_index_of_tcd(
0076 volatile struct fsl_edma_tcd *edma_tcd
0077 )
0078 {
0079 volatile struct fsl_edma *edma = fsl_edma_by_tcd(edma_tcd);
0080 unsigned channel = edma_tcd - &edma->TCD[0];
0081
0082 #if EDMA_MODULE_COUNT == 2
0083 if (edma_inst[1] == edma) {
0084 channel += EDMA_CHANNELS_PER_MODULE;
0085 }
0086 #elif EDMA_MODULE_COUNT > 2
0087 #error "unsupported module count"
0088 #endif
0089
0090 return channel;
0091 }
0092
0093 volatile struct fsl_edma_tcd *fsl_edma_tcd_of_channel_index(unsigned index)
0094 {
0095 unsigned module = index / EDMA_CHANNELS_PER_MODULE;
0096 unsigned channel = index % EDMA_CHANNELS_PER_MODULE;
0097
0098 return &edma_inst[module]->TCD[channel];
0099 }
0100
0101 static volatile struct fsl_edma *fsl_edma_get_regs_by_module(unsigned module)
0102 {
0103 return edma_inst[module];
0104 }
0105
0106 static uint32_t fsl_edma_bit_array_get_lowest_0(uint32_t *bit_array)
0107 {
0108 unsigned array;
0109
0110 for (array = 0; array < EDMA_MODULE_COUNT; ++array) {
0111 uint32_t first_0 = __builtin_ffs(~(bit_array[array]));
0112 if (first_0 > 0) {
0113 return (first_0 - 1) + array * 32;
0114 }
0115 }
0116
0117 return UINT32_MAX;
0118 }
0119
0120 static uint32_t fsl_edma_bit_array_set(unsigned channel, uint32_t *bit_array)
0121 {
0122 unsigned array = channel / 32;
0123 uint32_t bit = 1U << (channel % 32);
0124 uint32_t previous = bit_array [array];
0125
0126 bit_array [array] = previous | bit;
0127
0128 return previous;
0129 }
0130
0131 static uint32_t fsl_edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
0132 {
0133 unsigned array = channel / 32;
0134 uint32_t bit = 1U << (channel % 32);
0135 uint32_t previous = bit_array [array];
0136
0137 bit_array [array] = previous & ~bit;
0138
0139 return previous;
0140 }
0141
0142 static void fsl_edma_interrupt_handler(void *arg)
0143 {
0144 fsl_edma_channel_context *ctx = arg;
0145
0146 fsl_edma_clear_interrupts(ctx->edma_tcd);
0147
0148 (*ctx->done)(ctx, 0);
0149 }
0150
0151 static void edma_interrupt_error_handler(void *arg)
0152 {
0153 rtems_chain_control *chain = &edma_channel_chain;
0154 rtems_chain_node *node = rtems_chain_first(chain);
0155
0156 uint32_t error_channels [] = {
0157 #if EDMA_GROUP_COUNT >= 1
0158 edma_inst[0]->ERL,
0159 #endif
0160 #if EDMA_GROUP_COUNT >= 2
0161 edma_inst[0]->ERH,
0162 #endif
0163 #if EDMA_GROUP_COUNT >= 3
0164 edma_inst[1]->ERL,
0165 #endif
0166 };
0167 uint32_t error_status [] = {
0168 #if EDMA_GROUP_COUNT >= 1
0169 edma_inst[0]->ESR,
0170 #endif
0171 #if EDMA_GROUP_COUNT >= 3
0172 edma_inst[1]->ESR,
0173 #endif
0174 };
0175
0176 #if EDMA_GROUP_COUNT >= 1
0177 edma_inst[0]->ERL = error_channels [0];
0178 #endif
0179 #if EDMA_GROUP_COUNT >= 2
0180 edma_inst[0]->ERH = error_channels [1];
0181 #endif
0182 #if EDMA_GROUP_COUNT >= 3
0183 edma_inst[1]->ERL = error_channels [2];
0184 #endif
0185
0186 while (!rtems_chain_is_tail(chain, node)) {
0187 fsl_edma_channel_context *ctx = (fsl_edma_channel_context *) node;
0188 unsigned channel_index = fsl_edma_channel_index_of_tcd(ctx->edma_tcd);
0189 unsigned group_index = EDMA_GROUP_INDEX(channel_index);
0190 unsigned group_bit = EDMA_GROUP_BIT(channel_index);
0191
0192 if ((error_channels [group_index] & group_bit) != 0) {
0193 unsigned module_index = EDMA_MODULE_INDEX(channel_index);
0194
0195 (*ctx->done)(ctx, error_status [module_index]);
0196 }
0197
0198 node = rtems_chain_next(node);
0199 }
0200 }
0201
0202 void fsl_edma_init(void)
0203 {
0204 rtems_status_code sc = RTEMS_SUCCESSFUL;
0205 unsigned channel_remaining = EDMA_CHANNEL_COUNT;
0206 unsigned module = 0;
0207 unsigned group = 0;
0208
0209 for (module = 0; module < EDMA_MODULE_COUNT; ++module) {
0210 volatile struct fsl_edma *edma = fsl_edma_get_regs_by_module(module);
0211 unsigned channel_count = channel_remaining < EDMA_CHANNELS_PER_MODULE ?
0212 channel_remaining : EDMA_CHANNELS_PER_MODULE;
0213 unsigned channel = 0;
0214
0215 channel_remaining -= channel_count;
0216
0217
0218 edma->CERQR = EDMA_CERQR_CAER;
0219
0220
0221 edma->CR |= EDMA_CR_ERGA;
0222 edma->CR &= ~EDMA_CR_ERCA;
0223 #if defined(BSP_FSL_EDMA_EMLM)
0224 edma->CR |= EDMA_CR_EMLM;
0225 #endif
0226 for (channel = 0; channel < channel_count; ++channel) {
0227 volatile struct fsl_edma_tcd *tcd = &edma->TCD [channel];
0228 edma->CPR [channel] = EDMA_CPR_ECP | EDMA_CPR_CHPRI(channel);
0229
0230
0231 tcd->BMF = 0;
0232 tcd->SADDR = 0;
0233 tcd->SDF = 0;
0234 tcd->NBYTES = 0;
0235 tcd->SLAST = 0;
0236 tcd->DADDR = 0;
0237 tcd->CDF = 0;
0238 tcd->DLAST_SGA = 0;
0239 }
0240
0241
0242 edma->CIRQR = EDMA_CIRQR_CAIR;
0243 edma->CER = EDMA_CER_CAEI;
0244 }
0245
0246 for (group = 0; group < EDMA_GROUP_COUNT; ++group) {
0247 #if defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
0248 sc = mpc55xx_interrupt_handler_install(
0249 MPC55XX_IRQ_EDMA_ERROR(group),
0250 "eDMA Error",
0251 RTEMS_INTERRUPT_UNIQUE,
0252 MPC55XX_INTC_DEFAULT_PRIORITY,
0253 edma_interrupt_error_handler,
0254 NULL
0255 );
0256 #elif defined(LIBBSP_ARM_IMXRT_BSP_H)
0257 sc = rtems_interrupt_handler_install(
0258 DMA_ERROR_IRQn,
0259 "eDMA Error",
0260 RTEMS_INTERRUPT_UNIQUE,
0261 edma_interrupt_error_handler,
0262 NULL
0263 );
0264 #else
0265 #error "Unknown chip"
0266 #endif
0267 if (sc != RTEMS_SUCCESSFUL) {
0268 bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_INSTALL);
0269 }
0270 }
0271 }
0272
0273 static rtems_status_code fsl_edma_obtain_next_free_channel_and_get_tcd(
0274 volatile struct fsl_edma_tcd **edma_tcd
0275 )
0276 {
0277 rtems_status_code sc = RTEMS_SUCCESSFUL;
0278 unsigned channel_index;
0279 rtems_interrupt_level level;
0280
0281 rtems_interrupt_disable(level);
0282 channel_index = fsl_edma_bit_array_get_lowest_0(&edma_channel_occupation [0]);
0283 if (channel_index > EDMA_CHANNEL_COUNT) {
0284 sc = RTEMS_RESOURCE_IN_USE;
0285 } else {
0286 fsl_edma_bit_array_set(
0287 channel_index,
0288 &edma_channel_occupation [0]
0289 );
0290 }
0291 rtems_interrupt_enable(level);
0292
0293 if (sc == RTEMS_SUCCESSFUL) {
0294 *edma_tcd = fsl_edma_tcd_of_channel_index(channel_index);
0295 }
0296
0297 return sc;
0298 }
0299
0300 rtems_status_code fsl_edma_obtain_channel_by_tcd(
0301 volatile struct fsl_edma_tcd *edma_tcd
0302 )
0303 {
0304 rtems_status_code sc = RTEMS_SUCCESSFUL;
0305 unsigned channel_index = fsl_edma_channel_index_of_tcd(edma_tcd);
0306 rtems_interrupt_level level;
0307 uint32_t channel_occupation;
0308
0309 rtems_interrupt_disable(level);
0310 channel_occupation = fsl_edma_bit_array_set(
0311 channel_index,
0312 &edma_channel_occupation [0]
0313 );
0314 rtems_interrupt_enable(level);
0315
0316 if ((channel_occupation & EDMA_GROUP_BIT(channel_index)) != 0) {
0317 sc = RTEMS_RESOURCE_IN_USE;
0318 }
0319
0320 return sc;
0321 }
0322
0323 void fsl_edma_release_channel_by_tcd(volatile struct fsl_edma_tcd *edma_tcd)
0324 {
0325 unsigned channel_index = fsl_edma_channel_index_of_tcd(edma_tcd);
0326 rtems_interrupt_level level;
0327
0328 rtems_interrupt_disable(level);
0329 fsl_edma_bit_array_clear(channel_index, &edma_channel_occupation [0]);
0330 rtems_interrupt_enable(level);
0331
0332 fsl_edma_disable_hardware_requests(edma_tcd);
0333 fsl_edma_disable_error_interrupts(edma_tcd);
0334 }
0335
0336 static rtems_status_code fsl_edma_install_obtained_channel(
0337 fsl_edma_channel_context *ctx,
0338 unsigned irq_priority
0339 )
0340 {
0341 unsigned channel_index = fsl_edma_channel_index_of_tcd(ctx->edma_tcd);
0342 rtems_status_code sc;
0343
0344 #if defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
0345 sc = fsl_interrupt_handler_install(
0346 MPC55XX_IRQ_EDMA(channel_index),
0347 "eDMA Channel",
0348 RTEMS_INTERRUPT_SHARED,
0349 irq_priority,
0350 fsl_edma_interrupt_handler,
0351 ctx
0352 );
0353 #elif defined(LIBBSP_ARM_IMXRT_BSP_H)
0354 sc = rtems_interrupt_handler_install(
0355 DMA0_DMA16_IRQn + (channel_index % 16),
0356 "eDMA Channel",
0357 RTEMS_INTERRUPT_SHARED,
0358 fsl_edma_interrupt_handler,
0359 ctx
0360 );
0361 #else
0362 #error "Unknown chip"
0363 #endif
0364 if (sc == RTEMS_SUCCESSFUL) {
0365 rtems_chain_prepend(&edma_channel_chain, &ctx->node);
0366 fsl_edma_enable_error_interrupts(ctx->edma_tcd);
0367 } else {
0368 fsl_edma_release_channel_by_tcd(ctx->edma_tcd);
0369 sc = RTEMS_IO_ERROR;
0370 }
0371
0372 return sc;
0373 }
0374
0375 rtems_status_code fsl_edma_obtain_channel(
0376 fsl_edma_channel_context *ctx,
0377 unsigned irq_priority
0378 )
0379 {
0380 rtems_status_code sc = fsl_edma_obtain_channel_by_tcd(ctx->edma_tcd);
0381 if (sc == RTEMS_SUCCESSFUL) {
0382 sc = fsl_edma_install_obtained_channel(ctx, irq_priority);
0383 }
0384
0385 return sc;
0386 }
0387
0388 rtems_status_code fsl_edma_obtain_next_free_channel(
0389 fsl_edma_channel_context *ctx
0390 )
0391 {
0392 rtems_status_code sc;
0393
0394 sc = fsl_edma_obtain_next_free_channel_and_get_tcd(&ctx->edma_tcd);
0395 if (sc == RTEMS_SUCCESSFUL) {
0396 sc = fsl_edma_install_obtained_channel(ctx,
0397 #ifdef LIBBSP_POWERPC_MPC55XXEVB_BSP_H
0398 MPC55XX_INTC_DEFAULT_PRIORITY
0399 #else
0400 0
0401 #endif
0402 );
0403 }
0404
0405 return sc;
0406 }
0407
0408 void fsl_edma_release_channel(fsl_edma_channel_context *ctx)
0409 {
0410 rtems_status_code sc = RTEMS_SUCCESSFUL;
0411 unsigned channel_index = fsl_edma_channel_index_of_tcd(ctx->edma_tcd);
0412
0413 fsl_edma_release_channel_by_tcd(ctx->edma_tcd);
0414 rtems_chain_extract(&ctx->node);
0415
0416 sc = rtems_interrupt_handler_remove(
0417 #if defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
0418 MPC55XX_IRQ_EDMA(channel_index),
0419 #elif defined(LIBBSP_ARM_IMXRT_BSP_H)
0420 DMA0_DMA16_IRQn + (channel_index % 16),
0421 #else
0422 #error "Unknown chip"
0423 #endif
0424 fsl_edma_interrupt_handler,
0425 ctx
0426 );
0427 if (sc != RTEMS_SUCCESSFUL) {
0428 bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_REMOVE);
0429 }
0430 }
0431
0432 void fsl_edma_copy(
0433 volatile struct fsl_edma_tcd *edma_tcd,
0434 const struct fsl_edma_tcd *source_tcd
0435 )
0436 {
0437
0438 edma_tcd->BMF = 0;
0439
0440 edma_tcd->SADDR = source_tcd->SADDR;
0441 edma_tcd->SDF = source_tcd->SDF;
0442 edma_tcd->NBYTES = source_tcd->NBYTES;
0443 edma_tcd->SLAST = source_tcd->SLAST;
0444 edma_tcd->DADDR = source_tcd->DADDR;
0445 edma_tcd->CDF = source_tcd->CDF;
0446 edma_tcd->DLAST_SGA = source_tcd->DLAST_SGA;
0447 edma_tcd->BMF = source_tcd->BMF;
0448 }
0449
0450 void fsl_edma_copy_and_enable_hardware_requests(
0451 volatile struct fsl_edma_tcd *edma_tcd,
0452 const struct fsl_edma_tcd *source_tcd
0453 )
0454 {
0455 fsl_edma_copy(edma_tcd, source_tcd);
0456 fsl_edma_enable_hardware_requests(edma_tcd);
0457 }
0458
0459 void fsl_edma_sg_link(
0460 volatile struct fsl_edma_tcd *edma_tcd,
0461 const struct fsl_edma_tcd *source_tcd
0462 )
0463 {
0464 edma_tcd->DLAST_SGA = (int32_t) source_tcd;
0465 edma_tcd->BMF |= EDMA_TCD_BMF_E_SG;
0466
0467 if ((edma_tcd->BMF & EDMA_TCD_BMF_E_SG) == 0) {
0468 fsl_edma_copy(edma_tcd, source_tcd);
0469 }
0470 }