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