1 /*
2 * Copyright 2022 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_edma.h"
9 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
10 #include "fsl_memory.h"
11 #endif
12
13 /*******************************************************************************
14 * Definitions
15 ******************************************************************************/
16
17 /* Component ID definition, used by tools. */
18 #ifndef FSL_COMPONENT_ID
19 #define FSL_COMPONENT_ID "platform.drivers.edma4"
20 #endif
21 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
22 #define CONVERT_TO_DMA_ADDRESS(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
23 #else
24 #define CONVERT_TO_DMA_ADDRESS(addr) ((uint32_t)(addr))
25 #endif
26 #if defined(DMA_RSTS_N)
27 #define EDMA_RESETS_ARRAY DMA_RSTS_N
28 #endif
29 /*******************************************************************************
30 * Prototypes
31 ******************************************************************************/
32 /*!
33 * @brief Map transfer width.
34 *
35 * @param width transfer width.
36 */
37 static edma_transfer_size_t EDMA_TransferWidthMapping(uint32_t width);
38
39 /*!
40 * @brief validate edma errata.
41 *
42 * @param base edma base address.
43 * @param tcd edma transfer content descriptor.
44 */
45 #if defined FSL_FEATURE_EDMA_HAS_ERRATA_51327
46 static inline status_t EDMA_CheckErrata(EDMA_Type *base, edma_tcd_t *tcd);
47 #endif
48 /*******************************************************************************
49 * Variables
50 ******************************************************************************/
51 /*! @brief Array to map EDMA instance number to base pointer. */
52 static EDMA_Type *const s_edmaBases[] = EDMA_BASE_PTRS;
53
54 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
55 /*! @brief Array to map EDMA instance number to clock name. */
56 static const clock_ip_name_t s_edmaClockName[] = EDMA_CLOCKS;
57 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
58
59 #if defined(EDMA_RESETS_ARRAY)
60 /* Reset array */
61 static const reset_ip_name_t s_edmaResets[] = EDMA_RESETS_ARRAY;
62 #endif
63
64 /*! @brief Array to map EDMA instance number to IRQ number. */
65 static const IRQn_Type s_edmaIRQNumber[][FSL_FEATURE_EDMA_MODULE_CHANNEL] = EDMA_CHN_IRQS;
66
67 /*! @brief Pointers to transfer handle for each EDMA channel. */
68 static edma_handle_t *s_EDMAHandle[FSL_FEATURE_SOC_EDMA_COUNT][FSL_FEATURE_EDMA_MODULE_CHANNEL];
69 /*******************************************************************************
70 * Code
71 ******************************************************************************/
EDMA_GetInstance(EDMA_Type * base)72 static uint32_t EDMA_GetInstance(EDMA_Type *base)
73 {
74 uint32_t instance;
75
76 /* Find the instance index from base address mappings. */
77 for (instance = 0; instance < ARRAY_SIZE(s_edmaBases); instance++)
78 {
79 if (s_edmaBases[instance] == base)
80 {
81 break;
82 }
83 }
84
85 assert(instance < ARRAY_SIZE(s_edmaBases));
86
87 return instance;
88 }
89
90 #if defined FSL_FEATURE_EDMA_HAS_ERRATA_51327
EDMA_CheckErrata(EDMA_Type * base,edma_tcd_t * tcd)91 static inline status_t EDMA_CheckErrata(EDMA_Type *base, edma_tcd_t *tcd)
92 {
93 status_t status = kStatus_Success;
94 /* errata 51327: to use scatter gather feature, NBYTES must be multiple of 8 */
95 if ((uint32_t)FSL_FEATURE_EDMA_INSTANCE_HAS_ERRATA_51327n(base) == 1U)
96 {
97 if ((EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(base)) % 8U) != 0U)
98 {
99 assert(false);
100 status = kStatus_InvalidArgument;
101 }
102 }
103
104 return status;
105 }
106 #endif
107
108 /*!
109 * brief Push content of TCD structure into hardware TCD register.
110 *
111 * param base EDMA peripheral base address.
112 * param channel EDMA channel number.
113 * param tcd Point to TCD structure.
114 */
EDMA_InstallTCD(EDMA_Type * base,uint32_t channel,edma_tcd_t * tcd)115 void EDMA_InstallTCD(EDMA_Type *base, uint32_t channel, edma_tcd_t *tcd)
116 {
117 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
118 assert(tcd != NULL);
119
120 edma_tcd_t *tcdRegs = EDMA_TCD_BASE(base, channel);
121
122 #if defined FSL_FEATURE_EDMA_HAS_ERRATA_51327
123 if ((EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(base)) != 0U) &&
124 ((EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) & (uint16_t)DMA_CSR_ESG_MASK) != 0U) &&
125 (EDMA_CheckErrata(base, tcd) != kStatus_Success))
126 {
127 assert(false);
128 }
129 #endif
130
131 /* Clear DONE bit first, otherwise ESG cannot be set */
132 DMA_CLEAR_DONE_STATUS(base, channel);
133 /* Push tcd into hardware TCD register */
134 EDMA_TCD_SADDR(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_SADDR(tcd, EDMA_TCD_TYPE(base));
135 EDMA_TCD_SOFF(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_SOFF(tcd, EDMA_TCD_TYPE(base));
136 EDMA_TCD_ATTR(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(base));
137 EDMA_TCD_NBYTES(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(base));
138 EDMA_TCD_SLAST(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_SLAST(tcd, EDMA_TCD_TYPE(base));
139 EDMA_TCD_DADDR(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_DADDR(tcd, EDMA_TCD_TYPE(base));
140 EDMA_TCD_DOFF(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_DOFF(tcd, EDMA_TCD_TYPE(base));
141 EDMA_TCD_CITER(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base));
142 EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(base));
143 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base));
144 EDMA_TCD_BITER(tcdRegs, EDMA_TCD_TYPE(base)) = EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base));
145 }
146
147 /*!
148 * brief Initializes the eDMA peripheral.
149 *
150 * This function ungates the eDMA clock and configures the eDMA peripheral according
151 * to the configuration structure.
152 *
153 * param base eDMA peripheral base address.
154 * param config A pointer to the configuration structure, see "edma_config_t".
155 * note This function enables the minor loop map feature.
156 */
EDMA_Init(EDMA_Type * base,const edma_config_t * config)157 void EDMA_Init(EDMA_Type *base, const edma_config_t *config)
158 {
159 assert(config != NULL);
160 assert(FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base) != -1);
161
162 uint32_t tmpreg, i = 0U;
163
164 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
165 /* Ungate EDMA peripheral clock */
166 CLOCK_EnableClock(s_edmaClockName[EDMA_GetInstance(base)]);
167 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
168
169 #if defined(EDMA_RESETS_ARRAY)
170 RESET_ReleasePeripheralReset(s_edmaResets[EDMA_GetInstance(base)]);
171 #endif
172
173 #if defined(FSL_EDMA_SOC_IP_EDMA) && FSL_EDMA_SOC_IP_EDMA
174 /* clear all the enabled request, status to make sure EDMA status is in normal condition */
175 EDMA_BASE(base)->ERQ = 0U;
176 EDMA_BASE(base)->INT = 0xFFFFFFFFU;
177 EDMA_BASE(base)->ERR = 0xFFFFFFFFU;
178 /* Configure EDMA peripheral according to the configuration structure. */
179 tmpreg = EDMA_BASE(base)->CR;
180 tmpreg &= ~(DMA_CR_ERCA_MASK | DMA_CR_HOE_MASK | DMA_CR_CLM_MASK | DMA_CR_EDBG_MASK);
181 tmpreg |= (DMA_CR_ERCA(config->enableRoundRobinArbitration) | DMA_CR_HOE(config->enableHaltOnError) |
182 DMA_CR_CLM(config->enableContinuousLinkMode) | DMA_CR_EDBG(config->enableDebugMode) | DMA_CR_EMLM(1U));
183 EDMA_BASE(base)->CR = tmpreg;
184 #else
185 tmpreg = EDMA_MP_BASE(base)->MP_CSR;
186 #if defined FSL_FEATURE_EDMA_HAS_GLOBAL_MASTER_ID_REPLICATION && FSL_FEATURE_EDMA_HAS_GLOBAL_MASTER_ID_REPLICATION
187 tmpreg = (tmpreg & ~(DMA_MP_CSR_HAE_MASK | DMA_MP_CSR_ERCA_MASK | DMA_MP_CSR_EDBG_MASK | DMA_MP_CSR_GCLC_MASK |
188 DMA_MP_CSR_GMRC_MASK | DMA_MP_CSR_HALT_MASK)) |
189 DMA_MP_CSR_GMRC(config->enableMasterIdReplication) | DMA_MP_CSR_HAE(config->enableHaltOnError) |
190 DMA_MP_CSR_ERCA(config->enableRoundRobinArbitration) | DMA_MP_CSR_EDBG(config->enableDebugMode) |
191 DMA_MP_CSR_GCLC(config->enableGlobalChannelLink);
192 #else
193 tmpreg = (tmpreg & ~(DMA_MP_CSR_HAE_MASK | DMA_MP_CSR_ERCA_MASK | DMA_MP_CSR_EDBG_MASK | DMA_MP_CSR_GCLC_MASK |
194 DMA_MP_CSR_HALT_MASK)) |
195 DMA_MP_CSR_HAE(config->enableHaltOnError) | DMA_MP_CSR_ERCA(config->enableRoundRobinArbitration) |
196 DMA_MP_CSR_EDBG(config->enableDebugMode) | DMA_MP_CSR_GCLC(config->enableGlobalChannelLink);
197 #endif
198 EDMA_MP_BASE(base)->MP_CSR = tmpreg;
199
200 #if defined FSL_FEATURE_EDMA_HAS_CHANNEL_CONFIG && FSL_FEATURE_EDMA_HAS_CHANNEL_CONFIG
201 /* channel transfer configuration */
202 for (i = 0U; i < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base); i++)
203 {
204 if (config->channelConfig[i] != NULL)
205 {
206 EDMA_InitChannel(base, i, config->channelConfig[i]);
207 }
208 }
209 #endif
210 #endif
211 }
212
213 /*!
214 * brief Deinitializes the eDMA peripheral.
215 *
216 * This function gates the eDMA clock.
217 *
218 * param base eDMA peripheral base address.
219 */
EDMA_Deinit(EDMA_Type * base)220 void EDMA_Deinit(EDMA_Type *base)
221 {
222 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
223 /* Gate EDMA peripheral clock */
224 CLOCK_DisableClock(s_edmaClockName[EDMA_GetInstance(base)]);
225 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
226 }
227
228 #if defined FSL_FEATURE_EDMA_HAS_CHANNEL_CONFIG && FSL_FEATURE_EDMA_HAS_CHANNEL_CONFIG
229 /*!
230 * brief EDMA Channel initialization
231 *
232 * param base eDMA peripheral base address.
233 * param channel eDMA channel number.
234 * param channelConfig pointer to user's eDMA channel config structure, see edma_channel_config_t for detail.
235 */
EDMA_InitChannel(EDMA_Type * base,uint32_t channel,edma_channel_config_t * channelConfig)236 void EDMA_InitChannel(EDMA_Type *base, uint32_t channel, edma_channel_config_t *channelConfig)
237 {
238 assert(channelConfig != NULL);
239
240 EDMA_SetChannelPreemptionConfig(base, channel, &channelConfig->channelPreemptionConfig);
241
242 #if defined FSL_FEATURE_EDMA_HAS_CHANNEL_SWAP_SIZE && FSL_FEATURE_EDMA_HAS_CHANNEL_SWAP_SIZE
243 EDMA_SetChannelSwapSize(base, channel, channelConfig->channelSwapSize);
244 #endif
245
246 #if defined FSL_FEATURE_EDMA_HAS_CHANNEL_MEMORY_ATTRIBUTE && FSL_FEATURE_EDMA_HAS_CHANNEL_MEMORY_ATTRIBUTE
247 EDMA_SetChannelMemoryAttribute(base, channel, channelConfig->channelWriteMemoryAttribute,
248 channelConfig->channelReadMemoryAttribute);
249 #endif
250 #if defined FSL_FEATURE_EDMA_HAS_CHANNEL_SIGN_EXTENSION && FSL_FEATURE_EDMA_HAS_CHANNEL_SIGN_EXTENSION
251 EDMA_SetChannelSignExtension(base, channel, channelConfig->channelDataSignExtensionBitPosition);
252 #endif
253 #if defined FSL_FEATURE_EDMA_HAS_CHANNEL_ACCESS_TYPE && FSL_FEATURE_EDMA_HAS_CHANNEL_ACCESS_TYPE
254 EDMA_SetChannelAccessType(base, channel, channelConfig->channelAccessType);
255 #endif
256
257 #if (defined FSL_FEATURE_EDMA_HAS_CHANNEL_MUX && FSL_FEATURE_EDMA_HAS_CHANNEL_MUX) || \
258 (defined FSL_FEATURE_EDMA_HAS_MP_CHANNEL_MUX && FSL_FEATURE_EDMA_HAS_MP_CHANNEL_MUX)
259 if (0U != (uint32_t)channelConfig->channelRequestSource)
260 {
261 /* dma request source */
262 EDMA_SetChannelMux(base, channel, (int32_t)channelConfig->channelRequestSource);
263 }
264 #endif
265
266 /* master ID replication */
267 EDMA_EnableChannelMasterIDReplication(base, channel, channelConfig->enableMasterIDReplication);
268 #if !(defined(FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC) && FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC)
269 /* dma transfer security level */
270 EDMA_SetChannelSecurityLevel(base, channel, channelConfig->securityLevel);
271 #endif
272 /* dma transfer protection level */
273 EDMA_SetChannelProtectionLevel(base, channel, channelConfig->protectionLevel);
274 }
275 #endif
276
277 /*!
278 * brief Gets the eDMA default configuration structure.
279 *
280 * This function sets the configuration structure to default values.
281 * The default configuration is set to the following values.
282 * code
283 * config.enableContinuousLinkMode = false;
284 * config.enableHaltOnError = true;
285 * config.enableRoundRobinArbitration = false;
286 * config.enableDebugMode = false;
287 * endcode
288 *
289 * param config A pointer to the eDMA configuration structure.
290 */
EDMA_GetDefaultConfig(edma_config_t * config)291 void EDMA_GetDefaultConfig(edma_config_t *config)
292 {
293 assert(config != NULL);
294
295 /* Initializes the configure structure to zero. */
296 (void)memset(config, 0, sizeof(*config));
297
298 config->enableRoundRobinArbitration = false;
299
300 config->enableHaltOnError = true;
301
302 #if defined FSL_FEATURE_EDMA_HAS_CONTINUOUS_LINK_MODE && FSL_FEATURE_EDMA_HAS_CONTINUOUS_LINK_MODE
303 config->enableContinuousLinkMode = false;
304 #endif
305
306 #if defined FSL_FEATURE_EDMA_HAS_GLOBAL_MASTER_ID_REPLICATION && FSL_FEATURE_EDMA_HAS_GLOBAL_MASTER_ID_REPLICATION
307 config->enableMasterIdReplication = false;
308 #endif
309
310 config->enableDebugMode = false;
311
312 config->enableGlobalChannelLink = true;
313 }
314
315 /*!
316 * brief Sets all TCD registers to default values.
317 *
318 * This function sets TCD registers for this channel to default values.
319 *
320 * param base eDMA peripheral base address.
321 * param channel eDMA channel number.
322 * note This function must not be called while the channel transfer is ongoing
323 * or it causes unpredictable results.
324 * note This function enables the auto stop request feature.
325 */
EDMA_ResetChannel(EDMA_Type * base,uint32_t channel)326 void EDMA_ResetChannel(EDMA_Type *base, uint32_t channel)
327 {
328 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
329
330 /* reset channel CSR */
331 EDMA_ClearChannelStatusFlags(base, channel, (uint32_t)kEDMA_DoneFlag | (uint32_t)kEDMA_ErrorFlag);
332 /* reset channel TCD */
333 EDMA_TcdResetExt(base, EDMA_TCD_BASE(base, channel));
334 }
335
336 /*!
337 * brief Configures the eDMA transfer attribute.
338 *
339 * This function configures the transfer attribute, including source address, destination address,
340 * transfer size, address offset, and so on. It also configures the scatter gather feature if the
341 * user supplies the TCD address.
342 * Example:
343 * code
344 * edma_transfer_t config;
345 * edma_tcd_t tcd;
346 * config.srcAddr = ..;
347 * config.destAddr = ..;
348 * ...
349 * EDMA_SetTransferConfig(DMA0, channel, &config, &stcd);
350 * endcode
351 *
352 * param base eDMA peripheral base address.
353 * param channel eDMA channel number.
354 * param config Pointer to eDMA transfer configuration structure.
355 * param nextTcd Point to TCD structure. It can be NULL if users
356 * do not want to enable scatter/gather feature.
357 * note If nextTcd is not NULL, it means scatter gather feature is enabled
358 * and DREQ bit is cleared in the previous transfer configuration, which
359 * is set in the eDMA_ResetChannel.
360 */
EDMA_SetTransferConfig(EDMA_Type * base,uint32_t channel,const edma_transfer_config_t * config,edma_tcd_t * nextTcd)361 void EDMA_SetTransferConfig(EDMA_Type *base,
362 uint32_t channel,
363 const edma_transfer_config_t *config,
364 edma_tcd_t *nextTcd)
365 {
366 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
367 assert(config != NULL);
368
369 EDMA_TcdSetTransferConfigExt(base, EDMA_TCD_BASE(base, channel), config,
370 (edma_tcd_t *)CONVERT_TO_DMA_ADDRESS(nextTcd));
371 }
372
373 /*!
374 * brief Configures the eDMA minor offset feature.
375 *
376 * The minor offset means that the signed-extended value is added to the source address or destination
377 * address after each minor loop.
378 *
379 * param base eDMA peripheral base address.
380 * param channel eDMA channel number.
381 * param config A pointer to the minor offset configuration structure.
382 */
EDMA_SetMinorOffsetConfig(EDMA_Type * base,uint32_t channel,const edma_minor_offset_config_t * config)383 void EDMA_SetMinorOffsetConfig(EDMA_Type *base, uint32_t channel, const edma_minor_offset_config_t *config)
384 {
385 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
386 assert(config != NULL);
387
388 uint32_t tmpreg;
389
390 tmpreg = EDMA_TCD_NBYTES(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base));
391 tmpreg &= ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
392 tmpreg |=
393 (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
394 DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
395 EDMA_TCD_NBYTES(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) = tmpreg;
396 }
397
398 /*!
399 * brief Configures the eDMA channel TCD major offset feature.
400 *
401 * Adjustment value added to the source address at the completion of the major iteration count
402 *
403 * param base eDMA peripheral base address.
404 * param channel edma channel number.
405 * param sourceOffset source address offset.
406 * param destOffset destination address offset.
407 */
EDMA_SetMajorOffsetConfig(EDMA_Type * base,uint32_t channel,int32_t sourceOffset,int32_t destOffset)408 void EDMA_SetMajorOffsetConfig(EDMA_Type *base, uint32_t channel, int32_t sourceOffset, int32_t destOffset)
409 {
410 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
411
412 EDMA_TCD_SLAST(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) = (uint32_t)sourceOffset;
413 EDMA_TCD_DLAST_SGA(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) = (uint32_t)destOffset;
414 }
415
416 /*!
417 * brief Configures the eDMA channel preemption feature.
418 *
419 * This function configures the channel preemption attribute and the priority of the channel.
420 *
421 * param base eDMA peripheral base address.
422 * param channel eDMA channel number
423 * param config A pointer to the channel preemption configuration structure.
424 */
EDMA_SetChannelPreemptionConfig(EDMA_Type * base,uint32_t channel,const edma_channel_Preemption_config_t * config)425 void EDMA_SetChannelPreemptionConfig(EDMA_Type *base, uint32_t channel, const edma_channel_Preemption_config_t *config)
426 {
427 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
428 assert(config != NULL);
429
430 bool tmpEnablePreemptAbility = config->enablePreemptAbility;
431 bool tmpEnablchannelPreemption = config->enableChannelPreemption;
432 uint8_t tmpChannelPriority = config->channelPriority;
433
434 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
435
436 volatile uint8_t *tmpReg = &EDMA_BASE(base)->DCHPRI3;
437
438 ((volatile uint8_t *)tmpReg)[DMA_DCHPRI_INDEX(channel)] =
439 (DMA_DCHPRI0_DPA((true == tmpEnablePreemptAbility ? 0U : 1U)) |
440 DMA_DCHPRI0_ECP((true == tmpEnablchannelPreemption ? 1U : 0U)) | DMA_DCHPRI0_CHPRI(tmpChannelPriority));
441 #else
442 EDMA_CHANNEL_BASE(base, channel)->CH_PRI = DMA_CH_PRI_ECP(tmpEnablchannelPreemption) |
443 DMA_CH_PRI_DPA(tmpEnablePreemptAbility) |
444 DMA_CH_PRI_APL(tmpChannelPriority);
445 #endif
446 }
447
448 /*!
449 * brief Sets the channel link for the eDMA transfer.
450 *
451 * This function configures either the minor link or the major link mode. The minor link means that the channel link is
452 * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
453 * exhausted.
454 *
455 * param base eDMA peripheral base address.
456 * param channel eDMA channel number.
457 * param type A channel link type, which can be one of the following:
458 * arg kEDMA_LinkNone
459 * arg kEDMA_MinorLink
460 * arg kEDMA_MajorLink
461 * param linkedChannel The linked channel number.
462 * note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
463 */
EDMA_SetChannelLink(EDMA_Type * base,uint32_t channel,edma_channel_link_type_t type,uint32_t linkedChannel)464 void EDMA_SetChannelLink(EDMA_Type *base, uint32_t channel, edma_channel_link_type_t type, uint32_t linkedChannel)
465 {
466 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
467 assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
468
469 EDMA_TcdSetChannelLinkExt(base, EDMA_TCD_BASE(base, channel), type, linkedChannel);
470 }
471
472 #if defined FSL_FEATURE_EDMA_HAS_BANDWIDTH && FSL_FEATURE_EDMA_HAS_BANDWIDTH
473 /*!
474 * brief Sets the bandwidth for the eDMA transfer.
475 *
476 * Because the eDMA processes the minor loop, it continuously generates read/write sequences
477 * until the minor count is exhausted. The bandwidth forces the eDMA to stall after the completion of
478 * each read/write access to control the bus request bandwidth seen by the crossbar switch.
479 *
480 * param base eDMA peripheral base address.
481 * param channel eDMA channel number.
482 * param bandWidth A bandwidth setting, which can be one of the following:
483 * arg kEDMABandwidthStallNone
484 * arg kEDMABandwidthStall4Cycle
485 * arg kEDMABandwidthStall8Cycle
486 */
EDMA_SetBandWidth(EDMA_Type * base,uint32_t channel,edma_bandwidth_t bandWidth)487 void EDMA_SetBandWidth(EDMA_Type *base, uint32_t channel, edma_bandwidth_t bandWidth)
488 {
489 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
490
491 EDMA_TCD_CSR(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) =
492 (uint16_t)((EDMA_TCD_CSR(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) & (~DMA_CSR_BWC_MASK)) |
493 DMA_CSR_BWC(bandWidth));
494 }
495 #endif
496
497 /*!
498 * brief Sets the source modulo and the destination modulo for the eDMA transfer.
499 *
500 * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
501 * calculation is performed or the original register value. It provides the ability to implement a circular data
502 * queue easily.
503 *
504 * param base eDMA peripheral base address.
505 * param channel eDMA channel number.
506 * param srcModulo A source modulo value.
507 * param destModulo A destination modulo value.
508 */
EDMA_SetModulo(EDMA_Type * base,uint32_t channel,edma_modulo_t srcModulo,edma_modulo_t destModulo)509 void EDMA_SetModulo(EDMA_Type *base, uint32_t channel, edma_modulo_t srcModulo, edma_modulo_t destModulo)
510 {
511 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
512
513 uint16_t tmpreg = EDMA_TCD_ATTR(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) &
514 (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
515 EDMA_TCD_ATTR(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) =
516 tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
517 }
518
519 /*!
520 * brief Sets all fields to default values for the TCD structure.
521 *
522 * This function sets all fields for this TCD structure to default value.
523 *
524 * param base eDMA peripheral base address.
525 * param tcd Pointer to the TCD structure.
526 * note This function enables the auto stop request feature.
527 */
EDMA_TcdResetExt(EDMA_Type * base,edma_tcd_t * tcd)528 void EDMA_TcdResetExt(EDMA_Type *base, edma_tcd_t *tcd)
529 {
530 assert(tcd != NULL);
531 assert(((uint32_t)tcd & 0x1FU) == 0U);
532
533 /* Reset channel TCD */
534 EDMA_TCD_SADDR(tcd, EDMA_TCD_TYPE(base)) = 0U;
535 EDMA_TCD_SOFF(tcd, EDMA_TCD_TYPE(base)) = 0U;
536 EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(base)) = 0U;
537 EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(base)) = 0U;
538 EDMA_TCD_SLAST(tcd, EDMA_TCD_TYPE(base)) = 0U;
539 EDMA_TCD_DADDR(tcd, EDMA_TCD_TYPE(base)) = 0U;
540 EDMA_TCD_DOFF(tcd, EDMA_TCD_TYPE(base)) = 0U;
541 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) = 0U;
542 EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(base)) = 0U;
543 /* Enable auto disable request feature */
544 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) = DMA_CSR_DREQ(1U);
545 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) = 0U;
546 }
547
548 /*!
549 * brief Configures the eDMA TCD transfer attribute.
550 *
551 * The TCD is a transfer control descriptor. The content of the TCD is the same as the hardware TCD registers.
552 * The TCD is used in the scatter-gather mode.
553 * This function configures the TCD transfer attribute, including source address, destination address,
554 * transfer size, address offset, and so on. It also configures the scatter gather feature if the
555 * user supplies the next TCD address.
556 * Example:
557 * code
558 * edma_transfer_t config = {
559 * ...
560 * }
561 * edma_tcd_t tcd __aligned(32);
562 * edma_tcd_t nextTcd __aligned(32);
563 * EDMA_TcdSetTransferConfig(&tcd, &config, &nextTcd);
564 * endcode
565 *
566 * param base eDMA peripheral base address.
567 * param tcd Pointer to the TCD structure.
568 * param config Pointer to eDMA transfer configuration structure.
569 * param nextTcd Pointer to the next TCD structure. It can be NULL if users
570 * do not want to enable scatter/gather feature.
571 * note TCD address should be 32 bytes aligned or it causes an eDMA error.
572 * note If the nextTcd is not NULL, the scatter gather feature is enabled
573 * and DREQ bit is cleared in the previous transfer configuration, which
574 * is set in the EDMA_TcdReset.
575 */
EDMA_TcdSetTransferConfigExt(EDMA_Type * base,edma_tcd_t * tcd,const edma_transfer_config_t * config,edma_tcd_t * nextTcd)576 void EDMA_TcdSetTransferConfigExt(EDMA_Type *base,
577 edma_tcd_t *tcd,
578 const edma_transfer_config_t *config,
579 edma_tcd_t *nextTcd)
580 {
581 assert(tcd != NULL);
582 assert(((uint32_t)tcd & 0x1FU) == 0U);
583 assert(config != NULL);
584
585 EDMA_ConfigChannelSoftwareTCDExt(base, tcd, config);
586
587 if (nextTcd != NULL)
588 {
589 EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(base)) = CONVERT_TO_DMA_ADDRESS(nextTcd);
590 /*
591 Before call EDMA_TcdSetTransferConfig or EDMA_SetTransferConfig,
592 user must call EDMA_TcdReset or EDMA_ResetChannel which will set
593 DREQ, so must use "|" or "&" rather than "=".
594
595 Clear the DREQ bit because scatter gather has been enabled, so the
596 previous transfer is not the last transfer, and channel request should
597 be enabled at the next transfer(the next TCD).
598 */
599 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) =
600 (EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
601 }
602 }
603
604 /*!
605 * brief Sets TCD fields according to the user's channel transfer configuration structure, see
606 * edma_transfer_config_t.
607 *
608 * Application should be careful about the TCD pool buffer storage class,
609 * - For the platform has cache, the software TCD should be put in non cache section
610 * - The TCD pool buffer should have a consistent storage class.
611 *
612 * param base eDMA peripheral base address.
613 * param tcd Pointer to the TCD structure.
614 * param transfer channel transfer configuration pointer.
615 *
616 */
EDMA_ConfigChannelSoftwareTCDExt(EDMA_Type * base,edma_tcd_t * tcd,const edma_transfer_config_t * transfer)617 void EDMA_ConfigChannelSoftwareTCDExt(EDMA_Type *base, edma_tcd_t *tcd, const edma_transfer_config_t *transfer)
618 {
619 assert(transfer != NULL);
620 assert((transfer->minorLoopBytes % (1UL << ((uint32_t)transfer->srcTransferSize))) == 0U);
621 assert((transfer->minorLoopBytes % (1UL << ((uint32_t)transfer->destTransferSize))) == 0U);
622 assert(((uint32_t)transfer->srcOffset % (1UL << ((uint32_t)transfer->srcTransferSize))) == 0U);
623 assert(((uint32_t)transfer->destOffset % (1UL << ((uint32_t)transfer->destTransferSize))) == 0U);
624 assert((transfer->srcAddr % (1UL << ((uint32_t)transfer->srcTransferSize))) == 0U);
625 assert((transfer->destAddr % (1UL << ((uint32_t)transfer->destTransferSize))) == 0U);
626 assert((transfer->srcAddr % (1UL << ((uint32_t)transfer->srcAddrModulo))) == 0U);
627 assert((transfer->destAddr % (1UL << ((uint32_t)transfer->dstAddrModulo))) == 0U);
628
629 uint16_t tmpreg;
630
631 EDMA_TCD_SADDR(tcd, EDMA_TCD_TYPE(base)) = CONVERT_TO_DMA_ADDRESS(transfer->srcAddr);
632 /* destination address */
633 EDMA_TCD_DADDR(tcd, EDMA_TCD_TYPE(base)) = CONVERT_TO_DMA_ADDRESS(transfer->destAddr);
634 /* Source data and destination data transfer size */
635 EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(base)) =
636 DMA_ATTR_SSIZE(transfer->srcTransferSize) | DMA_ATTR_DSIZE(transfer->destTransferSize);
637
638 /* Source address signed offset */
639 EDMA_TCD_SOFF(tcd, EDMA_TCD_TYPE(base)) = (uint16_t)(transfer->srcOffset);
640 /* Destination address signed offset */
641 EDMA_TCD_DOFF(tcd, EDMA_TCD_TYPE(base)) = (uint16_t)(transfer->destOffset);
642
643 if (((transfer->enableSrcMinorLoopOffset) || (transfer->enableDstMinorLoopOffset)))
644 {
645 EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(base)) = DMA_NBYTES_MLOFFYES_NBYTES(transfer->minorLoopBytes) |
646 DMA_NBYTES_MLOFFYES_MLOFF(transfer->minorLoopOffset) |
647 DMA_NBYTES_MLOFFYES_DMLOE(transfer->enableDstMinorLoopOffset) |
648 DMA_NBYTES_MLOFFYES_SMLOE(transfer->enableSrcMinorLoopOffset);
649 }
650 else
651 {
652 EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(base)) = DMA_NBYTES_MLOFFNO_NBYTES(transfer->minorLoopBytes);
653 }
654
655 /* Current major iteration count */
656 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) = (uint16_t)(transfer->majorLoopCounts);
657 /* Starting major iteration count */
658 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) = (uint16_t)(transfer->majorLoopCounts);
659 /* reset CSR firstly */
660 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) = DMA_CSR_DREQ(1U);
661 /* Enable scatter/gather processing */
662 if (transfer->linkTCD != NULL)
663 {
664 EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(base)) = CONVERT_TO_DMA_ADDRESS((uint32_t)((uint8_t *)transfer->linkTCD));
665 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) =
666 (EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
667 }
668 else
669 {
670 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_CSR_ESG_MASK;
671 EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(base)) = (uint32_t)transfer->dstMajorLoopOffset;
672 }
673
674 /* configure interrupt/auto disable channel request */
675 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) |= (transfer->enabledInterruptMask & (~(uint16_t)kEDMA_ErrorInterruptEnable));
676
677 /* Minor link config */
678 if (transfer->enableChannelMinorLoopLink)
679 {
680 /* Enable minor link */
681 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) |= DMA_CITER_ELINKYES_ELINK_MASK;
682 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) |= DMA_BITER_ELINKYES_ELINK_MASK;
683 /* Set linked channel */
684 tmpreg = EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)DMA_CITER_ELINKYES_LINKCH_MASK);
685 tmpreg |= DMA_CITER_ELINKYES_LINKCH(transfer->minorLoopLinkChannel);
686 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) = tmpreg;
687 tmpreg = EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)DMA_BITER_ELINKYES_LINKCH_MASK);
688 tmpreg |= DMA_BITER_ELINKYES_LINKCH(transfer->minorLoopLinkChannel);
689 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) = tmpreg;
690 }
691 /* Major link config */
692 if (transfer->enableChannelMajorLoopLink)
693 {
694 /* Enable major link */
695 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) |= DMA_CSR_MAJORELINK_MASK;
696 /* Set major linked channel */
697 tmpreg = EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)DMA_CSR_MAJORLINKCH_MASK);
698 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) = tmpreg | DMA_CSR_MAJORLINKCH(transfer->majorLoopLinkChannel);
699 }
700
701 /* clear link relate field if no channel link enabled */
702 if ((!transfer->enableChannelMajorLoopLink) && (!transfer->enableChannelMinorLoopLink))
703 {
704 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_CITER_ELINKYES_ELINK_MASK;
705 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_BITER_ELINKYES_ELINK_MASK;
706 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_CSR_MAJORELINK_MASK;
707 }
708
709 /* major loop offset */
710 EDMA_TCD_SLAST(tcd, EDMA_TCD_TYPE(base)) = (uint32_t)transfer->srcMajorLoopOffset;
711 /* modulo feature */
712 tmpreg = EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
713 EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(base)) =
714 tmpreg | DMA_ATTR_DMOD(transfer->dstAddrModulo) | DMA_ATTR_SMOD(transfer->srcAddrModulo);
715 }
716
717 /*!
718 * brief Configures the eDMA TCD minor offset feature.
719 *
720 * A minor offset is a signed-extended value added to the source address or a destination
721 * address after each minor loop.
722 *
723 * param base eDMA peripheral base address.
724 * param tcd A point to the TCD structure.
725 * param config A pointer to the minor offset configuration structure.
726 */
EDMA_TcdSetMinorOffsetConfigExt(EDMA_Type * base,edma_tcd_t * tcd,const edma_minor_offset_config_t * config)727 void EDMA_TcdSetMinorOffsetConfigExt(EDMA_Type *base, edma_tcd_t *tcd, const edma_minor_offset_config_t *config)
728 {
729 assert(tcd != NULL);
730 assert(((uint32_t)tcd & 0x1FU) == 0U);
731
732 uint32_t tmpreg;
733
734 tmpreg = EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(base)) &
735 ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
736 tmpreg |=
737 (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
738 DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
739 EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(base)) = tmpreg;
740 }
741
742 /*!
743 * brief Configures the eDMA TCD major offset feature.
744 *
745 * Adjustment value added to the source address at the completion of the major iteration count
746 *
747 * param base eDMA peripheral base address.
748 * param tcd A point to the TCD structure.
749 * param sourceOffset source address offset.
750 * param destOffset destination address offset.
751 */
EDMA_TcdSetMajorOffsetConfigExt(EDMA_Type * base,edma_tcd_t * tcd,int32_t sourceOffset,int32_t destOffset)752 void EDMA_TcdSetMajorOffsetConfigExt(EDMA_Type *base, edma_tcd_t *tcd, int32_t sourceOffset, int32_t destOffset)
753 {
754 assert(tcd != NULL);
755 assert(((uint32_t)tcd & 0x1FU) == 0U);
756
757 EDMA_TCD_SLAST(tcd, EDMA_TCD_TYPE(base)) = (uint32_t)sourceOffset;
758 EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(base)) = (uint32_t)destOffset;
759 }
760
761 /*!
762 * brief Sets the channel link for the eDMA TCD.
763 *
764 * This function configures either a minor link or a major link. The minor link means the channel link is
765 * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
766 * exhausted.
767 *
768 * note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
769 * param base eDMA peripheral base address.
770 * param tcd Point to the TCD structure.
771 * param type Channel link type, it can be one of:
772 * arg kEDMA_LinkNone
773 * arg kEDMA_MinorLink
774 * arg kEDMA_MajorLink
775 * param linkedChannel The linked channel number.
776 */
EDMA_TcdSetChannelLinkExt(EDMA_Type * base,edma_tcd_t * tcd,edma_channel_link_type_t type,uint32_t linkedChannel)777 void EDMA_TcdSetChannelLinkExt(EDMA_Type *base, edma_tcd_t *tcd, edma_channel_link_type_t type, uint32_t linkedChannel)
778 {
779 assert(tcd != NULL);
780 assert(((uint32_t)tcd & 0x1FU) == 0U);
781 assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
782
783 if (type == kEDMA_MinorLink) /* Minor link config */
784 {
785 uint16_t tmpreg;
786
787 /* Enable minor link */
788 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) |= DMA_CITER_ELINKYES_ELINK_MASK;
789 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) |= DMA_BITER_ELINKYES_ELINK_MASK;
790 /* Set linked channel */
791 tmpreg = EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)DMA_CITER_ELINKYES_LINKCH_MASK);
792 tmpreg |= DMA_CITER_ELINKYES_LINKCH(linkedChannel);
793 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) = tmpreg;
794 tmpreg = EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)DMA_BITER_ELINKYES_LINKCH_MASK);
795 tmpreg |= DMA_BITER_ELINKYES_LINKCH(linkedChannel);
796 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) = tmpreg;
797 }
798 else if (type == kEDMA_MajorLink) /* Major link config */
799 {
800 uint16_t tmpreg;
801
802 /* Enable major link */
803 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) |= DMA_CSR_MAJORELINK_MASK;
804 /* Set major linked channel */
805 tmpreg = EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)DMA_CSR_MAJORLINKCH_MASK);
806 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) = tmpreg | DMA_CSR_MAJORLINKCH(linkedChannel);
807 }
808 else /* Link none */
809 {
810 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_CITER_ELINKYES_ELINK_MASK;
811 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_BITER_ELINKYES_ELINK_MASK;
812 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_CSR_MAJORELINK_MASK;
813 }
814 }
815
816 /*!
817 * brief Sets the source modulo and the destination modulo for the eDMA TCD.
818 *
819 * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
820 * calculation is performed or the original register value. It provides the ability to implement a circular data
821 * queue easily.
822 *
823 * param base eDMA peripheral base address.
824 * param tcd A pointer to the TCD structure.
825 * param srcModulo A source modulo value.
826 * param destModulo A destination modulo value.
827 */
EDMA_TcdSetModuloExt(EDMA_Type * base,edma_tcd_t * tcd,edma_modulo_t srcModulo,edma_modulo_t destModulo)828 void EDMA_TcdSetModuloExt(EDMA_Type *base, edma_tcd_t *tcd, edma_modulo_t srcModulo, edma_modulo_t destModulo)
829 {
830 assert(tcd != NULL);
831 assert(((uint32_t)tcd & 0x1FU) == 0U);
832
833 uint16_t tmpreg;
834
835 tmpreg = EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(base)) & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
836 EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(base)) = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
837 }
838
839 /*!
840 * brief Enables the interrupt source for the eDMA TCD.
841 *
842 * param base eDMA peripheral base address.
843 * param tcd Point to the TCD structure.
844 * param mask The mask of interrupt source to be set. Users need to use
845 * the defined edma_interrupt_enable_t type.
846 */
EDMA_TcdEnableInterruptsExt(EDMA_Type * base,edma_tcd_t * tcd,uint32_t mask)847 void EDMA_TcdEnableInterruptsExt(EDMA_Type *base, edma_tcd_t *tcd, uint32_t mask)
848 {
849 assert(tcd != NULL);
850
851 /* Enable Major interrupt */
852 if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
853 {
854 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) |= DMA_CSR_INTMAJOR_MASK;
855 }
856
857 /* Enable Half major interrupt */
858 if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
859 {
860 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) |= DMA_CSR_INTHALF_MASK;
861 }
862 }
863
864 /*!
865 * brief Disables the interrupt source for the eDMA TCD.
866 *
867 * param base eDMA peripheral base address.
868 * param tcd Point to the TCD structure.
869 * param mask The mask of interrupt source to be set. Users need to use
870 * the defined edma_interrupt_enable_t type.
871 */
EDMA_TcdDisableInterruptsExt(EDMA_Type * base,edma_tcd_t * tcd,uint32_t mask)872 void EDMA_TcdDisableInterruptsExt(EDMA_Type *base, edma_tcd_t *tcd, uint32_t mask)
873 {
874 assert(tcd != NULL);
875
876 /* Disable Major interrupt */
877 if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
878 {
879 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_CSR_INTMAJOR_MASK;
880 }
881
882 /* Disable Half major interrupt */
883 if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
884 {
885 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(base)) &= ~(uint16_t)DMA_CSR_INTHALF_MASK;
886 }
887 }
888
889 /*!
890 * brief Sets all fields to default values for the TCD structure.
891 *
892 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
893 * EDMA_TcdResetExt
894 *
895 * This function sets all fields for this TCD structure to default value.
896 *
897 * param tcd Pointer to the TCD structure.
898 * note This function enables the auto stop request feature.
899 */
EDMA_TcdReset(edma_tcd_t * tcd)900 void EDMA_TcdReset(edma_tcd_t *tcd)
901 {
902 assert(tcd != NULL);
903
904 /* Reset channel TCD */
905 EDMA_TCD_SADDR(tcd, kEDMA_EDMA4Flag) = 0U;
906 EDMA_TCD_SOFF(tcd, kEDMA_EDMA4Flag) = 0U;
907 EDMA_TCD_ATTR(tcd, kEDMA_EDMA4Flag) = 0U;
908 EDMA_TCD_NBYTES(tcd, kEDMA_EDMA4Flag) = 0U;
909 EDMA_TCD_SLAST(tcd, kEDMA_EDMA4Flag) = 0U;
910 EDMA_TCD_DADDR(tcd, kEDMA_EDMA4Flag) = 0U;
911 EDMA_TCD_DOFF(tcd, kEDMA_EDMA4Flag) = 0U;
912 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) = 0U;
913 EDMA_TCD_DLAST_SGA(tcd, kEDMA_EDMA4Flag) = 0U;
914 /* Enable auto disable request feature */
915 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) = DMA_CSR_DREQ(1U);
916 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) = 0U;
917 }
918
919 /*!
920 * brief Configures the eDMA TCD transfer attribute.
921 *
922 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
923 * EDMA_TcdSetTransferConfigExt
924 *
925 * The TCD is a transfer control descriptor. The content of the TCD is the same as the hardware TCD registers.
926 * The TCD is used in the scatter-gather mode.
927 * This function configures the TCD transfer attribute, including source address, destination address,
928 * transfer size, address offset, and so on. It also configures the scatter gather feature if the
929 * user supplies the next TCD address.
930 * Example:
931 * code
932 * edma_transfer_t config = {
933 * ...
934 * }
935 * edma_tcd_t tcd __aligned(32);
936 * edma_tcd_t nextTcd __aligned(32);
937 * EDMA_TcdSetTransferConfig(&tcd, &config, &nextTcd);
938 * endcode
939 *
940 * param tcd Pointer to the TCD structure.
941 * param config Pointer to eDMA transfer configuration structure.
942 * param nextTcd Pointer to the next TCD structure. It can be NULL if users
943 * do not want to enable scatter/gather feature.
944 * note TCD address should be 32 bytes aligned or it causes an eDMA error.
945 * note If the nextTcd is not NULL, the scatter gather feature is enabled
946 * and DREQ bit is cleared in the previous transfer configuration, which
947 * is set in the EDMA_TcdReset.
948 */
EDMA_TcdSetTransferConfig(edma_tcd_t * tcd,const edma_transfer_config_t * config,edma_tcd_t * nextTcd)949 void EDMA_TcdSetTransferConfig(edma_tcd_t *tcd, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
950 {
951 assert(tcd != NULL);
952 assert(config != NULL);
953
954 EDMA_ConfigChannelSoftwareTCD(tcd, config);
955
956 if (nextTcd != NULL)
957 {
958 EDMA_TCD_DLAST_SGA(tcd, kEDMA_EDMA4Flag) = CONVERT_TO_DMA_ADDRESS(nextTcd);
959 /*
960 Before call EDMA_TcdSetTransferConfig or EDMA_SetTransferConfig,
961 user must call EDMA_TcdReset or EDMA_ResetChannel which will set
962 DREQ, so must use "|" or "&" rather than "=".
963
964 Clear the DREQ bit because scatter gather has been enabled, so the
965 previous transfer is not the last transfer, and channel request should
966 be enabled at the next transfer(the next TCD).
967 */
968 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) =
969 (EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
970 }
971 }
972
973 /*!
974 * brief Sets TCD fields according to the user's channel transfer configuration structure, see
975 * edma_transfer_config_t.
976 *
977 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
978 * EDMA_ConfigChannelSoftwareTCDExt
979 *
980 * Application should be careful about the TCD pool buffer storage class,
981 * - For the platform has cache, the software TCD should be put in non cache section
982 * - The TCD pool buffer should have a consistent storage class.
983 *
984 * param tcd Pointer to the TCD structure.
985 * param transfer channel transfer configuration pointer.
986 *
987 */
EDMA_ConfigChannelSoftwareTCD(edma_tcd_t * tcd,const edma_transfer_config_t * transfer)988 void EDMA_ConfigChannelSoftwareTCD(edma_tcd_t *tcd, const edma_transfer_config_t *transfer)
989 {
990 assert(transfer != NULL);
991 assert((transfer->minorLoopBytes % (1UL << ((uint32_t)transfer->srcTransferSize))) == 0U);
992 assert((transfer->minorLoopBytes % (1UL << ((uint32_t)transfer->destTransferSize))) == 0U);
993 assert(((uint32_t)transfer->srcOffset % (1UL << ((uint32_t)transfer->srcTransferSize))) == 0U);
994 assert(((uint32_t)transfer->destOffset % (1UL << ((uint32_t)transfer->destTransferSize))) == 0U);
995 assert((transfer->srcAddr % (1UL << ((uint32_t)transfer->srcTransferSize))) == 0U);
996 assert((transfer->destAddr % (1UL << ((uint32_t)transfer->destTransferSize))) == 0U);
997 assert((transfer->srcAddr % (1UL << ((uint32_t)transfer->srcAddrModulo))) == 0U);
998 assert((transfer->destAddr % (1UL << ((uint32_t)transfer->dstAddrModulo))) == 0U);
999
1000 uint16_t tmpreg;
1001
1002 EDMA_TCD_SADDR(tcd, kEDMA_EDMA4Flag) = CONVERT_TO_DMA_ADDRESS(transfer->srcAddr);
1003 /* destination address */
1004 EDMA_TCD_DADDR(tcd, kEDMA_EDMA4Flag) = CONVERT_TO_DMA_ADDRESS(transfer->destAddr);
1005 /* Source data and destination data transfer size */
1006 EDMA_TCD_ATTR(tcd, kEDMA_EDMA4Flag) =
1007 DMA_ATTR_SSIZE(transfer->srcTransferSize) | DMA_ATTR_DSIZE(transfer->destTransferSize);
1008
1009 /* Source address signed offset */
1010 EDMA_TCD_SOFF(tcd, kEDMA_EDMA4Flag) = (uint16_t)(transfer->srcOffset);
1011 /* Destination address signed offset */
1012 EDMA_TCD_DOFF(tcd, kEDMA_EDMA4Flag) = (uint16_t)(transfer->destOffset);
1013
1014 if (((transfer->enableSrcMinorLoopOffset) || (transfer->enableDstMinorLoopOffset)))
1015 {
1016 EDMA_TCD_NBYTES(tcd, kEDMA_EDMA4Flag) = DMA_NBYTES_MLOFFYES_NBYTES(transfer->minorLoopBytes) |
1017 DMA_NBYTES_MLOFFYES_MLOFF(transfer->minorLoopOffset) |
1018 DMA_NBYTES_MLOFFYES_DMLOE(transfer->enableDstMinorLoopOffset) |
1019 DMA_NBYTES_MLOFFYES_SMLOE(transfer->enableSrcMinorLoopOffset);
1020 }
1021 else
1022 {
1023 EDMA_TCD_NBYTES(tcd, kEDMA_EDMA4Flag) = DMA_NBYTES_MLOFFNO_NBYTES(transfer->minorLoopBytes);
1024 }
1025
1026 /* Current major iteration count */
1027 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) = (uint16_t)(transfer->majorLoopCounts);
1028 /* Starting major iteration count */
1029 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) = (uint16_t)(transfer->majorLoopCounts);
1030 /* reset CSR firstly */
1031 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) = DMA_CSR_DREQ(1U);
1032 /* Enable scatter/gather processing */
1033 if (transfer->linkTCD != NULL)
1034 {
1035 EDMA_TCD_DLAST_SGA(tcd, kEDMA_EDMA4Flag) = CONVERT_TO_DMA_ADDRESS((uint32_t)((uint8_t *)transfer->linkTCD));
1036 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) =
1037 (EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
1038 }
1039 else
1040 {
1041 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_CSR_ESG_MASK;
1042 EDMA_TCD_DLAST_SGA(tcd, kEDMA_EDMA4Flag) = (uint32_t)transfer->dstMajorLoopOffset;
1043 }
1044
1045 /* configure interrupt/auto disable channel request */
1046 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) |= (transfer->enabledInterruptMask & (~(uint16_t)kEDMA_ErrorInterruptEnable));
1047
1048 /* Minor link config */
1049 if (transfer->enableChannelMinorLoopLink)
1050 {
1051 /* Enable minor link */
1052 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) |= DMA_CITER_ELINKYES_ELINK_MASK;
1053 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) |= DMA_BITER_ELINKYES_ELINK_MASK;
1054 /* Set linked channel */
1055 tmpreg = EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)DMA_CITER_ELINKYES_LINKCH_MASK);
1056 tmpreg |= DMA_CITER_ELINKYES_LINKCH(transfer->minorLoopLinkChannel);
1057 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) = tmpreg;
1058 tmpreg = EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)DMA_BITER_ELINKYES_LINKCH_MASK);
1059 tmpreg |= DMA_BITER_ELINKYES_LINKCH(transfer->minorLoopLinkChannel);
1060 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) = tmpreg;
1061 }
1062 /* Major link config */
1063 if (transfer->enableChannelMajorLoopLink)
1064 {
1065 /* Enable major link */
1066 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) |= DMA_CSR_MAJORELINK_MASK;
1067 /* Set major linked channel */
1068 tmpreg = EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)DMA_CSR_MAJORLINKCH_MASK);
1069 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) = tmpreg | DMA_CSR_MAJORLINKCH(transfer->majorLoopLinkChannel);
1070 }
1071
1072 /* clear link relate field if no channel link enabled */
1073 if ((!transfer->enableChannelMajorLoopLink) && (!transfer->enableChannelMinorLoopLink))
1074 {
1075 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_CITER_ELINKYES_ELINK_MASK;
1076 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_BITER_ELINKYES_ELINK_MASK;
1077 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_CSR_MAJORELINK_MASK;
1078 }
1079
1080 /* major loop offset */
1081 EDMA_TCD_SLAST(tcd, kEDMA_EDMA4Flag) = (uint32_t)transfer->srcMajorLoopOffset;
1082 /* modulo feature */
1083 tmpreg = EDMA_TCD_ATTR(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
1084 EDMA_TCD_ATTR(tcd, kEDMA_EDMA4Flag) =
1085 tmpreg | DMA_ATTR_DMOD(transfer->dstAddrModulo) | DMA_ATTR_SMOD(transfer->srcAddrModulo);
1086 }
1087
1088 /*!
1089 * brief Configures the eDMA TCD minor offset feature.
1090 *
1091 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
1092 * EDMA_TcdSetMinorOffsetConfigExt
1093 *
1094 * A minor offset is a signed-extended value added to the source address or a destination
1095 * address after each minor loop.
1096 *
1097 * param tcd A point to the TCD structure.
1098 * param config A pointer to the minor offset configuration structure.
1099 */
EDMA_TcdSetMinorOffsetConfig(edma_tcd_t * tcd,const edma_minor_offset_config_t * config)1100 void EDMA_TcdSetMinorOffsetConfig(edma_tcd_t *tcd, const edma_minor_offset_config_t *config)
1101 {
1102 assert(tcd != NULL);
1103
1104 uint32_t tmpreg;
1105
1106 tmpreg = EDMA_TCD_NBYTES(tcd, kEDMA_EDMA4Flag) &
1107 ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
1108 tmpreg |=
1109 (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
1110 DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
1111 EDMA_TCD_NBYTES(tcd, kEDMA_EDMA4Flag) = tmpreg;
1112 }
1113
1114 /*!
1115 * brief Configures the eDMA TCD major offset feature.
1116 *
1117 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
1118 * EDMA_TcdSetMajorOffsetConfigExt
1119 *
1120 * Adjustment value added to the source address at the completion of the major iteration count
1121 *
1122 * param tcd A point to the TCD structure.
1123 * param sourceOffset source address offset.
1124 * param destOffset destination address offset.
1125 */
EDMA_TcdSetMajorOffsetConfig(edma_tcd_t * tcd,int32_t sourceOffset,int32_t destOffset)1126 void EDMA_TcdSetMajorOffsetConfig(edma_tcd_t *tcd, int32_t sourceOffset, int32_t destOffset)
1127 {
1128 assert(tcd != NULL);
1129
1130 EDMA_TCD_SLAST(tcd, kEDMA_EDMA4Flag) = (uint32_t)sourceOffset;
1131 EDMA_TCD_DLAST_SGA(tcd, kEDMA_EDMA4Flag) = (uint32_t)destOffset;
1132 }
1133
1134 /*!
1135 * brief Sets the channel link for the eDMA TCD.
1136 *
1137 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
1138 * EDMA_TcdSetChannelLinkExt
1139 *
1140 * This function configures either a minor link or a major link. The minor link means the channel link is
1141 * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
1142 * exhausted.
1143 *
1144 * note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
1145 * param tcd Point to the TCD structure.
1146 * param type Channel link type, it can be one of:
1147 * arg kEDMA_LinkNone
1148 * arg kEDMA_MinorLink
1149 * arg kEDMA_MajorLink
1150 * param linkedChannel The linked channel number.
1151 */
EDMA_TcdSetChannelLink(edma_tcd_t * tcd,edma_channel_link_type_t type,uint32_t linkedChannel)1152 void EDMA_TcdSetChannelLink(edma_tcd_t *tcd, edma_channel_link_type_t type, uint32_t linkedChannel)
1153 {
1154 assert(tcd != NULL);
1155 assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
1156
1157 if (type == kEDMA_MinorLink) /* Minor link config */
1158 {
1159 uint16_t tmpreg;
1160
1161 /* Enable minor link */
1162 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) |= DMA_CITER_ELINKYES_ELINK_MASK;
1163 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) |= DMA_BITER_ELINKYES_ELINK_MASK;
1164 /* Set linked channel */
1165 tmpreg = EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)DMA_CITER_ELINKYES_LINKCH_MASK);
1166 tmpreg |= DMA_CITER_ELINKYES_LINKCH(linkedChannel);
1167 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) = tmpreg;
1168 tmpreg = EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)DMA_BITER_ELINKYES_LINKCH_MASK);
1169 tmpreg |= DMA_BITER_ELINKYES_LINKCH(linkedChannel);
1170 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) = tmpreg;
1171 }
1172 else if (type == kEDMA_MajorLink) /* Major link config */
1173 {
1174 uint16_t tmpreg;
1175
1176 /* Enable major link */
1177 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) |= DMA_CSR_MAJORELINK_MASK;
1178 /* Set major linked channel */
1179 tmpreg = EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)DMA_CSR_MAJORLINKCH_MASK);
1180 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) = tmpreg | DMA_CSR_MAJORLINKCH(linkedChannel);
1181 }
1182 else /* Link none */
1183 {
1184 EDMA_TCD_CITER(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_CITER_ELINKYES_ELINK_MASK;
1185 EDMA_TCD_BITER(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_BITER_ELINKYES_ELINK_MASK;
1186 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_CSR_MAJORELINK_MASK;
1187 }
1188 }
1189
1190 /*!
1191 * brief Sets the source modulo and the destination modulo for the eDMA TCD.
1192 *
1193 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
1194 * EDMA_TcdSetModuloExt
1195 *
1196 * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
1197 * calculation is performed or the original register value. It provides the ability to implement a circular data
1198 * queue easily.
1199 *
1200 * param tcd A pointer to the TCD structure.
1201 * param srcModulo A source modulo value.
1202 * param destModulo A destination modulo value.
1203 */
EDMA_TcdSetModulo(edma_tcd_t * tcd,edma_modulo_t srcModulo,edma_modulo_t destModulo)1204 void EDMA_TcdSetModulo(edma_tcd_t *tcd, edma_modulo_t srcModulo, edma_modulo_t destModulo)
1205 {
1206 assert(tcd != NULL);
1207
1208 uint16_t tmpreg;
1209
1210 tmpreg = EDMA_TCD_ATTR(tcd, kEDMA_EDMA4Flag) & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
1211 EDMA_TCD_ATTR(tcd, kEDMA_EDMA4Flag) = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
1212 }
1213
1214 /*!
1215 * brief Enables the interrupt source for the eDMA TCD.
1216 *
1217 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
1218 * EDMA_TcdEnableInterruptsExt
1219 *
1220 * param tcd Point to the TCD structure.
1221 * param mask The mask of interrupt source to be set. Users need to use
1222 * the defined edma_interrupt_enable_t type.
1223 */
EDMA_TcdEnableInterrupts(edma_tcd_t * tcd,uint32_t mask)1224 void EDMA_TcdEnableInterrupts(edma_tcd_t *tcd, uint32_t mask)
1225 {
1226 assert(tcd != NULL);
1227
1228 /* Enable Major interrupt */
1229 if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
1230 {
1231 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) |= DMA_CSR_INTMAJOR_MASK;
1232 }
1233
1234 /* Enable Half major interrupt */
1235 if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
1236 {
1237 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) |= DMA_CSR_INTHALF_MASK;
1238 }
1239 }
1240
1241 /*!
1242 * brief Disables the interrupt source for the eDMA TCD.
1243 *
1244 * Note This API only supports EDMA4 TCD type. It can be used to support all types with extension API ref
1245 * EDMA_TcdDisableInterruptsExt
1246 *
1247 * param tcd Point to the TCD structure.
1248 * param mask The mask of interrupt source to be set. Users need to use
1249 * the defined edma_interrupt_enable_t type.
1250 */
EDMA_TcdDisableInterrupts(edma_tcd_t * tcd,uint32_t mask)1251 void EDMA_TcdDisableInterrupts(edma_tcd_t *tcd, uint32_t mask)
1252 {
1253 assert(tcd != NULL);
1254
1255 /* Disable Major interrupt */
1256 if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
1257 {
1258 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_CSR_INTMAJOR_MASK;
1259 }
1260
1261 /* Disable Half major interrupt */
1262 if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
1263 {
1264 EDMA_TCD_CSR(tcd, kEDMA_EDMA4Flag) &= ~(uint16_t)DMA_CSR_INTHALF_MASK;
1265 }
1266 }
1267
1268 /*!
1269 * brief Gets the remaining major loop count from the eDMA current channel TCD.
1270 *
1271 * This function checks the TCD (Task Control Descriptor) status for a specified
1272 * eDMA channel and returns the number of major loop count that has not finished.
1273 *
1274 * param base eDMA peripheral base address.
1275 * param channel eDMA channel number.
1276 * return Major loop count which has not been transferred yet for the current TCD.
1277 * note 1. This function can only be used to get unfinished major loop count of transfer without
1278 * the next TCD, or it might be inaccuracy.
1279 * 2. The unfinished/remaining transfer bytes cannot be obtained directly from registers while
1280 * the channel is running.
1281 * Because to calculate the remaining bytes, the initial NBYTES configured in DMA_TCDn_NBYTES_MLNO
1282 * register is needed while the eDMA IP does not support getting it while a channel is active.
1283 * In another word, the NBYTES value reading is always the actual (decrementing) NBYTES value the dma_engine
1284 * is working with while a channel is running.
1285 * Consequently, to get the remaining transfer bytes, a software-saved initial value of NBYTES (for example
1286 * copied before enabling the channel) is needed. The formula to calculate it is shown below:
1287 * RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured)
1288 */
EDMA_GetRemainingMajorLoopCount(EDMA_Type * base,uint32_t channel)1289 uint32_t EDMA_GetRemainingMajorLoopCount(EDMA_Type *base, uint32_t channel)
1290 {
1291 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
1292
1293 uint32_t remainingCount = 0;
1294
1295 if (0U != DMA_GET_DONE_STATUS(base, channel))
1296 {
1297 remainingCount = 0;
1298 }
1299 else
1300 {
1301 /* Calculate the unfinished bytes */
1302 if (0U != (EDMA_TCD_CITER(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) & DMA_CITER_ELINKNO_ELINK_MASK))
1303 {
1304 remainingCount = (((uint32_t)EDMA_TCD_CITER(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) &
1305 DMA_CITER_ELINKYES_CITER_MASK) >>
1306 DMA_CITER_ELINKYES_CITER_SHIFT);
1307 }
1308 else
1309 {
1310 remainingCount = (((uint32_t)EDMA_TCD_CITER(EDMA_TCD_BASE(base, channel), EDMA_TCD_TYPE(base)) &
1311 DMA_CITER_ELINKNO_CITER_MASK) >>
1312 DMA_CITER_ELINKNO_CITER_SHIFT);
1313 }
1314 }
1315
1316 return remainingCount;
1317 }
1318
1319 /*!
1320 * brief Enables the interrupt source for the eDMA transfer.
1321 *
1322 * param base eDMA peripheral base address.
1323 * param channel eDMA channel number.
1324 * param mask The mask of interrupt source to be set. Users need to use
1325 * the defined edma_interrupt_enable_t type.
1326 */
EDMA_EnableChannelInterrupts(EDMA_Type * base,uint32_t channel,uint32_t mask)1327 void EDMA_EnableChannelInterrupts(EDMA_Type *base, uint32_t channel, uint32_t mask)
1328 {
1329 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
1330
1331 /* Enable error interrupt */
1332 if (0U != (mask & (uint32_t)kEDMA_ErrorInterruptEnable))
1333 {
1334 DMA_ENABLE_ERROR_INT(base, channel);
1335 }
1336
1337 /* Enable Major interrupt */
1338 if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
1339 {
1340 DMA_ENABLE_MAJOR_INT(base, channel);
1341 }
1342
1343 /* Enable Half major interrupt */
1344 if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
1345 {
1346 DMA_ENABLE_HALF_INT(base, channel);
1347 }
1348 }
1349
1350 /*!
1351 * brief Disables the interrupt source for the eDMA transfer.
1352 *
1353 * param base eDMA peripheral base address.
1354 * param channel eDMA channel number.
1355 * param mask The mask of the interrupt source to be set. Use
1356 * the defined edma_interrupt_enable_t type.
1357 */
EDMA_DisableChannelInterrupts(EDMA_Type * base,uint32_t channel,uint32_t mask)1358 void EDMA_DisableChannelInterrupts(EDMA_Type *base, uint32_t channel, uint32_t mask)
1359 {
1360 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
1361
1362 /* Disable error interrupt */
1363 if (0U != (mask & (uint32_t)kEDMA_ErrorInterruptEnable))
1364 {
1365 DMA_DISABLE_ERROR_INT(base, channel);
1366 }
1367
1368 /* Disable Major interrupt */
1369 if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
1370 {
1371 DMA_DISABLE_MAJOR_INT(base, channel);
1372 }
1373
1374 /* Disable Half major interrupt */
1375 if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
1376 {
1377 DMA_DISABLE_HALF_INT(base, channel);
1378 }
1379 }
1380
1381 /*!
1382 * brief Gets the eDMA channel status flags.
1383 *
1384 * param base eDMA peripheral base address.
1385 * param channel eDMA channel number.
1386 * return The mask of channel status flags. Users need to use the
1387 * _edma_channel_status_flags type to decode the return variables.
1388 */
EDMA_GetChannelStatusFlags(EDMA_Type * base,uint32_t channel)1389 uint32_t EDMA_GetChannelStatusFlags(EDMA_Type *base, uint32_t channel)
1390 {
1391 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
1392
1393 uint32_t retval = 0;
1394
1395 /* Get DONE bit flag */
1396 retval |= DMA_GET_DONE_STATUS(base, channel);
1397 /* Get ERROR bit flag */
1398 retval |= (DMA_GET_ERROR_STATUS(base, channel) << 1U);
1399 /* Get INT bit flag */
1400 retval |= (DMA_GET_INT_STATUS(base, channel) << 2U);
1401
1402 return retval;
1403 }
1404
1405 /*!
1406 * brief Clears the eDMA channel status flags.
1407 *
1408 * param base eDMA peripheral base address.
1409 * param channel eDMA channel number.
1410 * param mask The mask of channel status to be cleared. Users need to use
1411 * the defined _edma_channel_status_flags type.
1412 */
EDMA_ClearChannelStatusFlags(EDMA_Type * base,uint32_t channel,uint32_t mask)1413 void EDMA_ClearChannelStatusFlags(EDMA_Type *base, uint32_t channel, uint32_t mask)
1414 {
1415 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
1416
1417 /* Clear DONE bit flag */
1418 if (0U != (mask & (uint32_t)kEDMA_DoneFlag))
1419 {
1420 DMA_CLEAR_DONE_STATUS(base, channel);
1421 }
1422 /* Clear ERROR bit flag */
1423 if (0U != (mask & (uint32_t)kEDMA_ErrorFlag))
1424 {
1425 DMA_CLEAR_ERROR_STATUS(base, channel);
1426 }
1427 /* Clear INT bit flag */
1428 if (0U != (mask & (uint32_t)kEDMA_InterruptFlag))
1429 {
1430 DMA_CLEAR_INT_STATUS(base, channel);
1431 }
1432 }
1433
1434 /*!
1435 * brief Creates the eDMA handle.
1436 *
1437 * This function is called if using the transactional API for eDMA. This function
1438 * initializes the internal state of the eDMA handle.
1439 *
1440 * param handle eDMA handle pointer. The eDMA handle stores callback function and
1441 * parameters.
1442 * param base eDMA peripheral base address.
1443 * param channel eDMA channel number.
1444 */
EDMA_CreateHandle(edma_handle_t * handle,EDMA_Type * base,uint32_t channel)1445 void EDMA_CreateHandle(edma_handle_t *handle, EDMA_Type *base, uint32_t channel)
1446 {
1447 assert(handle != NULL);
1448 assert(FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base) != -1);
1449 assert(channel < (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));
1450
1451 uint32_t edmaInstance;
1452 edma_tcd_t *tcdRegs;
1453
1454 /* Zero the handle */
1455 (void)memset(handle, 0, sizeof(*handle));
1456
1457 handle->channel = channel;
1458
1459 /* Get the DMA instance number */
1460 edmaInstance = EDMA_GetInstance(base);
1461 s_EDMAHandle[edmaInstance][channel] = handle;
1462 /* Enable NVIC interrupt */
1463 (void)EnableIRQ(s_edmaIRQNumber[edmaInstance][channel]);
1464
1465 handle->tcdBase = EDMA_TCD_BASE(base, channel);
1466 handle->channelBase = EDMA_CHANNEL_BASE(base, channel);
1467 handle->base = base;
1468 /*
1469 Reset TCD registers to zero. Unlike the EDMA_TcdReset(DREQ will be set),
1470 CSR will be 0. Because in order to suit EDMA busy check mechanism in
1471 EDMA_SubmitTransfer, CSR must be set 0.
1472 */
1473 tcdRegs = handle->tcdBase;
1474 EDMA_TCD_SADDR(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1475 EDMA_TCD_SOFF(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1476 EDMA_TCD_ATTR(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1477 EDMA_TCD_NBYTES(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1478 EDMA_TCD_SLAST(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1479 EDMA_TCD_DADDR(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1480 EDMA_TCD_DOFF(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1481 EDMA_TCD_CITER(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1482 EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1483 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1484 EDMA_TCD_BITER(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
1485 }
1486
1487 /*!
1488 * brief Installs the TCDs memory pool into the eDMA handle.
1489 *
1490 * This function is called after the EDMA_CreateHandle to use scatter/gather feature. This function shall only be used
1491 * while users need to use scatter gather mode. Scatter gather mode enables EDMA to load a new transfer control block
1492 * (tcd) in hardware, and automatically reconfigure that DMA channel for a new transfer.
1493 * Users need to prepare tcd memory and also configure tcds using interface EDMA_SubmitTransfer.
1494 *
1495 * param handle eDMA handle pointer.
1496 * param tcdPool A memory pool to store TCDs. It must be 32 bytes aligned.
1497 * param tcdSize The number of TCD slots.
1498 */
EDMA_InstallTCDMemory(edma_handle_t * handle,edma_tcd_t * tcdPool,uint32_t tcdSize)1499 void EDMA_InstallTCDMemory(edma_handle_t *handle, edma_tcd_t *tcdPool, uint32_t tcdSize)
1500 {
1501 assert(handle != NULL);
1502 assert(((uint32_t)tcdPool & 0x1FU) == 0U);
1503
1504 /* Initialize tcd queue attribute. */
1505 /* header should initial as 1, since that it is used to point to the next TCD to be loaded into TCD memory,
1506 * In EDMA driver IRQ handler, header will be used to calculate how many tcd has done, for example,
1507 * If application submit 4 transfer request, A->B->C->D,
1508 * when A finshed, the header is 0, C is the next TCD to be load, since B is already loaded,
1509 * according to EDMA driver IRQ handler, tcdDone = C - A - header = 2 - header = 2, but actually only 1 TCD done,
1510 * so the issue will be the wrong TCD done count will pass to application in first TCD interrupt.
1511 * During first submit, the header should be assigned to 1, since 0 is current one and 1 is next TCD to be loaded,
1512 * but software cannot know which submission is the first one, so assign 1 to header here.
1513 */
1514 handle->header = 1;
1515 handle->tcdUsed = 0;
1516 handle->tcdSize = (int8_t)tcdSize;
1517 handle->tcdPool = tcdPool;
1518 }
1519
1520 /*!
1521 * brief Installs a callback function for the eDMA transfer.
1522 *
1523 * This callback is called in the eDMA IRQ handler. Use the callback to do something after
1524 * the current major loop transfer completes. This function will be called every time one tcd finished transfer.
1525 *
1526 * param handle eDMA handle pointer.
1527 * param callback eDMA callback function pointer.
1528 * param userData A parameter for the callback function.
1529 */
EDMA_SetCallback(edma_handle_t * handle,edma_callback callback,void * userData)1530 void EDMA_SetCallback(edma_handle_t *handle, edma_callback callback, void *userData)
1531 {
1532 assert(handle != NULL);
1533
1534 handle->callback = callback;
1535 handle->userData = userData;
1536 }
1537
EDMA_TransferWidthMapping(uint32_t width)1538 static edma_transfer_size_t EDMA_TransferWidthMapping(uint32_t width)
1539 {
1540 edma_transfer_size_t transferSize = kEDMA_TransferSize1Bytes;
1541
1542 /* map width to register value */
1543 switch (width)
1544 {
1545 /* width 8bit */
1546 case 1U:
1547 transferSize = kEDMA_TransferSize1Bytes;
1548 break;
1549 /* width 16bit */
1550 case 2U:
1551 transferSize = kEDMA_TransferSize2Bytes;
1552 break;
1553 /* width 32bit */
1554 case 4U:
1555 transferSize = kEDMA_TransferSize4Bytes;
1556 break;
1557 #if (defined(FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER)
1558 /* width 64bit */
1559 case 8U:
1560 transferSize = kEDMA_TransferSize8Bytes;
1561 break;
1562 #endif
1563 #if (defined(FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER)
1564 /* width 128bit */
1565 case 16U:
1566 transferSize = kEDMA_TransferSize16Bytes;
1567 break;
1568 #endif
1569 /* width 256bit */
1570 case 32U:
1571 transferSize = kEDMA_TransferSize32Bytes;
1572 break;
1573 #if (defined(FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER)
1574 /* width 512bit */
1575 case 64U:
1576 transferSize = kEDMA_TransferSize64Bytes;
1577 break;
1578 #endif
1579 #if (defined(FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER)
1580 /* width 1024bit */
1581 case 128U:
1582 transferSize = kEDMA_TransferSize128Bytes;
1583 break;
1584 #endif
1585 default:
1586 /* All the cases have been listed above, the default clause should not be reached. */
1587 assert(false);
1588 break;
1589 }
1590
1591 return transferSize;
1592 }
1593
1594 /*!
1595 * brief Prepares the eDMA transfer structure configurations.
1596 *
1597 * This function prepares the transfer configuration structure according to the user input.
1598 *
1599 * param config The user configuration structure of type edma_transfer_t.
1600 * param srcAddr eDMA transfer source address.
1601 * param srcWidth eDMA transfer source address width(bytes).
1602 * param srcOffset source address offset.
1603 * param destAddr eDMA transfer destination address.
1604 * param destWidth eDMA transfer destination address width(bytes).
1605 * param destOffset destination address offset.
1606 * param bytesEachRequest eDMA transfer bytes per channel request.
1607 * param transferBytes eDMA transfer bytes to be transferred.
1608 * note The data address and the data width must be consistent. For example, if the SRC
1609 * is 4 bytes, the source address must be 4 bytes aligned, or it results in
1610 * source address error (SAE).
1611 * User can check if 128 bytes support is available for specific instance by
1612 * FSL_FEATURE_EDMA_INSTANCE_SUPPORT_128_BYTES_TRANSFERn.
1613 */
EDMA_PrepareTransferConfig(edma_transfer_config_t * config,void * srcAddr,uint32_t srcWidth,int16_t srcOffset,void * destAddr,uint32_t destWidth,int16_t destOffset,uint32_t bytesEachRequest,uint32_t transferBytes)1614 void EDMA_PrepareTransferConfig(edma_transfer_config_t *config,
1615 void *srcAddr,
1616 uint32_t srcWidth,
1617 int16_t srcOffset,
1618 void *destAddr,
1619 uint32_t destWidth,
1620 int16_t destOffset,
1621 uint32_t bytesEachRequest,
1622 uint32_t transferBytes)
1623 {
1624 assert(config != NULL);
1625 assert(srcAddr != NULL);
1626 assert(destAddr != NULL);
1627 #if (defined(FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER)
1628 assert((srcWidth != 0U) && (srcWidth <= 128U) && ((srcWidth & (srcWidth - 1U)) == 0U));
1629 assert((destWidth != 0U) && (destWidth <= 128U) && ((destWidth & (destWidth - 1U)) == 0U));
1630 #elif (defined(FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER)
1631 assert((srcWidth != 0U) && (srcWidth <= 64U) && ((srcWidth & (srcWidth - 1U)) == 0U));
1632 assert((destWidth != 0U) && (destWidth <= 64U) && ((destWidth & (destWidth - 1U)) == 0U));
1633 #else
1634 assert((srcWidth != 0U) && (srcWidth <= 32U) && ((srcWidth & (srcWidth - 1U)) == 0U));
1635 assert((destWidth != 0U) && (destWidth <= 32U) && ((destWidth & (destWidth - 1U)) == 0U));
1636 #endif
1637 #if (!defined(FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER) || !FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER)
1638 assert(srcWidth != 8U);
1639 assert(srcWidth != 8U);
1640 #endif
1641 #if (!defined(FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER) || !FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER)
1642 assert(srcWidth != 16U);
1643 assert(srcWidth != 16U);
1644 #endif
1645 #if (!defined(FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER) || !FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER)
1646 assert(srcWidth != 64U);
1647 assert(srcWidth != 64U);
1648 #endif
1649 assert((transferBytes % bytesEachRequest) == 0U);
1650 assert((((uint32_t)(uint8_t *)srcAddr) % srcWidth) == 0U);
1651 assert((((uint32_t)(uint8_t *)destAddr) % destWidth) == 0U);
1652
1653 /* Initializes the configure structure to zero. */
1654 (void)memset(config, 0, sizeof(*config));
1655
1656 config->destAddr = CONVERT_TO_DMA_ADDRESS((uint32_t)(uint32_t *)destAddr);
1657 config->srcAddr = CONVERT_TO_DMA_ADDRESS((uint32_t)(uint32_t *)srcAddr);
1658 config->minorLoopBytes = bytesEachRequest;
1659 config->majorLoopCounts = transferBytes / bytesEachRequest;
1660 config->srcTransferSize = EDMA_TransferWidthMapping(srcWidth);
1661 config->destTransferSize = EDMA_TransferWidthMapping(destWidth);
1662 config->destOffset = destOffset;
1663 config->srcOffset = srcOffset;
1664 /* enable major interrupt by default */
1665 config->enabledInterruptMask = (uint16_t)kEDMA_MajorInterruptEnable;
1666 }
1667
1668 /*!
1669 * brief Prepares the eDMA transfer structure.
1670 *
1671 * This function prepares the transfer configuration structure according to the user input.
1672 *
1673 * param config The user configuration structure of type edma_transfer_t.
1674 * param srcAddr eDMA transfer source address.
1675 * param srcWidth eDMA transfer source address width(bytes).
1676 * param destAddr eDMA transfer destination address.
1677 * param destWidth eDMA transfer destination address width(bytes).
1678 * param bytesEachRequest eDMA transfer bytes per channel request.
1679 * param transferBytes eDMA transfer bytes to be transferred.
1680 * param type eDMA transfer type.
1681 * note The data address and the data width must be consistent. For example, if the SRC
1682 * is 4 bytes, the source address must be 4 bytes aligned, or it results in
1683 * source address error (SAE).
1684 */
EDMA_PrepareTransfer(edma_transfer_config_t * config,void * srcAddr,uint32_t srcWidth,void * destAddr,uint32_t destWidth,uint32_t bytesEachRequest,uint32_t transferBytes,edma_transfer_type_t type)1685 void EDMA_PrepareTransfer(edma_transfer_config_t *config,
1686 void *srcAddr,
1687 uint32_t srcWidth,
1688 void *destAddr,
1689 uint32_t destWidth,
1690 uint32_t bytesEachRequest,
1691 uint32_t transferBytes,
1692 edma_transfer_type_t type)
1693 {
1694 assert(config != NULL);
1695
1696 int16_t srcOffset = 0, destOffset = 0;
1697
1698 switch (type)
1699 {
1700 case kEDMA_MemoryToMemory:
1701 destOffset = (int16_t)destWidth;
1702 srcOffset = (int16_t)srcWidth;
1703 break;
1704 case kEDMA_MemoryToPeripheral:
1705 destOffset = 0;
1706 srcOffset = (int16_t)srcWidth;
1707 break;
1708 case kEDMA_PeripheralToMemory:
1709 destOffset = (int16_t)destWidth;
1710 srcOffset = 0;
1711 break;
1712 case kEDMA_PeripheralToPeripheral:
1713 destOffset = 0;
1714 srcOffset = 0;
1715 break;
1716 default:
1717 /* All the cases have been listed above, the default clause should not be reached. */
1718 assert(false);
1719 break;
1720 }
1721
1722 EDMA_PrepareTransferConfig(config, srcAddr, srcWidth, srcOffset, destAddr, destWidth, destOffset, bytesEachRequest,
1723 transferBytes);
1724 }
1725
1726 /*!
1727 * brief Prepares the eDMA transfer content descriptor.
1728 *
1729 * This function prepares the transfer content descriptor structure according to the user input.
1730 *
1731 * param handle eDMA handle pointer.
1732 * param tcd Pointer to eDMA transfer content descriptor structure.
1733 * param srcAddr eDMA transfer source address.
1734 * param srcWidth eDMA transfer source address width(bytes).
1735 * param srcOffset source address offset.
1736 * param destAddr eDMA transfer destination address.
1737 * param destWidth eDMA transfer destination address width(bytes).
1738 * param destOffset destination address offset.
1739 * param bytesEachRequest eDMA transfer bytes per channel request.
1740 * param transferBytes eDMA transfer bytes to be transferred.
1741 * param nextTcd eDMA transfer linked TCD address.
1742 *
1743 * note The data address and the data width must be consistent. For example, if the SRC
1744 * is 4 bytes, the source address must be 4 bytes aligned, or it results in
1745 * source address error (SAE).
1746 */
EDMA_PrepareTransferTCD(edma_handle_t * handle,edma_tcd_t * tcd,void * srcAddr,uint32_t srcWidth,int16_t srcOffset,void * destAddr,uint32_t destWidth,int16_t destOffset,uint32_t bytesEachRequest,uint32_t transferBytes,edma_tcd_t * nextTcd)1747 void EDMA_PrepareTransferTCD(edma_handle_t *handle,
1748 edma_tcd_t *tcd,
1749 void *srcAddr,
1750 uint32_t srcWidth,
1751 int16_t srcOffset,
1752 void *destAddr,
1753 uint32_t destWidth,
1754 int16_t destOffset,
1755 uint32_t bytesEachRequest,
1756 uint32_t transferBytes,
1757 edma_tcd_t *nextTcd)
1758 {
1759 assert(tcd != NULL);
1760 assert(srcAddr != NULL);
1761 assert(destAddr != NULL);
1762 #if (defined(FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER)
1763 assert((srcWidth != 0U) && (srcWidth <= 128U) && ((srcWidth & (srcWidth - 1U)) == 0U) &&
1764 (FSL_FEATURE_EDMA_INSTANCE_SUPPORT_128_BYTES_TRANSFERn(handle->base) == 1));
1765 assert((destWidth != 0U) && (destWidth <= 128U) && ((destWidth & (destWidth - 1U)) == 0U) &&
1766 (FSL_FEATURE_EDMA_INSTANCE_SUPPORT_128_BYTES_TRANSFERn(handle->base) == 1));
1767 #elif (defined(FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER)
1768 assert((srcWidth != 0U) && (srcWidth <= 64U) && ((srcWidth & (srcWidth - 1U)) == 0U));
1769 assert((destWidth != 0U) && (destWidth <= 64U) && ((destWidth & (destWidth - 1U)) == 0U));
1770 #else
1771 assert((srcWidth != 0U) && (srcWidth <= 32U) && ((srcWidth & (srcWidth - 1U)) == 0U));
1772 assert((destWidth != 0U) && (destWidth <= 32U) && ((destWidth & (destWidth - 1U)) == 0U));
1773 #endif
1774 #if (!defined(FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER) || !FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER)
1775 assert(srcWidth != 8U);
1776 assert(srcWidth != 8U);
1777 #endif
1778 #if (!defined(FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER) || !FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER)
1779 assert(srcWidth != 16U);
1780 assert(srcWidth != 16U);
1781 #endif
1782 #if (!defined(FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER) || !FSL_FEATURE_EDMA_SUPPORT_64_BYTES_TRANSFER)
1783 assert(srcWidth != 64U);
1784 assert(srcWidth != 64U);
1785 #endif
1786 assert((transferBytes % bytesEachRequest) == 0U);
1787 assert((((uint32_t)(uint32_t *)srcAddr) % srcWidth) == 0U);
1788 assert((((uint32_t)(uint32_t *)destAddr) % destWidth) == 0U);
1789
1790 edma_transfer_size_t srcTransferSize = EDMA_TransferWidthMapping(srcWidth),
1791 destTransferSize = EDMA_TransferWidthMapping(srcWidth);
1792
1793 /* Initializes the configure structure to zero. */
1794 EDMA_TcdResetExt(handle->base, tcd);
1795 assert((bytesEachRequest % (1UL << ((uint32_t)srcTransferSize))) == 0U);
1796 assert((bytesEachRequest % (1UL << ((uint32_t)destTransferSize))) == 0U);
1797 assert(((uint32_t)srcOffset % (1UL << ((uint32_t)srcTransferSize))) == 0U);
1798 assert(((uint32_t)destOffset % (1UL << ((uint32_t)destTransferSize))) == 0U);
1799 assert(((uint32_t)(uint32_t *)srcAddr % (1UL << ((uint32_t)srcTransferSize))) == 0U);
1800 assert(((uint32_t)(uint32_t *)destAddr % (1UL << ((uint32_t)destTransferSize))) == 0U);
1801
1802 EDMA_TCD_SADDR(tcd, EDMA_TCD_TYPE(handle->base)) = CONVERT_TO_DMA_ADDRESS((uint32_t *)srcAddr);
1803 /* destination address */
1804 EDMA_TCD_DADDR(tcd, EDMA_TCD_TYPE(handle->base)) = CONVERT_TO_DMA_ADDRESS((uint32_t *)destAddr);
1805 /* Source data and destination data transfer size */
1806 EDMA_TCD_ATTR(tcd, EDMA_TCD_TYPE(handle->base)) = DMA_ATTR_SSIZE(srcTransferSize) | DMA_ATTR_DSIZE(destTransferSize);
1807
1808 /* Source address signed offset */
1809 EDMA_TCD_SOFF(tcd, EDMA_TCD_TYPE(handle->base)) = (uint16_t)(srcOffset);
1810 /* Destination address signed offset */
1811 EDMA_TCD_DOFF(tcd, EDMA_TCD_TYPE(handle->base)) = (uint16_t)(destOffset);
1812
1813 EDMA_TCD_NBYTES(tcd, EDMA_TCD_TYPE(handle->base)) = DMA_NBYTES_MLOFFNO_NBYTES(bytesEachRequest);
1814
1815 /* Current major iteration count */
1816 EDMA_TCD_CITER(tcd, EDMA_TCD_TYPE(handle->base)) = (uint16_t)(transferBytes / bytesEachRequest);
1817 /* Starting major iteration count */
1818 EDMA_TCD_BITER(tcd, EDMA_TCD_TYPE(handle->base)) = (uint16_t)(transferBytes / bytesEachRequest);
1819 /* reset CSR firstly */
1820 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(handle->base)) = DMA_CSR_DREQ(1U);
1821 /* Enable scatter/gather processing */
1822 if (nextTcd != NULL)
1823 {
1824 EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(handle->base)) = CONVERT_TO_DMA_ADDRESS(nextTcd);
1825 /*
1826 Before call EDMA_TcdSetTransferConfig or EDMA_SetTransferConfig,
1827 user must call EDMA_TcdReset or EDMA_ResetChannel which will set
1828 DREQ, so must use "|" or "&" rather than "=".
1829
1830 Clear the DREQ bit because scatter gather has been enabled, so the
1831 previous transfer is not the last transfer, and channel request should
1832 be enabled at the next transfer(the next TCD).
1833 */
1834 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(handle->base)) =
1835 (EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(handle->base)) | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
1836 }
1837
1838 /* configure interrupt/auto disable channel request, enable major interrupt by default */
1839 EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(handle->base)) |=
1840 (EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(handle->base)) & (~(uint16_t)kEDMA_ErrorInterruptEnable)) |
1841 (uint16_t)kEDMA_MajorInterruptEnable;
1842 }
1843
1844 /*!
1845 * brief Submits the eDMA transfer content descriptor.
1846 *
1847 * This function submits the eDMA transfer request according to the transfer content descriptor.
1848 * In scatter gather mode, call this function will add a configured tcd to the circular list of tcd pool.
1849 * The tcd pools is setup by call function EDMA_InstallTCDMemory before.
1850 *
1851 * Typical user case:
1852 * 1. submit single transfer
1853 * code
1854 * edma_tcd_t tcd;
1855 * EDMA_PrepareTransferTCD(handle, tcd, ....)
1856 * EDMA_SubmitTransferTCD(handle, tcd)
1857 * EDMA_StartTransfer(handle)
1858 * endcode
1859 *
1860 * 2. submit static link transfer,
1861 * code
1862 * edma_tcd_t tcd[2];
1863 * EDMA_PrepareTransferTCD(handle, &tcd[0], ....)
1864 * EDMA_PrepareTransferTCD(handle, &tcd[1], ....)
1865 * EDMA_SubmitTransferTCD(handle, &tcd[0])
1866 * EDMA_StartTransfer(handle)
1867 * endcode
1868 *
1869 * 3. submit dynamic link transfer
1870 * code
1871 * edma_tcd_t tcdpool[2];
1872 * EDMA_InstallTCDMemory(&g_DMA_Handle, tcdpool, 2);
1873 * edma_tcd_t tcd;
1874 * EDMA_PrepareTransferTCD(handle, tcd, ....)
1875 * EDMA_SubmitTransferTCD(handle, tcd)
1876 * EDMA_PrepareTransferTCD(handle, tcd, ....)
1877 * EDMA_SubmitTransferTCD(handle, tcd)
1878 * EDMA_StartTransfer(handle)
1879 * endcode
1880 *
1881 * 4. submit loop transfer
1882 * code
1883 * edma_tcd_t tcd[2];
1884 * EDMA_PrepareTransferTCD(handle, &tcd[0], ...,&tcd[1])
1885 * EDMA_PrepareTransferTCD(handle, &tcd[1], ..., &tcd[0])
1886 * EDMA_SubmitTransferTCD(handle, &tcd[0])
1887 * EDMA_StartTransfer(handle)
1888 * endcode
1889 *
1890 * param handle eDMA handle pointer.
1891 * param tcd Pointer to eDMA transfer content descriptor structure.
1892 *
1893 * retval kStatus_EDMA_Success It means submit transfer request succeed.
1894 * retval kStatus_EDMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
1895 * retval kStatus_EDMA_Busy It means the given channel is busy, need to submit request later.
1896 */
EDMA_SubmitTransferTCD(edma_handle_t * handle,edma_tcd_t * tcd)1897 status_t EDMA_SubmitTransferTCD(edma_handle_t *handle, edma_tcd_t *tcd)
1898 {
1899 assert(handle != NULL);
1900 assert(handle->tcdBase != NULL);
1901
1902 edma_tcd_t *tcdRegs = handle->tcdBase;
1903
1904 if (handle->tcdPool == NULL)
1905 {
1906 /*
1907 * Check if EDMA channel is busy:
1908 * 1. if channel active bit is set, it implies that minor loop is executing, then channel is busy
1909 * 2. if channel active bit is not set and BITER not equal to CITER, it implies that major loop is executing,
1910 * then channel is busy
1911 *
1912 * There is one case can not be covered in below condition:
1913 * When transfer request is submitted, but no request from peripheral, that is to say channel sevice doesn't
1914 * begin, if application would like to submit another transfer , then the TCD will be overwritten, since the
1915 * ACTIVE is 0 and BITER = CITER, for such case, it is a scatter gather(link TCD) case actually, so
1916 * application should enabled TCD pool for dynamic scatter gather mode by calling EDMA_InstallTCDMemory.
1917 */
1918 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
1919 if (((tcdRegs->CSR & DMA_CSR_ACTIVE_MASK) != 0U) ||
1920 #else
1921 if (((handle->channelBase->CH_CSR & DMA_CH_CSR_ACTIVE_MASK) != 0U) ||
1922 #endif
1923 (((EDMA_TCD_CITER(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_CITER_ELINKNO_CITER_MASK) !=
1924 (EDMA_TCD_BITER(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_BITER_ELINKNO_BITER_MASK))))
1925 {
1926 return kStatus_EDMA_Busy;
1927 }
1928 else
1929 {
1930 EDMA_InstallTCD(handle->base, handle->channel, tcd);
1931 /* Enable auto disable request feature */
1932 EDMA_EnableAutoStopRequest(handle->base, handle->channel, true);
1933 /* Enable major interrupt */
1934 EDMA_EnableChannelInterrupts(handle->base, handle->channel, kEDMA_MajorInterruptEnable);
1935
1936 return kStatus_Success;
1937 }
1938 }
1939 else /* Use the TCD queue. */
1940 {
1941 uint32_t primask;
1942 uint16_t csr;
1943 int8_t currentTcd;
1944 int8_t previousTcd;
1945 int8_t nextTcd;
1946 int8_t tmpTcdUsed;
1947 int8_t tmpTcdSize;
1948
1949 /* Check if tcd pool is full. */
1950 primask = DisableGlobalIRQ();
1951 tmpTcdUsed = handle->tcdUsed;
1952 tmpTcdSize = handle->tcdSize;
1953 if (tmpTcdUsed >= tmpTcdSize)
1954 {
1955 EnableGlobalIRQ(primask);
1956
1957 return kStatus_EDMA_QueueFull;
1958 }
1959 currentTcd = handle->tail;
1960 handle->tcdUsed++;
1961 /* Calculate index of next TCD */
1962 nextTcd = currentTcd + 1;
1963 if (nextTcd == handle->tcdSize)
1964 {
1965 nextTcd = 0;
1966 }
1967 /* Advance queue tail index */
1968 handle->tail = nextTcd;
1969 EnableGlobalIRQ(primask);
1970 /* Calculate index of previous TCD */
1971 previousTcd = currentTcd != 0 ? currentTcd - 1 : (handle->tcdSize - 1);
1972
1973 /* Configure current TCD block. */
1974 EDMA_TcdResetExt(handle->base, &handle->tcdPool[currentTcd]);
1975 (void)memcpy(&handle->tcdPool[currentTcd], tcd, sizeof(edma_tcd_t));
1976
1977 /* Enable major interrupt */
1978 EDMA_TCD_CSR((&handle->tcdPool[currentTcd]), EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_INTMAJOR_MASK;
1979
1980 if ((EDMA_TCD_DLAST_SGA(tcd, EDMA_TCD_TYPE(handle->base)) == 0U) ||
1981 ((EDMA_TCD_CSR(tcd, EDMA_TCD_TYPE(handle->base)) & DMA_CSR_ESG_MASK) == 0U))
1982 {
1983 /* Link current TCD with next TCD for identification of current TCD */
1984 EDMA_TCD_DLAST_SGA((&handle->tcdPool[currentTcd]), EDMA_TCD_TYPE(handle->base)) =
1985 CONVERT_TO_DMA_ADDRESS((uint32_t)&handle->tcdPool[nextTcd]);
1986 }
1987
1988 /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
1989 if (currentTcd != previousTcd)
1990 {
1991 #if defined FSL_FEATURE_EDMA_HAS_ERRATA_51327
1992 if (EDMA_CheckErrata(handle->base, &handle->tcdPool[previousTcd]) != kStatus_Success)
1993 {
1994 return kStatus_InvalidArgument;
1995 }
1996 #endif
1997 /* Enable scatter/gather feature in the previous TCD block. */
1998 csr = EDMA_TCD_CSR((&handle->tcdPool[previousTcd]), EDMA_TCD_TYPE(handle->base)) |
1999 ((uint16_t)DMA_CSR_ESG_MASK);
2000 csr &= ~((uint16_t)DMA_CSR_DREQ_MASK);
2001 EDMA_TCD_CSR((&handle->tcdPool[previousTcd]), EDMA_TCD_TYPE(handle->base)) = csr;
2002 /*
2003 Check if the TCD block in the registers is the previous one (points to current TCD block). It
2004 is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
2005 link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
2006 before link the previous TCD block.
2007 */
2008 if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) ==
2009 CONVERT_TO_DMA_ADDRESS((uint32_t)&handle->tcdPool[currentTcd]))
2010 {
2011 /* Clear the DREQ bits for the dynamic scatter gather */
2012 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_DREQ_MASK;
2013 /* Enable scatter/gather also in the TCD registers. */
2014 csr = EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) | DMA_CSR_ESG_MASK;
2015 /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
2016 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) = csr;
2017 /*
2018 It is very important to check the ESG bit!
2019 Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
2020 be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
2021 and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
2022 the current TCD block has been loaded into TCD registers), it means transfer finished
2023 and TCD link operation fail, so must install TCD content into TCD registers and enable
2024 transfer again. And if ESG is set, it means transfer has not finished, so TCD dynamic
2025 link succeed.
2026 */
2027 if (0U != (EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_CSR_ESG_MASK))
2028 {
2029 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) &= ~(uint16_t)DMA_CSR_DREQ_MASK;
2030 return kStatus_Success;
2031 }
2032 /*
2033 Check whether the current TCD block is already loaded in the TCD registers. It is another
2034 condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
2035 TCD block has been loaded into TCD registers.
2036 */
2037 if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) ==
2038 CONVERT_TO_DMA_ADDRESS((uint32_t)&handle->tcdPool[nextTcd]))
2039 {
2040 return kStatus_Success;
2041 }
2042 /*
2043 If go to this, means the previous transfer finished, and the DONE bit is set.
2044 So shall configure TCD registers.
2045 */
2046 }
2047 else if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) != 0UL)
2048 {
2049 /* The current TCD block has been linked successfully. */
2050 return kStatus_Success;
2051 }
2052 else
2053 {
2054 /*
2055 DLAST_SGA is 0 and it means the first submit transfer, so shall configure
2056 TCD registers.
2057 */
2058 }
2059 }
2060 /* There is no live chain, TCD block need to be installed in TCD registers. */
2061 EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
2062
2063 return kStatus_Success;
2064 }
2065 }
2066
2067 /*!
2068 * brief Submits the eDMA transfer request.
2069 *
2070 * This function submits the eDMA transfer request according to the transfer configuration structure.
2071 * In scatter gather mode, call this function will add a configured tcd to the circular list of tcd pool.
2072 * The tcd pools is setup by call function EDMA_InstallTCDMemory before.
2073 *
2074 * param handle eDMA handle pointer.
2075 * param config Pointer to eDMA transfer configuration structure.
2076 * retval kStatus_EDMA_Success It means submit transfer request succeed.
2077 * retval kStatus_EDMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
2078 * retval kStatus_EDMA_Busy It means the given channel is busy, need to submit request later.
2079 */
EDMA_SubmitTransfer(edma_handle_t * handle,const edma_transfer_config_t * config)2080 status_t EDMA_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config)
2081 {
2082 assert(handle != NULL);
2083 assert(config != NULL);
2084 assert(handle->tcdBase != NULL);
2085 #if (defined(FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_128_BYTES_TRANSFER)
2086 assert(((config->srcTransferSize != kEDMA_TransferSize128Bytes) &&
2087 (config->destTransferSize != kEDMA_TransferSize128Bytes)) ||
2088 (FSL_FEATURE_EDMA_INSTANCE_SUPPORT_128_BYTES_TRANSFERn(handle->base) == 1));
2089 #endif
2090 edma_tcd_t *tcdRegs = handle->tcdBase;
2091
2092 if (handle->tcdPool == NULL)
2093 {
2094 /*
2095 * Check if EDMA channel is busy:
2096 * 1. if channel active bit is set, it implies that minor loop is executing, then channel is busy
2097 * 2. if channel active bit is not set and BITER not equal to CITER, it implies that major loop is executing,
2098 * then channel is busy
2099 *
2100 * There is one case can not be covered in below condition:
2101 * When transfer request is submitted, but no request from peripheral, that is to say channel sevice doesn't
2102 * begin, if application would like to submit another transfer , then the TCD will be overwritten, since the
2103 * ACTIVE is 0 and BITER = CITER, for such case, it is a scatter gather(link TCD) case actually, so
2104 * application should enabled TCD pool for dynamic scatter gather mode by calling EDMA_InstallTCDMemory.
2105 */
2106 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2107 if (((tcdRegs->CSR & DMA_CSR_ACTIVE_MASK) != 0U) ||
2108 #else
2109 if (((handle->channelBase->CH_CSR & DMA_CH_CSR_ACTIVE_MASK) != 0U) ||
2110 #endif
2111 (((EDMA_TCD_CITER(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_CITER_ELINKNO_CITER_MASK) !=
2112 (EDMA_TCD_BITER(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_BITER_ELINKNO_BITER_MASK))))
2113 {
2114 return kStatus_EDMA_Busy;
2115 }
2116 else
2117 {
2118 EDMA_TcdSetTransferConfigExt(handle->base, tcdRegs, config, NULL);
2119 /* Enable auto disable request feature */
2120 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_DREQ_MASK;
2121 /* Enable major interrupt */
2122 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_INTMAJOR_MASK;
2123
2124 return kStatus_Success;
2125 }
2126 }
2127 else /* Use the TCD queue. */
2128 {
2129 uint32_t primask;
2130 uint16_t csr;
2131 int8_t currentTcd;
2132 int8_t previousTcd;
2133 int8_t nextTcd;
2134 int8_t tmpTcdUsed;
2135 int8_t tmpTcdSize;
2136
2137 /* Check if tcd pool is full. */
2138 primask = DisableGlobalIRQ();
2139 tmpTcdUsed = handle->tcdUsed;
2140 tmpTcdSize = handle->tcdSize;
2141 if (tmpTcdUsed >= tmpTcdSize)
2142 {
2143 EnableGlobalIRQ(primask);
2144
2145 return kStatus_EDMA_QueueFull;
2146 }
2147 currentTcd = handle->tail;
2148 handle->tcdUsed++;
2149 /* Calculate index of next TCD */
2150 nextTcd = currentTcd + 1;
2151 if (nextTcd == handle->tcdSize)
2152 {
2153 nextTcd = 0;
2154 }
2155 /* Advance queue tail index */
2156 handle->tail = nextTcd;
2157 EnableGlobalIRQ(primask);
2158 /* Calculate index of previous TCD */
2159 previousTcd = currentTcd != 0 ? currentTcd - 1 : (handle->tcdSize - 1);
2160 /* Configure current TCD block. */
2161 EDMA_TcdResetExt(handle->base, &handle->tcdPool[currentTcd]);
2162 EDMA_TcdSetTransferConfigExt(handle->base, &handle->tcdPool[currentTcd], config, NULL);
2163 /* Enable major interrupt */
2164 EDMA_TCD_CSR((&handle->tcdPool[currentTcd]), EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_INTMAJOR_MASK;
2165 /* Link current TCD with next TCD for identification of current TCD */
2166 EDMA_TCD_DLAST_SGA((&handle->tcdPool[currentTcd]), EDMA_TCD_TYPE(handle->base)) =
2167 CONVERT_TO_DMA_ADDRESS((uint32_t)&handle->tcdPool[nextTcd]);
2168 /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
2169 if (currentTcd != previousTcd)
2170 {
2171 #if defined FSL_FEATURE_EDMA_HAS_ERRATA_51327
2172 if (EDMA_CheckErrata(handle->base, &handle->tcdPool[previousTcd]) != kStatus_Success)
2173 {
2174 return kStatus_InvalidArgument;
2175 }
2176 #endif
2177 /* Enable scatter/gather feature in the previous TCD block. */
2178 csr = EDMA_TCD_CSR((&handle->tcdPool[previousTcd]), EDMA_TCD_TYPE(handle->base)) |
2179 ((uint16_t)DMA_CSR_ESG_MASK);
2180 csr &= ~((uint16_t)DMA_CSR_DREQ_MASK);
2181 EDMA_TCD_CSR((&handle->tcdPool[previousTcd]), EDMA_TCD_TYPE(handle->base)) = csr;
2182 /*
2183 Check if the TCD block in the registers is the previous one (points to current TCD block). It
2184 is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
2185 link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
2186 before link the previous TCD block.
2187 */
2188 if (EDMA_TCD_DLAST_SGA(handle->tcdBase, EDMA_TCD_TYPE(handle->base)) ==
2189 CONVERT_TO_DMA_ADDRESS((uint32_t)&handle->tcdPool[currentTcd]))
2190 {
2191 /* Clear the DREQ bits for the dynamic scatter gather */
2192 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_DREQ_MASK;
2193 /* Enable scatter/gather also in the TCD registers. */
2194 csr = EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) | DMA_CSR_ESG_MASK;
2195 /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
2196 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) = csr;
2197 /*
2198 It is very important to check the ESG bit!
2199 Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
2200 be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
2201 and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
2202 the current TCD block has been loaded into TCD registers), it means transfer finished
2203 and TCD link operation fail, so must install TCD content into TCD registers and enable
2204 transfer again. And if ESG is set, it means transfer has not finished, so TCD dynamic
2205 link succeed.
2206 */
2207 if (0U != (EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_CSR_ESG_MASK))
2208 {
2209 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) &= ~(uint16_t)DMA_CSR_DREQ_MASK;
2210 return kStatus_Success;
2211 }
2212 /*
2213 Check whether the current TCD block is already loaded in the TCD registers. It is another
2214 condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
2215 TCD block has been loaded into TCD registers.
2216 */
2217 if (EDMA_TCD_DLAST_SGA(handle->tcdBase, EDMA_TCD_TYPE(handle->base)) ==
2218 CONVERT_TO_DMA_ADDRESS((uint32_t)&handle->tcdPool[nextTcd]))
2219 {
2220 return kStatus_Success;
2221 }
2222 /*
2223 If go to this, means the previous transfer finished, and the DONE bit is set.
2224 So shall configure TCD registers.
2225 */
2226 }
2227 else if (EDMA_TCD_DLAST_SGA(handle->tcdBase, EDMA_TCD_TYPE(handle->base)) != 0UL)
2228 {
2229 /* The current TCD block has been linked successfully. */
2230 return kStatus_Success;
2231 }
2232 else
2233 {
2234 /*
2235 DLAST_SGA is 0 and it means the first submit transfer, so shall configure
2236 TCD registers.
2237 */
2238 }
2239 }
2240 /* There is no live chain, TCD block need to be installed in TCD registers. */
2241 EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
2242
2243 return kStatus_Success;
2244 }
2245 }
2246
2247 /*!
2248 * brief Submits the eDMA scatter gather transfer configurations.
2249 *
2250 * The function is target for submit loop transfer request,
2251 * the ring transfer request means that the transfer request TAIL is link to HEAD, such as,
2252 * A->B->C->D->A, or A->A
2253 *
2254 * To use the ring transfer feature, the application should allocate several transfer object, such as
2255 * @code
2256 * edma_channel_transfer_config_t transfer[2];
2257 * EDMA_TransferSubmitLoopTransfer(handle, &transfer, 2U);
2258 * @endcode
2259 * Then eDMA driver will link transfer[0] and transfer[1] to each other
2260 *
2261 * note Application should check the return value of this function to avoid transfer request
2262 * submit failed
2263 *
2264 * param handle eDMA handle pointer
2265 * param transfer pointer to user's eDMA channel configure structure, see edma_channel_transfer_config_t for detail
2266 * param transferLoopCount the count of the transfer ring, if loop count is 1, that means that the one will link to
2267 * itself.
2268 *
2269 * retval #kStatus_Success It means submit transfer request succeed
2270 * retval #kStatus_EDMA_Busy channel is in busy status
2271 * retval #kStatus_InvalidArgument Invalid Argument
2272 */
EDMA_SubmitLoopTransfer(edma_handle_t * handle,edma_transfer_config_t * transfer,uint32_t transferLoopCount)2273 status_t EDMA_SubmitLoopTransfer(edma_handle_t *handle, edma_transfer_config_t *transfer, uint32_t transferLoopCount)
2274 {
2275 assert(transfer != NULL);
2276 assert(handle != NULL);
2277 assert(handle->tcdPool != NULL);
2278
2279 uint32_t i = 0U;
2280
2281 if (handle->tcdSize < (int8_t)transferLoopCount)
2282 {
2283 return kStatus_InvalidArgument;
2284 }
2285
2286 /*
2287 * Check if EDMA channel is busy:
2288 * 1. if channel active bit is set, it implies that minor loop is executing, then channel is busy
2289 * 2. if channel active bit is not set and BITER not equal to CITER, it implies that major loop is executing,
2290 * then channel is busy
2291 *
2292 * There is one case can not be covered in below condition:
2293 * When transfer request is submitted, but no request from peripheral, that is to say channel service doesn't
2294 * begin, if application would like to submit another transfer , then the TCD will be overwritten, since the
2295 * ACTIVE is 0 and BITER = CITER, for such case, it is a scatter gather(link TCD) case actually, so
2296 * application should enabled TCD pool for dynamic scatter gather mode by calling EDMA_InstallTCDMemory.
2297 */
2298 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2299 if (((handle->tcdBase->CSR & DMA_CSR_ACTIVE_MASK) != 0U) ||
2300 #else
2301 if (((handle->channelBase->CH_CSR & DMA_CH_CSR_ACTIVE_MASK) != 0U) ||
2302 #endif
2303 (((EDMA_TCD_CITER(handle->tcdBase, EDMA_TCD_TYPE(handle->base)) & DMA_CITER_ELINKNO_CITER_MASK) !=
2304 (EDMA_TCD_BITER(handle->tcdBase, EDMA_TCD_TYPE(handle->base)) & DMA_BITER_ELINKNO_BITER_MASK))))
2305 {
2306 return kStatus_EDMA_Busy;
2307 }
2308
2309 (void)memset(handle->tcdPool, 0, (uint32_t)handle->tcdSize * sizeof(edma_tcd_t));
2310 for (i = 0U; i < transferLoopCount - 1UL; i++)
2311 {
2312 transfer[i].linkTCD = &handle->tcdPool[i + 1UL];
2313 EDMA_ConfigChannelSoftwareTCDExt(handle->base, &(handle->tcdPool[i]), &transfer[i]);
2314 #if defined FSL_FEATURE_EDMA_HAS_ERRATA_51327
2315 if (EDMA_CheckErrata(handle->base, &(handle->tcdPool[i])) != kStatus_Success)
2316 {
2317 return kStatus_InvalidArgument;
2318 }
2319 #endif
2320 }
2321
2322 /* prepare last one in the ring and link it to the HEAD of the ring */
2323 transfer[i].linkTCD = &handle->tcdPool[0];
2324 EDMA_ConfigChannelSoftwareTCDExt(handle->base, &(handle->tcdPool[i]), &transfer[i]);
2325
2326 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2327 if (((transfer->enableSrcMinorLoopOffset) || (transfer->enableDstMinorLoopOffset)))
2328 {
2329 EDMA_EnableMinorLoopMapping(handle->psBase, true);
2330 }
2331 #endif
2332 /* There is no live chain, TCD block need to be installed in TCD registers. */
2333 EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[0U]);
2334
2335 /* enable interrupt */
2336 EDMA_EnableChannelInterrupts(handle->base, handle->channel,
2337 ((uint32_t)transfer->enabledInterruptMask & ~((uint32_t)kEDMA_ErrorInterruptEnable)));
2338
2339 return kStatus_Success;
2340 }
2341
2342 /*!
2343 * brief eDMA starts transfer.
2344 *
2345 * This function enables the channel request. Users can call this function after submitting the transfer request
2346 * or before submitting the transfer request.
2347 *
2348 * param handle eDMA handle pointer.
2349 */
EDMA_StartTransfer(edma_handle_t * handle)2350 void EDMA_StartTransfer(edma_handle_t *handle)
2351 {
2352 assert(handle != NULL);
2353
2354 edma_tcd_t *tcdRegs = handle->tcdBase;
2355
2356 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2357 if (handle->tcdPool == NULL)
2358 {
2359 handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
2360 }
2361 else /* Use the TCD queue. */
2362 {
2363 uint32_t primask;
2364
2365 /* Check if there was at least one descriptor submitted since reset (TCD in registers is valid) */
2366 if (tcdRegs->DLAST_SGA != 0U)
2367 {
2368 primask = DisableGlobalIRQ();
2369 /* Check if channel request is actually disable. */
2370 if ((handle->base->ERQ & ((uint32_t)1U << handle->channel)) == 0U)
2371 {
2372 /* Check if transfer is paused. */
2373 tmpCSR = tcdRegs->CSR;
2374 if ((0U == (tmpCSR & DMA_CSR_DONE_MASK)) || (0U != (tmpCSR & DMA_CSR_ESG_MASK)))
2375 {
2376 /*
2377 Re-enable channel request must be as soon as possible, so must put it into
2378 critical section to avoid task switching or interrupt service routine.
2379 */
2380 handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
2381 }
2382 }
2383 EnableGlobalIRQ(primask);
2384 }
2385 }
2386 #else
2387 #if defined FSL_FEATURE_EDMA_HAS_CHANNEL_MUX && FSL_FEATURE_EDMA_HAS_CHANNEL_MUX
2388 #if defined FSL_FEATURE_EDMA_HAS_MP_CHANNEL_MUX && FSL_FEATURE_EDMA_HAS_MP_CHANNEL_MUX
2389 if (((uint32_t)FSL_FEATURE_EDMA_INSTANCE_HAS_CHANNEL_MUXn(handle->base) == 1U) &&
2390 (EDMA_MP_BASE(handle->base)->MP_REGS.EDMA5_REG.CH_MUX[handle->channel] == 0U) &&
2391 (FSL_FEATURE_EDMA_INSTANCE_HAS_MP_CHANNEL_MUXn(handle->base) == 1U))
2392 {
2393 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_START_MASK;
2394 }
2395 else if (((uint32_t)FSL_FEATURE_EDMA_INSTANCE_HAS_CHANNEL_MUXn(handle->base) == 1U) &&
2396 handle->channelBase->CH_REGS.EDMA4_REG.CH_MUX == 0U &&
2397 !(FSL_FEATURE_EDMA_INSTANCE_HAS_MP_CHANNEL_MUXn(handle->base) == 1U))
2398 {
2399 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_START_MASK;
2400 }
2401 else
2402 #else
2403 if (((uint32_t)FSL_FEATURE_EDMA_INSTANCE_HAS_CHANNEL_MUXn(handle->base) == 1U) &&
2404 handle->channelBase->CH_REGS.EDMA4_REG.CH_MUX == 0U)
2405 {
2406 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_START_MASK;
2407 }
2408 else
2409 #endif
2410 #endif
2411 if (handle->tcdPool == NULL)
2412 {
2413 handle->channelBase->CH_CSR |= DMA_CH_CSR_ERQ_MASK;
2414 }
2415 else
2416 {
2417 /* Check if channel request is actually disable. */
2418 if ((handle->channelBase->CH_CSR & DMA_CH_CSR_ERQ_MASK) == 0U)
2419 {
2420 /* Check if transfer is paused. */
2421 if ((!((handle->channelBase->CH_CSR & DMA_CH_CSR_DONE_MASK) != 0U)) ||
2422 ((EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_CSR_ESG_MASK) != 0U))
2423 {
2424 /*
2425 Re-enable channel request must be as soon as possible, so must put it into
2426 critical section to avoid task switching or interrupt service routine.
2427 */
2428 handle->channelBase->CH_CSR |= DMA_CH_CSR_ERQ_MASK;
2429 }
2430 }
2431 }
2432 #endif
2433 }
2434
2435 /*!
2436 * brief eDMA stops transfer.
2437 *
2438 * This function disables the channel request to pause the transfer. Users can call EDMA_StartTransfer()
2439 * again to resume the transfer.
2440 *
2441 * param handle eDMA handle pointer.
2442 */
EDMA_StopTransfer(edma_handle_t * handle)2443 void EDMA_StopTransfer(edma_handle_t *handle)
2444 {
2445 assert(handle != NULL);
2446 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2447 handle->base->CERQ = DMA_CERQ_CERQ(handle->channel);
2448 #else
2449 handle->channelBase->CH_CSR = handle->channelBase->CH_CSR & (~(DMA_CH_CSR_DONE_MASK | DMA_CH_CSR_ERQ_MASK));
2450 #endif
2451 }
2452
2453 /*!
2454 * brief eDMA aborts transfer.
2455 *
2456 * This function disables the channel request and clear transfer status bits.
2457 * Users can submit another transfer after calling this API.
2458 *
2459 * param handle DMA handle pointer.
2460 */
EDMA_AbortTransfer(edma_handle_t * handle)2461 void EDMA_AbortTransfer(edma_handle_t *handle)
2462 {
2463 EDMA_StopTransfer(handle);
2464 /*
2465 Clear CSR to release channel. Because if the given channel started transfer,
2466 CSR will be not zero. Because if it is the last transfer, DREQ will be set.
2467 If not, ESG will be set.
2468 */
2469 EDMA_TcdResetExt(handle->base, handle->tcdBase);
2470
2471 /* Handle the tcd */
2472 if (handle->tcdPool != NULL)
2473 {
2474 handle->header = 1;
2475 handle->tail = 0;
2476 handle->tcdUsed = 0;
2477 }
2478 }
2479
2480 /*!
2481 * brief eDMA IRQ handler for the current major loop transfer completion.
2482 *
2483 * This function clears the channel major interrupt flag and calls
2484 * the callback function if it is not NULL.
2485 *
2486 * Note:
2487 * For the case using TCD queue, when the major iteration count is exhausted, additional operations are performed.
2488 * These include the final address adjustments and reloading of the BITER field into the CITER.
2489 * Assertion of an optional interrupt request also occurs at this time, as does a possible fetch of a new TCD from
2490 * memory using the scatter/gather address pointer included in the descriptor (if scatter/gather is enabled).
2491 *
2492 * For instance, when the time interrupt of TCD[0] happens, the TCD[1] has already been loaded into the eDMA engine.
2493 * As sga and sga_index are calculated based on the DLAST_SGA bitfield lies in the TCD_CSR register, the sga_index
2494 * in this case should be 2 (DLAST_SGA of TCD[1] stores the address of TCD[2]). Thus, the "tcdUsed" updated should be
2495 * (tcdUsed - 2U) which indicates the number of TCDs can be loaded in the memory pool (because TCD[0] and TCD[1] have
2496 * been loaded into the eDMA engine at this point already.).
2497 *
2498 * For the last two continuous ISRs in a scatter/gather process, they both load the last TCD (The last ISR does not
2499 * load a new TCD) from the memory pool to the eDMA engine when major loop completes.
2500 * Therefore, ensure that the header and tcdUsed updated are identical for them.
2501 * tcdUsed are both 0 in this case as no TCD to be loaded.
2502 *
2503 * See the "eDMA basic data flow" in the eDMA Functional description section of the Reference Manual for
2504 * further details.
2505 *
2506 * param handle eDMA handle pointer.
2507 */
EDMA_HandleIRQ(edma_handle_t * handle)2508 void EDMA_HandleIRQ(edma_handle_t *handle)
2509 {
2510 assert(handle != NULL);
2511
2512 bool transfer_done;
2513
2514 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2515 /* Check if transfer is already finished. */
2516 transfer_done = ((handle->tcdBase->CSR & DMA_CSR_DONE_MASK) != 0U);
2517 #else
2518 transfer_done = (bool)(handle->channelBase->CH_CSR & DMA_CH_CSR_DONE_MASK);
2519 #endif
2520
2521 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2522 if ((handle->base->INT >> channel) != 0U)
2523 {
2524 handle->base->CINT = channel;
2525 }
2526 #else
2527 if ((handle->channelBase->CH_INT & DMA_CH_INT_INT_MASK) != 0U)
2528 {
2529 handle->channelBase->CH_INT |= DMA_CH_INT_INT_MASK;
2530 }
2531 #endif
2532
2533 if (handle->tcdPool == NULL)
2534 {
2535 if (handle->callback != NULL)
2536 {
2537 (handle->callback)(handle, handle->userData, transfer_done, 0);
2538 }
2539 }
2540 else /* Use the TCD queue. Please refer to the API descriptions in the eDMA header file for detailed information. */
2541 {
2542 uint32_t sga = (uint32_t)EDMA_TCD_DLAST_SGA(handle->tcdBase, EDMA_TCD_TYPE(handle->base));
2543 uint32_t sga_index;
2544 int32_t tcds_done;
2545 uint8_t new_header;
2546 bool esg = ((EDMA_TCD_CSR(handle->tcdBase, EDMA_TCD_TYPE(handle->base)) & DMA_CSR_ESG_MASK) != 0U);
2547
2548 /* Get the offset of the next transfer TCD blocks to be loaded into the eDMA engine. */
2549 sga -= CONVERT_TO_DMA_ADDRESS((uint32_t)handle->tcdPool);
2550 /* Get the index of the next transfer TCD blocks to be loaded into the eDMA engine. */
2551 sga_index = sga / sizeof(edma_tcd_t);
2552 /* Adjust header positions. */
2553 if (transfer_done)
2554 {
2555 /* New header shall point to the next TCD to be loaded (current one is already finished) */
2556 new_header = (uint8_t)sga_index;
2557 }
2558 else
2559 {
2560 /* New header shall point to this descriptor currently loaded (not finished yet) */
2561 new_header = sga_index != 0U ? (uint8_t)sga_index - 1U : (uint8_t)handle->tcdSize - 1U;
2562 }
2563 /* Calculate the number of finished TCDs */
2564 if (new_header == (uint8_t)handle->header)
2565 {
2566 int8_t tmpTcdUsed = handle->tcdUsed;
2567 int8_t tmpTcdSize = handle->tcdSize;
2568
2569 /* check esg here for the case that application submit only one request, once the request complete:
2570 * new_header(1) = handle->header(1)
2571 * tcdUsed(1) != tcdSize(>1)
2572 * As the application submit only once, so scatter gather must not enabled, then tcds_done should be 1
2573 */
2574 if ((tmpTcdUsed == tmpTcdSize) || (!esg))
2575 {
2576 tcds_done = handle->tcdUsed;
2577 }
2578 else
2579 {
2580 /* No TCD in the memory are going to be loaded or internal error occurs. */
2581 tcds_done = 0;
2582 }
2583 }
2584 else
2585 {
2586 tcds_done = (int32_t)new_header - (int32_t)handle->header;
2587 if (tcds_done < 0)
2588 {
2589 tcds_done += handle->tcdSize;
2590 }
2591 /*
2592 * While code run to here, it means a TCD transfer Done and a new TCD has loaded to the hardware
2593 * so clear DONE here to allow submit scatter gather transfer request in the callback to avoid TCD
2594 * overwritten.
2595 */
2596 if (transfer_done)
2597 {
2598 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2599 handle->base->CDNE = handle->channel;
2600 #else
2601 handle->channelBase->CH_CSR |= DMA_CH_CSR_DONE_MASK;
2602 #endif
2603 }
2604 }
2605 /* Advance header which points to the TCD to be loaded into the eDMA engine from memory. */
2606 handle->header = (int8_t)new_header;
2607 /* Release TCD blocks. tcdUsed is the TCD number which can be used/loaded in the memory pool. */
2608 handle->tcdUsed -= (int8_t)tcds_done;
2609 /* Invoke callback function. */
2610 if (NULL != handle->callback)
2611 {
2612 (handle->callback)(handle, handle->userData, transfer_done, tcds_done);
2613 }
2614
2615 /*
2616 * 1.clear the DONE bit here is meaningful for below cases:
2617 * A new TCD has been loaded to EDMA already:
2618 * need to clear the DONE bit in the IRQ handler to avoid TCD in EDMA been overwritten
2619 * if peripheral request isn't coming before next transfer request.
2620 * 2. Don't clear DONE bit for below case,
2621 * for the case that transfer request submitted in the privious edma callback, this is a case that doesn't
2622 * need scatter gather, so keep DONE bit during the next transfer request submission will re-install the TCD and
2623 * the DONE bit will be cleared together with TCD re-installation.
2624 */
2625 if (transfer_done)
2626 {
2627 if ((EDMA_TCD_CSR(handle->tcdBase, EDMA_TCD_TYPE(handle->base)) & DMA_CSR_ESG_MASK) != 0U)
2628 {
2629 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2630 handle->base->CDNE = handle->channel;
2631 #else
2632 handle->channelBase->CH_CSR |= DMA_CH_CSR_DONE_MASK;
2633 #endif
2634 }
2635 }
2636 }
2637 }
2638
2639 void EDMA_DriverIRQHandler(uint32_t instance, uint32_t channel);
EDMA_DriverIRQHandler(uint32_t instance,uint32_t channel)2640 void EDMA_DriverIRQHandler(uint32_t instance, uint32_t channel)
2641 {
2642 #if defined FSL_EDMA_SOC_IP_EDMA && FSL_EDMA_SOC_IP_EDMA
2643 if ((s_edmaBases[instance]->INT >> channel) != 0U)
2644 {
2645 EDMA_HandleIRQ(s_EDMAHandle[instance][channel]);
2646 }
2647 #else
2648 if ((EDMA_CHANNEL_BASE(s_edmaBases[instance], channel)->CH_INT & DMA_CH_INT_INT_MASK) != 0U)
2649 {
2650 EDMA_HandleIRQ(s_EDMAHandle[instance][channel]);
2651 }
2652 #endif
2653 SDK_ISR_EXIT_BARRIER;
2654 }
2655