1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #ifndef _FSL_EDMA_H_
10 #define _FSL_EDMA_H_
11
12 #include "fsl_common.h"
13
14 /*!
15 * @addtogroup edma
16 * @{
17 */
18
19 /*******************************************************************************
20 * Definitions
21 ******************************************************************************/
22
23 /*! @name Driver version */
24 /*@{*/
25 /*! @brief eDMA driver version */
26 #define FSL_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 4, 3)) /*!< Version 2.4.3. */
27 /*@}*/
28
29 /*! @brief Compute the offset unit from DCHPRI3 */
30 #define DMA_DCHPRI_INDEX(channel) (((channel) & ~0x03U) | (3U - ((channel)&0x03U)))
31
32 /*! @brief eDMA transfer configuration */
33 typedef enum _edma_transfer_size
34 {
35 kEDMA_TransferSize1Bytes = 0x0U, /*!< Source/Destination data transfer size is 1 byte every time */
36 kEDMA_TransferSize2Bytes = 0x1U, /*!< Source/Destination data transfer size is 2 bytes every time */
37 kEDMA_TransferSize4Bytes = 0x2U, /*!< Source/Destination data transfer size is 4 bytes every time */
38 kEDMA_TransferSize8Bytes = 0x3U, /*!< Source/Destination data transfer size is 8 bytes every time */
39 kEDMA_TransferSize16Bytes = 0x4U, /*!< Source/Destination data transfer size is 16 bytes every time */
40 kEDMA_TransferSize32Bytes = 0x5U, /*!< Source/Destination data transfer size is 32 bytes every time */
41 } edma_transfer_size_t;
42
43 /*! @brief eDMA modulo configuration */
44 typedef enum _edma_modulo
45 {
46 kEDMA_ModuloDisable = 0x0U, /*!< Disable modulo */
47 kEDMA_Modulo2bytes, /*!< Circular buffer size is 2 bytes. */
48 kEDMA_Modulo4bytes, /*!< Circular buffer size is 4 bytes. */
49 kEDMA_Modulo8bytes, /*!< Circular buffer size is 8 bytes. */
50 kEDMA_Modulo16bytes, /*!< Circular buffer size is 16 bytes. */
51 kEDMA_Modulo32bytes, /*!< Circular buffer size is 32 bytes. */
52 kEDMA_Modulo64bytes, /*!< Circular buffer size is 64 bytes. */
53 kEDMA_Modulo128bytes, /*!< Circular buffer size is 128 bytes. */
54 kEDMA_Modulo256bytes, /*!< Circular buffer size is 256 bytes. */
55 kEDMA_Modulo512bytes, /*!< Circular buffer size is 512 bytes. */
56 kEDMA_Modulo1Kbytes, /*!< Circular buffer size is 1 K bytes. */
57 kEDMA_Modulo2Kbytes, /*!< Circular buffer size is 2 K bytes. */
58 kEDMA_Modulo4Kbytes, /*!< Circular buffer size is 4 K bytes. */
59 kEDMA_Modulo8Kbytes, /*!< Circular buffer size is 8 K bytes. */
60 kEDMA_Modulo16Kbytes, /*!< Circular buffer size is 16 K bytes. */
61 kEDMA_Modulo32Kbytes, /*!< Circular buffer size is 32 K bytes. */
62 kEDMA_Modulo64Kbytes, /*!< Circular buffer size is 64 K bytes. */
63 kEDMA_Modulo128Kbytes, /*!< Circular buffer size is 128 K bytes. */
64 kEDMA_Modulo256Kbytes, /*!< Circular buffer size is 256 K bytes. */
65 kEDMA_Modulo512Kbytes, /*!< Circular buffer size is 512 K bytes. */
66 kEDMA_Modulo1Mbytes, /*!< Circular buffer size is 1 M bytes. */
67 kEDMA_Modulo2Mbytes, /*!< Circular buffer size is 2 M bytes. */
68 kEDMA_Modulo4Mbytes, /*!< Circular buffer size is 4 M bytes. */
69 kEDMA_Modulo8Mbytes, /*!< Circular buffer size is 8 M bytes. */
70 kEDMA_Modulo16Mbytes, /*!< Circular buffer size is 16 M bytes. */
71 kEDMA_Modulo32Mbytes, /*!< Circular buffer size is 32 M bytes. */
72 kEDMA_Modulo64Mbytes, /*!< Circular buffer size is 64 M bytes. */
73 kEDMA_Modulo128Mbytes, /*!< Circular buffer size is 128 M bytes. */
74 kEDMA_Modulo256Mbytes, /*!< Circular buffer size is 256 M bytes. */
75 kEDMA_Modulo512Mbytes, /*!< Circular buffer size is 512 M bytes. */
76 kEDMA_Modulo1Gbytes, /*!< Circular buffer size is 1 G bytes. */
77 kEDMA_Modulo2Gbytes, /*!< Circular buffer size is 2 G bytes. */
78 } edma_modulo_t;
79
80 /*! @brief Bandwidth control */
81 typedef enum _edma_bandwidth
82 {
83 kEDMA_BandwidthStallNone = 0x0U, /*!< No eDMA engine stalls. */
84 kEDMA_BandwidthStall4Cycle = 0x2U, /*!< eDMA engine stalls for 4 cycles after each read/write. */
85 kEDMA_BandwidthStall8Cycle = 0x3U, /*!< eDMA engine stalls for 8 cycles after each read/write. */
86 } edma_bandwidth_t;
87
88 /*! @brief Channel link type */
89 typedef enum _edma_channel_link_type
90 {
91 kEDMA_LinkNone = 0x0U, /*!< No channel link */
92 kEDMA_MinorLink, /*!< Channel link after each minor loop */
93 kEDMA_MajorLink, /*!< Channel link while major loop count exhausted */
94 } edma_channel_link_type_t;
95
96 /*!@brief _edma_channel_status_flags eDMA channel status flags. */
97 enum
98 {
99 kEDMA_DoneFlag = 0x1U, /*!< DONE flag, set while transfer finished, CITER value exhausted*/
100 kEDMA_ErrorFlag = 0x2U, /*!< eDMA error flag, an error occurred in a transfer */
101 kEDMA_InterruptFlag = 0x4U, /*!< eDMA interrupt flag, set while an interrupt occurred of this channel */
102 };
103
104 /*! @brief _edma_error_status_flags eDMA channel error status flags. */
105 enum
106 {
107 kEDMA_DestinationBusErrorFlag = DMA_ES_DBE_MASK, /*!< Bus error on destination address */
108 kEDMA_SourceBusErrorFlag = DMA_ES_SBE_MASK, /*!< Bus error on the source address */
109 kEDMA_ScatterGatherErrorFlag = DMA_ES_SGE_MASK, /*!< Error on the Scatter/Gather address, not 32byte aligned. */
110 kEDMA_NbytesErrorFlag = DMA_ES_NCE_MASK, /*!< NBYTES/CITER configuration error */
111 kEDMA_DestinationOffsetErrorFlag = DMA_ES_DOE_MASK, /*!< Destination offset not aligned with destination size */
112 kEDMA_DestinationAddressErrorFlag = DMA_ES_DAE_MASK, /*!< Destination address not aligned with destination size */
113 kEDMA_SourceOffsetErrorFlag = DMA_ES_SOE_MASK, /*!< Source offset not aligned with source size */
114 kEDMA_SourceAddressErrorFlag = DMA_ES_SAE_MASK, /*!< Source address not aligned with source size*/
115 kEDMA_ErrorChannelFlag = DMA_ES_ERRCHN_MASK, /*!< Error channel number of the cancelled channel number */
116 kEDMA_ChannelPriorityErrorFlag = DMA_ES_CPE_MASK, /*!< Channel priority is not unique. */
117 kEDMA_TransferCanceledFlag = DMA_ES_ECX_MASK, /*!< Transfer cancelled */
118 #if defined(FSL_FEATURE_EDMA_CHANNEL_GROUP_COUNT) && (FSL_FEATURE_EDMA_CHANNEL_GROUP_COUNT > 1)
119 kEDMA_GroupPriorityErrorFlag = DMA_ES_GPE_MASK, /*!< Group priority is not unique. */
120 #endif
121 kEDMA_ValidFlag = (int)DMA_ES_VLD_MASK, /*!< No error occurred, this bit is 0. Otherwise, it is 1. */
122 };
123
124 /*! @brief eDMA interrupt source */
125 typedef enum _edma_interrupt_enable
126 {
127 kEDMA_ErrorInterruptEnable = 0x1U, /*!< Enable interrupt while channel error occurs. */
128 kEDMA_MajorInterruptEnable = DMA_CSR_INTMAJOR_MASK, /*!< Enable interrupt while major count exhausted. */
129 kEDMA_HalfInterruptEnable = DMA_CSR_INTHALF_MASK, /*!< Enable interrupt while major count to half value. */
130 } edma_interrupt_enable_t;
131
132 /*! @brief eDMA transfer type */
133 typedef enum _edma_transfer_type
134 {
135 kEDMA_MemoryToMemory = 0x0U, /*!< Transfer from memory to memory */
136 kEDMA_PeripheralToMemory, /*!< Transfer from peripheral to memory */
137 kEDMA_MemoryToPeripheral, /*!< Transfer from memory to peripheral */
138 kEDMA_PeripheralToPeripheral, /*!< Transfer from Peripheral to peripheral */
139 } edma_transfer_type_t;
140
141 /*! @brief _edma_transfer_status eDMA transfer status */
142 enum
143 {
144 kStatus_EDMA_QueueFull = MAKE_STATUS(kStatusGroup_EDMA, 0), /*!< TCD queue is full. */
145 kStatus_EDMA_Busy = MAKE_STATUS(kStatusGroup_EDMA, 1), /*!< Channel is busy and can't handle the
146 transfer request. */
147 };
148
149 /*! @brief eDMA global configuration structure.*/
150 typedef struct _edma_config
151 {
152 bool enableContinuousLinkMode; /*!< Enable (true) continuous link mode. Upon minor loop completion, the channel
153 activates again if that channel has a minor loop channel link enabled and
154 the link channel is itself. */
155 bool enableHaltOnError; /*!< Enable (true) transfer halt on error. Any error causes the HALT bit to set.
156 Subsequently, all service requests are ignored until the HALT bit is cleared.*/
157 bool enableRoundRobinArbitration; /*!< Enable (true) round robin channel arbitration method or fixed priority
158 arbitration is used for channel selection */
159 bool enableDebugMode; /*!< Enable(true) eDMA debug mode. When in debug mode, the eDMA stalls the start of
160 a new channel. Executing channels are allowed to complete. */
161 } edma_config_t;
162
163 /*!
164 * @brief eDMA transfer configuration
165 *
166 * This structure configures the source/destination transfer attribute.
167 */
168 typedef struct _edma_transfer_config
169 {
170 uint32_t srcAddr; /*!< Source data address. */
171 uint32_t destAddr; /*!< Destination data address. */
172 edma_transfer_size_t srcTransferSize; /*!< Source data transfer size. */
173 edma_transfer_size_t destTransferSize; /*!< Destination data transfer size. */
174 int16_t srcOffset; /*!< Sign-extended offset applied to the current source address to
175 form the next-state value as each source read is completed. */
176 int16_t destOffset; /*!< Sign-extended offset applied to the current destination address to
177 form the next-state value as each destination write is completed. */
178 uint32_t minorLoopBytes; /*!< Bytes to transfer in a minor loop*/
179 uint32_t majorLoopCounts; /*!< Major loop iteration count. */
180 } edma_transfer_config_t;
181
182 /*! @brief eDMA channel priority configuration */
183 typedef struct _edma_channel_Preemption_config
184 {
185 bool enableChannelPreemption; /*!< If true: a channel can be suspended by other channel with higher priority */
186 bool enablePreemptAbility; /*!< If true: a channel can suspend other channel with low priority */
187 uint8_t channelPriority; /*!< Channel priority */
188 } edma_channel_Preemption_config_t;
189
190 /*! @brief eDMA minor offset configuration */
191 typedef struct _edma_minor_offset_config
192 {
193 bool enableSrcMinorOffset; /*!< Enable(true) or Disable(false) source minor loop offset. */
194 bool enableDestMinorOffset; /*!< Enable(true) or Disable(false) destination minor loop offset. */
195 uint32_t minorOffset; /*!< Offset for a minor loop mapping. */
196 } edma_minor_offset_config_t;
197
198 /*!
199 * @brief eDMA TCD.
200 *
201 * This structure is same as TCD register which is described in reference manual,
202 * and is used to configure the scatter/gather feature as a next hardware TCD.
203 */
204 typedef struct _edma_tcd
205 {
206 __IO uint32_t SADDR; /*!< SADDR register, used to save source address */
207 __IO uint16_t SOFF; /*!< SOFF register, save offset bytes every transfer */
208 __IO uint16_t ATTR; /*!< ATTR register, source/destination transfer size and modulo */
209 __IO uint32_t NBYTES; /*!< Nbytes register, minor loop length in bytes */
210 __IO uint32_t SLAST; /*!< SLAST register */
211 __IO uint32_t DADDR; /*!< DADDR register, used for destination address */
212 __IO uint16_t DOFF; /*!< DOFF register, used for destination offset */
213 __IO uint16_t CITER; /*!< CITER register, current minor loop numbers, for unfinished minor loop.*/
214 __IO uint32_t DLAST_SGA; /*!< DLASTSGA register, next tcd address used in scatter-gather mode */
215 __IO uint16_t CSR; /*!< CSR register, for TCD control status */
216 __IO uint16_t BITER; /*!< BITER register, begin minor loop count. */
217 } edma_tcd_t;
218
219 /*! @brief Callback for eDMA */
220 struct _edma_handle;
221
222 /*! @brief Define callback function for eDMA.
223 *
224 * This callback function is called in the EDMA interrupt handle.
225 * In normal mode, run into callback function means the transfer users need is done.
226 * In scatter gather mode, run into callback function means a transfer control block (tcd) is finished. Not
227 * all transfer finished, users can get the finished tcd numbers using interface EDMA_GetUnusedTCDNumber.
228 *
229 * @param handle EDMA handle pointer, users shall not touch the values inside.
230 * @param userData The callback user parameter pointer. Users can use this parameter to involve things users need to
231 * change in EDMA callback function.
232 * @param transferDone If the current loaded transfer done. In normal mode it means if all transfer done. In scatter
233 * gather mode, this parameter shows is the current transfer block in EDMA register is done. As the
234 * load of core is different, it will be different if the new tcd loaded into EDMA registers while
235 * this callback called. If true, it always means new tcd still not loaded into registers, while
236 * false means new tcd already loaded into registers.
237 * @param tcds How many tcds are done from the last callback. This parameter only used in scatter gather mode. It
238 * tells user how many tcds are finished between the last callback and this.
239 */
240 typedef void (*edma_callback)(struct _edma_handle *handle, void *userData, bool transferDone, uint32_t tcds);
241
242 /*! @brief eDMA transfer handle structure */
243 typedef struct _edma_handle
244 {
245 edma_callback callback; /*!< Callback function for major count exhausted. */
246 void *userData; /*!< Callback function parameter. */
247 DMA_Type *base; /*!< eDMA peripheral base address. */
248 edma_tcd_t *tcdPool; /*!< Pointer to memory stored TCDs. */
249 uint8_t channel; /*!< eDMA channel number. */
250 volatile int8_t header; /*!< The first TCD index. Should point to the next TCD to be loaded into the eDMA engine. */
251 volatile int8_t tail; /*!< The last TCD index. Should point to the next TCD to be stored into the memory pool. */
252 volatile int8_t tcdUsed; /*!< The number of used TCD slots. Should reflect the number of TCDs can be used/loaded in
253 the memory. */
254 volatile int8_t tcdSize; /*!< The total number of TCD slots in the queue. */
255 uint8_t flags; /*!< The status of the current channel. */
256 } edma_handle_t;
257
258 /*******************************************************************************
259 * APIs
260 ******************************************************************************/
261 #if defined(__cplusplus)
262 extern "C" {
263 #endif /* __cplusplus */
264
265 /*!
266 * @name eDMA initialization and de-initialization
267 * @{
268 */
269
270 /*!
271 * @brief Initializes the eDMA peripheral.
272 *
273 * This function ungates the eDMA clock and configures the eDMA peripheral according
274 * to the configuration structure.
275 *
276 * @param base eDMA peripheral base address.
277 * @param config A pointer to the configuration structure, see "edma_config_t".
278 * @note This function enables the minor loop map feature.
279 */
280 void EDMA_Init(DMA_Type *base, const edma_config_t *config);
281
282 /*!
283 * @brief Deinitializes the eDMA peripheral.
284 *
285 * This function gates the eDMA clock.
286 *
287 * @param base eDMA peripheral base address.
288 */
289 void EDMA_Deinit(DMA_Type *base);
290
291 /*!
292 * @brief Push content of TCD structure into hardware TCD register.
293 *
294 * @param base EDMA peripheral base address.
295 * @param channel EDMA channel number.
296 * @param tcd Point to TCD structure.
297 */
298 void EDMA_InstallTCD(DMA_Type *base, uint32_t channel, edma_tcd_t *tcd);
299
300 /*!
301 * @brief Gets the eDMA default configuration structure.
302 *
303 * This function sets the configuration structure to default values.
304 * The default configuration is set to the following values.
305 * @code
306 * config.enableContinuousLinkMode = false;
307 * config.enableHaltOnError = true;
308 * config.enableRoundRobinArbitration = false;
309 * config.enableDebugMode = false;
310 * @endcode
311 *
312 * @param config A pointer to the eDMA configuration structure.
313 */
314 void EDMA_GetDefaultConfig(edma_config_t *config);
315
316 /*!
317 * @brief Enable/Disable continuous channel link mode.
318 *
319 * @note Do not use continuous link mode with a channel linking to itself if there is only one minor loop
320 * iteration per service request, for example, if the channel's NBYTES value is the same as either
321 * the source or destination size. The same data transfer profile can be achieved by simply
322 * increasing the NBYTES value, which provides more efficient, faster processing.
323 *
324 * @param base EDMA peripheral base address.
325 * @param enable true is enable, false is disable.
326 */
EDMA_EnableContinuousChannelLinkMode(DMA_Type * base,bool enable)327 static inline void EDMA_EnableContinuousChannelLinkMode(DMA_Type *base, bool enable)
328 {
329 if (enable)
330 {
331 base->CR |= DMA_CR_CLM_MASK;
332 }
333 else
334 {
335 base->CR &= ~DMA_CR_CLM_MASK;
336 }
337 }
338
339 /*!
340 * @brief Enable/Disable minor loop mapping.
341 *
342 * The TCDn.word2 is redefined to include individual enable fields, an offset field, and the
343 * NBYTES field.
344 *
345 * @param base EDMA peripheral base address.
346 * @param enable true is enable, false is disable.
347 */
EDMA_EnableMinorLoopMapping(DMA_Type * base,bool enable)348 static inline void EDMA_EnableMinorLoopMapping(DMA_Type *base, bool enable)
349 {
350 if (enable)
351 {
352 base->CR |= DMA_CR_EMLM_MASK;
353 }
354 else
355 {
356 base->CR &= ~DMA_CR_EMLM_MASK;
357 }
358 }
359
360 /* @} */
361 /*!
362 * @name eDMA Channel Operation
363 * @{
364 */
365
366 /*!
367 * @brief Sets all TCD registers to default values.
368 *
369 * This function sets TCD registers for this channel to default values.
370 *
371 * @param base eDMA peripheral base address.
372 * @param channel eDMA channel number.
373 * @note This function must not be called while the channel transfer is ongoing
374 * or it causes unpredictable results.
375 * @note This function enables the auto stop request feature.
376 */
377 void EDMA_ResetChannel(DMA_Type *base, uint32_t channel);
378
379 /*!
380 * @brief Configures the eDMA transfer attribute.
381 *
382 * This function configures the transfer attribute, including source address, destination address,
383 * transfer size, address offset, and so on. It also configures the scatter gather feature if the
384 * user supplies the TCD address.
385 * Example:
386 * @code
387 * edma_transfer_t config;
388 * edma_tcd_t tcd;
389 * config.srcAddr = ..;
390 * config.destAddr = ..;
391 * ...
392 * EDMA_SetTransferConfig(DMA0, channel, &config, &stcd);
393 * @endcode
394 *
395 * @param base eDMA peripheral base address.
396 * @param channel eDMA channel number.
397 * @param config Pointer to eDMA transfer configuration structure.
398 * @param nextTcd Point to TCD structure. It can be NULL if users
399 * do not want to enable scatter/gather feature.
400 * @note If nextTcd is not NULL, it means scatter gather feature is enabled
401 * and DREQ bit is cleared in the previous transfer configuration, which
402 * is set in the eDMA_ResetChannel.
403 */
404 void EDMA_SetTransferConfig(DMA_Type *base,
405 uint32_t channel,
406 const edma_transfer_config_t *config,
407 edma_tcd_t *nextTcd);
408
409 /*!
410 * @brief Configures the eDMA minor offset feature.
411 *
412 * The minor offset means that the signed-extended value is added to the source address or destination
413 * address after each minor loop.
414 *
415 * @param base eDMA peripheral base address.
416 * @param channel eDMA channel number.
417 * @param config A pointer to the minor offset configuration structure.
418 */
419 void EDMA_SetMinorOffsetConfig(DMA_Type *base, uint32_t channel, const edma_minor_offset_config_t *config);
420
421 /*!
422 * @brief Configures the eDMA channel preemption feature.
423 *
424 * This function configures the channel preemption attribute and the priority of the channel.
425 *
426 * @param base eDMA peripheral base address.
427 * @param channel eDMA channel number
428 * @param config A pointer to the channel preemption configuration structure.
429 */
430 void EDMA_SetChannelPreemptionConfig(DMA_Type *base, uint32_t channel, const edma_channel_Preemption_config_t *config);
431
432 /*!
433 * @brief Sets the channel link for the eDMA transfer.
434 *
435 * This function configures either the minor link or the major link mode. The minor link means that the channel link is
436 * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
437 * exhausted.
438 *
439 * @param base eDMA peripheral base address.
440 * @param channel eDMA channel number.
441 * @param linkType A channel link type, which can be one of the following:
442 * @arg kEDMA_LinkNone
443 * @arg kEDMA_MinorLink
444 * @arg kEDMA_MajorLink
445 * @param linkedChannel The linked channel number.
446 * @note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
447 */
448 void EDMA_SetChannelLink(DMA_Type *base, uint32_t channel, edma_channel_link_type_t linkType, uint32_t linkedChannel);
449
450 /*!
451 * @brief Sets the bandwidth for the eDMA transfer.
452 *
453 * Because the eDMA processes the minor loop, it continuously generates read/write sequences
454 * until the minor count is exhausted. The bandwidth forces the eDMA to stall after the completion of
455 * each read/write access to control the bus request bandwidth seen by the crossbar switch.
456 *
457 * @param base eDMA peripheral base address.
458 * @param channel eDMA channel number.
459 * @param bandWidth A bandwidth setting, which can be one of the following:
460 * @arg kEDMABandwidthStallNone
461 * @arg kEDMABandwidthStall4Cycle
462 * @arg kEDMABandwidthStall8Cycle
463 */
464 void EDMA_SetBandWidth(DMA_Type *base, uint32_t channel, edma_bandwidth_t bandWidth);
465
466 /*!
467 * @brief Sets the source modulo and the destination modulo for the eDMA transfer.
468 *
469 * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
470 * calculation is performed or the original register value. It provides the ability to implement a circular data
471 * queue easily.
472 *
473 * @param base eDMA peripheral base address.
474 * @param channel eDMA channel number.
475 * @param srcModulo A source modulo value.
476 * @param destModulo A destination modulo value.
477 */
478 void EDMA_SetModulo(DMA_Type *base, uint32_t channel, edma_modulo_t srcModulo, edma_modulo_t destModulo);
479
480 #if defined(FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT) && FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT
481 /*!
482 * @brief Enables an async request for the eDMA transfer.
483 *
484 * @param base eDMA peripheral base address.
485 * @param channel eDMA channel number.
486 * @param enable The command to enable (true) or disable (false).
487 */
EDMA_EnableAsyncRequest(DMA_Type * base,uint32_t channel,bool enable)488 static inline void EDMA_EnableAsyncRequest(DMA_Type *base, uint32_t channel, bool enable)
489 {
490 assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
491
492 base->EARS &= ~((uint32_t)1U << channel);
493 base->EARS |= ((uint32_t)(true == enable ? 1U : 0U) << channel);
494 }
495 #endif /* FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT */
496
497 /*!
498 * @brief Enables an auto stop request for the eDMA transfer.
499 *
500 * If enabling the auto stop request, the eDMA hardware automatically disables the hardware channel request.
501 *
502 * @param base eDMA peripheral base address.
503 * @param channel eDMA channel number.
504 * @param enable The command to enable (true) or disable (false).
505 */
EDMA_EnableAutoStopRequest(DMA_Type * base,uint32_t channel,bool enable)506 static inline void EDMA_EnableAutoStopRequest(DMA_Type *base, uint32_t channel, bool enable)
507 {
508 assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
509
510 base->TCD[channel].CSR =
511 (uint16_t)((base->TCD[channel].CSR & (~DMA_CSR_DREQ_MASK)) | DMA_CSR_DREQ((true == enable ? 1U : 0U)));
512 }
513
514 /*!
515 * @brief Enables the interrupt source for the eDMA transfer.
516 *
517 * @param base eDMA peripheral base address.
518 * @param channel eDMA channel number.
519 * @param mask The mask of interrupt source to be set. Users need to use
520 * the defined edma_interrupt_enable_t type.
521 */
522 void EDMA_EnableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask);
523
524 /*!
525 * @brief Disables the interrupt source for the eDMA transfer.
526 *
527 * @param base eDMA peripheral base address.
528 * @param channel eDMA channel number.
529 * @param mask The mask of the interrupt source to be set. Use
530 * the defined edma_interrupt_enable_t type.
531 */
532 void EDMA_DisableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask);
533
534 /*!
535 * @brief Configures the eDMA channel TCD major offset feature.
536 *
537 * Adjustment value added to the source address at the completion of the major iteration count
538 *
539 * @param base eDMA peripheral base address.
540 * @param channel edma channel number.
541 * @param sourceOffset source address offset will be applied to source address after major loop done.
542 * @param destOffset destination address offset will be applied to source address after major loop done.
543 */
544 void EDMA_SetMajorOffsetConfig(DMA_Type *base, uint32_t channel, int32_t sourceOffset, int32_t destOffset);
545
546 /* @} */
547 /*!
548 * @name eDMA TCD Operation
549 * @{
550 */
551
552 /*!
553 * @brief Sets all fields to default values for the TCD structure.
554 *
555 * This function sets all fields for this TCD structure to default value.
556 *
557 * @param tcd Pointer to the TCD structure.
558 * @note This function enables the auto stop request feature.
559 */
560 void EDMA_TcdReset(edma_tcd_t *tcd);
561
562 /*!
563 * @brief Configures the eDMA TCD transfer attribute.
564 *
565 * The TCD is a transfer control descriptor. The content of the TCD is the same as the hardware TCD registers.
566 * The TCD is used in the scatter-gather mode.
567 * This function configures the TCD transfer attribute, including source address, destination address,
568 * transfer size, address offset, and so on. It also configures the scatter gather feature if the
569 * user supplies the next TCD address.
570 * Example:
571 * @code
572 * edma_transfer_t config = {
573 * ...
574 * }
575 * edma_tcd_t tcd __aligned(32);
576 * edma_tcd_t nextTcd __aligned(32);
577 * EDMA_TcdSetTransferConfig(&tcd, &config, &nextTcd);
578 * @endcode
579 *
580 * @param tcd Pointer to the TCD structure.
581 * @param config Pointer to eDMA transfer configuration structure.
582 * @param nextTcd Pointer to the next TCD structure. It can be NULL if users
583 * do not want to enable scatter/gather feature.
584 * @note TCD address should be 32 bytes aligned or it causes an eDMA error.
585 * @note If the nextTcd is not NULL, the scatter gather feature is enabled
586 * and DREQ bit is cleared in the previous transfer configuration, which
587 * is set in the EDMA_TcdReset.
588 */
589 void EDMA_TcdSetTransferConfig(edma_tcd_t *tcd, const edma_transfer_config_t *config, edma_tcd_t *nextTcd);
590
591 /*!
592 * @brief Configures the eDMA TCD minor offset feature.
593 *
594 * A minor offset is a signed-extended value added to the source address or a destination
595 * address after each minor loop.
596 *
597 * @param tcd A point to the TCD structure.
598 * @param config A pointer to the minor offset configuration structure.
599 */
600 void EDMA_TcdSetMinorOffsetConfig(edma_tcd_t *tcd, const edma_minor_offset_config_t *config);
601
602 /*!
603 * @brief Sets the channel link for the eDMA TCD.
604 *
605 * This function configures either a minor link or a major link. The minor link means the channel link is
606 * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
607 * exhausted.
608 *
609 * @note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
610 * @param tcd Point to the TCD structure.
611 * @param linkType Channel link type, it can be one of:
612 * @arg kEDMA_LinkNone
613 * @arg kEDMA_MinorLink
614 * @arg kEDMA_MajorLink
615 * @param linkedChannel The linked channel number.
616 */
617 void EDMA_TcdSetChannelLink(edma_tcd_t *tcd, edma_channel_link_type_t linkType, uint32_t linkedChannel);
618
619 /*!
620 * @brief Sets the bandwidth for the eDMA TCD.
621 *
622 * Because the eDMA processes the minor loop, it continuously generates read/write sequences
623 * until the minor count is exhausted. The bandwidth forces the eDMA to stall after the completion of
624 * each read/write access to control the bus request bandwidth seen by the crossbar switch.
625 * @param tcd A pointer to the TCD structure.
626 * @param bandWidth A bandwidth setting, which can be one of the following:
627 * @arg kEDMABandwidthStallNone
628 * @arg kEDMABandwidthStall4Cycle
629 * @arg kEDMABandwidthStall8Cycle
630 */
EDMA_TcdSetBandWidth(edma_tcd_t * tcd,edma_bandwidth_t bandWidth)631 static inline void EDMA_TcdSetBandWidth(edma_tcd_t *tcd, edma_bandwidth_t bandWidth)
632 {
633 assert(tcd != NULL);
634 assert(((uint32_t)tcd & 0x1FU) == 0U);
635
636 tcd->CSR = (uint16_t)((tcd->CSR & (~DMA_CSR_BWC_MASK)) | DMA_CSR_BWC(bandWidth));
637 }
638
639 /*!
640 * @brief Sets the source modulo and the destination modulo for the eDMA TCD.
641 *
642 * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
643 * calculation is performed or the original register value. It provides the ability to implement a circular data
644 * queue easily.
645 *
646 * @param tcd A pointer to the TCD structure.
647 * @param srcModulo A source modulo value.
648 * @param destModulo A destination modulo value.
649 */
650 void EDMA_TcdSetModulo(edma_tcd_t *tcd, edma_modulo_t srcModulo, edma_modulo_t destModulo);
651
652 /*!
653 * @brief Sets the auto stop request for the eDMA TCD.
654 *
655 * If enabling the auto stop request, the eDMA hardware automatically disables the hardware channel request.
656 *
657 * @param tcd A pointer to the TCD structure.
658 * @param enable The command to enable (true) or disable (false).
659 */
EDMA_TcdEnableAutoStopRequest(edma_tcd_t * tcd,bool enable)660 static inline void EDMA_TcdEnableAutoStopRequest(edma_tcd_t *tcd, bool enable)
661 {
662 assert(tcd != NULL);
663 assert(((uint32_t)tcd & 0x1FU) == 0U);
664
665 tcd->CSR = (uint16_t)((tcd->CSR & (~DMA_CSR_DREQ_MASK)) | DMA_CSR_DREQ((true == enable ? 1U : 0U)));
666 }
667
668 /*!
669 * @brief Enables the interrupt source for the eDMA TCD.
670 *
671 * @param tcd Point to the TCD structure.
672 * @param mask The mask of interrupt source to be set. Users need to use
673 * the defined edma_interrupt_enable_t type.
674 */
675 void EDMA_TcdEnableInterrupts(edma_tcd_t *tcd, uint32_t mask);
676
677 /*!
678 * @brief Disables the interrupt source for the eDMA TCD.
679 *
680 * @param tcd Point to the TCD structure.
681 * @param mask The mask of interrupt source to be set. Users need to use
682 * the defined edma_interrupt_enable_t type.
683 */
684 void EDMA_TcdDisableInterrupts(edma_tcd_t *tcd, uint32_t mask);
685
686 /*!
687 * @brief Configures the eDMA TCD major offset feature.
688 *
689 * Adjustment value added to the source address at the completion of the major iteration count
690 *
691 * @param tcd A point to the TCD structure.
692 * @param sourceOffset source address offset wiil be applied to source address after major loop done.
693 * @param destOffset destination address offset will be applied to source address after major loop done.
694 */
695 void EDMA_TcdSetMajorOffsetConfig(edma_tcd_t *tcd, int32_t sourceOffset, int32_t destOffset);
696
697 /*! @} */
698 /*!
699 * @name eDMA Channel Transfer Operation
700 * @{
701 */
702
703 /*!
704 * @brief Enables the eDMA hardware channel request.
705 *
706 * This function enables the hardware channel request.
707 *
708 * @param base eDMA peripheral base address.
709 * @param channel eDMA channel number.
710 */
EDMA_EnableChannelRequest(DMA_Type * base,uint32_t channel)711 static inline void EDMA_EnableChannelRequest(DMA_Type *base, uint32_t channel)
712 {
713 assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
714
715 base->SERQ = DMA_SERQ_SERQ(channel);
716 }
717
718 /*!
719 * @brief Disables the eDMA hardware channel request.
720 *
721 * This function disables the hardware channel request.
722 *
723 * @param base eDMA peripheral base address.
724 * @param channel eDMA channel number.
725 */
EDMA_DisableChannelRequest(DMA_Type * base,uint32_t channel)726 static inline void EDMA_DisableChannelRequest(DMA_Type *base, uint32_t channel)
727 {
728 assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
729
730 base->CERQ = DMA_CERQ_CERQ(channel);
731 }
732
733 /*!
734 * @brief Starts the eDMA transfer by using the software trigger.
735 *
736 * This function starts a minor loop transfer.
737 *
738 * @param base eDMA peripheral base address.
739 * @param channel eDMA channel number.
740 */
EDMA_TriggerChannelStart(DMA_Type * base,uint32_t channel)741 static inline void EDMA_TriggerChannelStart(DMA_Type *base, uint32_t channel)
742 {
743 assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
744
745 base->SSRT = DMA_SSRT_SSRT(channel);
746 }
747
748 /*! @} */
749 /*!
750 * @name eDMA Channel Status Operation
751 * @{
752 */
753
754 /*!
755 * @brief Gets the remaining major loop count from the eDMA current channel TCD.
756 *
757 * This function checks the TCD (Task Control Descriptor) status for a specified
758 * eDMA channel and returns the number of major loop count that has not finished.
759 *
760 * @param base eDMA peripheral base address.
761 * @param channel eDMA channel number.
762 * @return Major loop count which has not been transferred yet for the current TCD.
763 * @note 1. This function can only be used to get unfinished major loop count of transfer without
764 * the next TCD, or it might be inaccuracy.
765 * 2. The unfinished/remaining transfer bytes cannot be obtained directly from registers while
766 * the channel is running.
767 * Because to calculate the remaining bytes, the initial NBYTES configured in DMA_TCDn_NBYTES_MLNO
768 * register is needed while the eDMA IP does not support getting it while a channel is active.
769 * In another word, the NBYTES value reading is always the actual (decrementing) NBYTES value the dma_engine
770 * is working with while a channel is running.
771 * Consequently, to get the remaining transfer bytes, a software-saved initial value of NBYTES (for example
772 * copied before enabling the channel) is needed. The formula to calculate it is shown below:
773 * RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured)
774 */
775 uint32_t EDMA_GetRemainingMajorLoopCount(DMA_Type *base, uint32_t channel);
776
777 /*!
778 * @brief Gets the eDMA channel error status flags.
779 *
780 * @param base eDMA peripheral base address.
781 * @return The mask of error status flags. Users need to use the
782 * _edma_error_status_flags type to decode the return variables.
783 */
EDMA_GetErrorStatusFlags(DMA_Type * base)784 static inline uint32_t EDMA_GetErrorStatusFlags(DMA_Type *base)
785 {
786 return base->ES;
787 }
788
789 /*!
790 * @brief Gets the eDMA channel status flags.
791 *
792 * @param base eDMA peripheral base address.
793 * @param channel eDMA channel number.
794 * @return The mask of channel status flags. Users need to use the
795 * _edma_channel_status_flags type to decode the return variables.
796 */
797 uint32_t EDMA_GetChannelStatusFlags(DMA_Type *base, uint32_t channel);
798
799 /*!
800 * @brief Clears the eDMA channel status flags.
801 *
802 * @param base eDMA peripheral base address.
803 * @param channel eDMA channel number.
804 * @param mask The mask of channel status to be cleared. Users need to use
805 * the defined _edma_channel_status_flags type.
806 */
807 void EDMA_ClearChannelStatusFlags(DMA_Type *base, uint32_t channel, uint32_t mask);
808
809 /*! @} */
810 /*!
811 * @name eDMA Transactional Operation
812 */
813
814 /*!
815 * @brief Creates the eDMA handle.
816 *
817 * This function is called if using the transactional API for eDMA. This function
818 * initializes the internal state of the eDMA handle.
819 *
820 * @param handle eDMA handle pointer. The eDMA handle stores callback function and
821 * parameters.
822 * @param base eDMA peripheral base address.
823 * @param channel eDMA channel number.
824 */
825 void EDMA_CreateHandle(edma_handle_t *handle, DMA_Type *base, uint32_t channel);
826
827 /*!
828 * @brief Installs the TCDs memory pool into the eDMA handle.
829 *
830 * This function is called after the EDMA_CreateHandle to use scatter/gather feature. This function shall only be used
831 * while users need to use scatter gather mode. Scatter gather mode enables EDMA to load a new transfer control block
832 * (tcd) in hardware, and automatically reconfigure that DMA channel for a new transfer.
833 * Users need to prepare tcd memory and also configure tcds using interface EDMA_SubmitTransfer.
834 *
835 * @param handle eDMA handle pointer.
836 * @param tcdPool A memory pool to store TCDs. It must be 32 bytes aligned.
837 * @param tcdSize The number of TCD slots.
838 */
839 void EDMA_InstallTCDMemory(edma_handle_t *handle, edma_tcd_t *tcdPool, uint32_t tcdSize);
840
841 /*!
842 * @brief Installs a callback function for the eDMA transfer.
843 *
844 * This callback is called in the eDMA IRQ handler. Use the callback to do something after
845 * the current major loop transfer completes. This function will be called every time one tcd finished transfer.
846 *
847 * @param handle eDMA handle pointer.
848 * @param callback eDMA callback function pointer.
849 * @param userData A parameter for the callback function.
850 */
851 void EDMA_SetCallback(edma_handle_t *handle, edma_callback callback, void *userData);
852
853 /*!
854 * @brief Prepares the eDMA transfer structure configurations.
855 *
856 * This function prepares the transfer configuration structure according to the user input.
857 *
858 * @param config The user configuration structure of type edma_transfer_t.
859 * @param srcAddr eDMA transfer source address.
860 * @param srcWidth eDMA transfer source address width(bytes).
861 * @param srcOffset source address offset.
862 * @param destAddr eDMA transfer destination address.
863 * @param destWidth eDMA transfer destination address width(bytes).
864 * @param destOffset destination address offset.
865 * @param bytesEachRequest eDMA transfer bytes per channel request.
866 * @param transferBytes eDMA transfer bytes to be transferred.
867 * @note The data address and the data width must be consistent. For example, if the SRC
868 * is 4 bytes, the source address must be 4 bytes aligned, or it results in
869 * source address error (SAE).
870 */
871 void EDMA_PrepareTransferConfig(edma_transfer_config_t *config,
872 void *srcAddr,
873 uint32_t srcWidth,
874 int16_t srcOffset,
875 void *destAddr,
876 uint32_t destWidth,
877 int16_t destOffset,
878 uint32_t bytesEachRequest,
879 uint32_t transferBytes);
880
881 /*!
882 * @brief Prepares the eDMA transfer structure.
883 *
884 * This function prepares the transfer configuration structure according to the user input.
885 *
886 * @param config The user configuration structure of type edma_transfer_t.
887 * @param srcAddr eDMA transfer source address.
888 * @param srcWidth eDMA transfer source address width(bytes).
889 * @param destAddr eDMA transfer destination address.
890 * @param destWidth eDMA transfer destination address width(bytes).
891 * @param bytesEachRequest eDMA transfer bytes per channel request.
892 * @param transferBytes eDMA transfer bytes to be transferred.
893 * @param transferType eDMA transfer type.
894 * @note The data address and the data width must be consistent. For example, if the SRC
895 * is 4 bytes, the source address must be 4 bytes aligned, or it results in
896 * source address error (SAE).
897 */
898 void EDMA_PrepareTransfer(edma_transfer_config_t *config,
899 void *srcAddr,
900 uint32_t srcWidth,
901 void *destAddr,
902 uint32_t destWidth,
903 uint32_t bytesEachRequest,
904 uint32_t transferBytes,
905 edma_transfer_type_t transferType);
906
907 /*!
908 * @brief Submits the eDMA transfer request.
909 *
910 * This function submits the eDMA transfer request according to the transfer configuration structure.
911 * In scatter gather mode, call this function will add a configured tcd to the circular list of tcd pool.
912 * The tcd pools is setup by call function EDMA_InstallTCDMemory before.
913 *
914 * @param handle eDMA handle pointer.
915 * @param config Pointer to eDMA transfer configuration structure.
916 * @retval kStatus_EDMA_Success It means submit transfer request succeed.
917 * @retval kStatus_EDMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
918 * @retval kStatus_EDMA_Busy It means the given channel is busy, need to submit request later.
919 */
920 status_t EDMA_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config);
921
922 /*!
923 * @brief eDMA starts transfer.
924 *
925 * This function enables the channel request. Users can call this function after submitting the transfer request
926 * or before submitting the transfer request.
927 *
928 * @param handle eDMA handle pointer.
929 */
930 void EDMA_StartTransfer(edma_handle_t *handle);
931
932 /*!
933 * @brief eDMA stops transfer.
934 *
935 * This function disables the channel request to pause the transfer. Users can call EDMA_StartTransfer()
936 * again to resume the transfer.
937 *
938 * @param handle eDMA handle pointer.
939 */
940 void EDMA_StopTransfer(edma_handle_t *handle);
941
942 /*!
943 * @brief eDMA aborts transfer.
944 *
945 * This function disables the channel request and clear transfer status bits.
946 * Users can submit another transfer after calling this API.
947 *
948 * @param handle DMA handle pointer.
949 */
950 void EDMA_AbortTransfer(edma_handle_t *handle);
951
952 /*!
953 * @brief Get unused TCD slot number.
954 *
955 * This function gets current tcd index which is run. If the TCD pool pointer is NULL, it will return 0.
956 *
957 * @param handle DMA handle pointer.
958 * @return The unused tcd slot number.
959 */
EDMA_GetUnusedTCDNumber(edma_handle_t * handle)960 static inline uint32_t EDMA_GetUnusedTCDNumber(edma_handle_t *handle)
961 {
962 int8_t tmpTcdSize = handle->tcdSize;
963 int8_t tmpTcdUsed = handle->tcdUsed;
964 return ((uint32_t)tmpTcdSize - (uint32_t)tmpTcdUsed);
965 }
966
967 /*!
968 * @brief Get the next tcd address.
969 *
970 * This function gets the next tcd address. If this is last TCD, return 0.
971 *
972 * @param handle DMA handle pointer.
973 * @return The next TCD address.
974 */
EDMA_GetNextTCDAddress(edma_handle_t * handle)975 static inline uint32_t EDMA_GetNextTCDAddress(edma_handle_t *handle)
976 {
977 return (uint32_t)(handle->base->TCD[handle->channel].DLAST_SGA);
978 }
979
980 /*!
981 * @brief eDMA IRQ handler for the current major loop transfer completion.
982 *
983 * This function clears the channel major interrupt flag and calls
984 * the callback function if it is not NULL.
985 *
986 * Note:
987 * For the case using TCD queue, when the major iteration count is exhausted, additional operations are performed.
988 * These include the final address adjustments and reloading of the BITER field into the CITER.
989 * Assertion of an optional interrupt request also occurs at this time, as does a possible fetch of a new TCD from
990 * memory using the scatter/gather address pointer included in the descriptor (if scatter/gather is enabled).
991 *
992 * For instance, when the time interrupt of TCD[0] happens, the TCD[1] has already been loaded into the eDMA engine.
993 * As sga and sga_index are calculated based on the DLAST_SGA bitfield lies in the TCD_CSR register, the sga_index
994 * in this case should be 2 (DLAST_SGA of TCD[1] stores the address of TCD[2]). Thus, the "tcdUsed" updated should be
995 * (tcdUsed - 2U) which indicates the number of TCDs can be loaded in the memory pool (because TCD[0] and TCD[1] have
996 * been loaded into the eDMA engine at this point already.).
997 *
998 * For the last two continuous ISRs in a scatter/gather process, they both load the last TCD (The last ISR does not
999 * load a new TCD) from the memory pool to the eDMA engine when major loop completes.
1000 * Therefore, ensure that the header and tcdUsed updated are identical for them.
1001 * tcdUsed are both 0 in this case as no TCD to be loaded.
1002 *
1003 * See the "eDMA basic data flow" in the eDMA Functional description section of the Reference Manual for
1004 * further details.
1005 *
1006 * @param handle eDMA handle pointer.
1007 */
1008 void EDMA_HandleIRQ(edma_handle_t *handle);
1009
1010 /* @} */
1011
1012 #if defined(__cplusplus)
1013 }
1014 #endif /* __cplusplus */
1015
1016 /* @} */
1017
1018 #endif /*_FSL_EDMA_H_*/
1019