1 /*
2 * Copyright 2021-2023 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #ifndef FSL_GDMA_H_
9 #define FSL_GDMA_H_
10
11 #include "fsl_common.h"
12
13 /*!
14 * @addtogroup gdma
15 * @{
16 */
17
18 /*******************************************************************************
19 * Definitions
20 ******************************************************************************/
21
22 /*! @name Driver version */
23 /*! @{ */
24 #define FSL_GDMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 3))
25 /*! @} */
26
27 /*!
28 * @brief Macro for GDMA link list descriptor LLI.
29 *
30 * This macro constructs @ref gdma_descriptor_t::lli.
31 *
32 * @param linkListAddr Address of next link list descriptor item.
33 * @param stopAfterDescFinished Stop or not after this descriptor transfer done.
34 * @param enableDescInterrupt Generate interrupt after this descriptor transfer done.
35 */
36 #define GDMA_DESC_LLI(linkListAddr, stopAfterDescFinished, enableDescInterrupt) \
37 (((uint32_t)(linkListAddr)&GDMA_LLI_LLI_MASK) | ((enableDescInterrupt) ? GDMA_LLI_DESC_INT_EN_MASK : 0UL) | \
38 ((stopAfterDescFinished) ? GDMA_LLI_STOP_MASK : 0UL))
39 /*
40 * @brief Macro for GDMA link list descriptor CTRL.
41 *
42 * This macro constructs @ref gdma_descriptor_t::ctrl.
43 *
44 * @param ahbProt GDMA AHB HPROT flags, it could be OR'ed value of @ref _gdma_ahb_prot.
45 * @param srcAddrInc Increase source address on each successive access, use true or false.
46 * @param destAddrInc Increase destination address on each successive access, use true or false.
47 * @param srcWidth Source transfer width, see @ref gdma_transfer_width_t.
48 * @param destWidth Destination transfer width, see @ref gdma_transfer_width_t.
49 * @param srcBurstSize Source address burst size, see @ref gdma_burst_size_t.
50 * @param destBurstSize Destination address burst size, see @ref gdma_burst_size_t.
51 * @param len Transfer length in bytes, max value is 8 * 1024 - 1.
52 */
53 #define GDMA_DESC_CTRL(ahbProt, srcAddrInc, destAddrInc, srcWidth, destWidth, srcBurstSize, destBurstSize, length) \
54 (GDMA_CTRL_PROT(ahbProt) | ((srcAddrInc) ? GDMA_CTRL_SRCADDRINC_MASK : 0UL) | \
55 ((destAddrInc) ? GDMA_CTRL_DESTADDRINC_MASK : 0UL) | GDMA_CTRL_SRCWIDTH(srcWidth) | \
56 GDMA_CTRL_DESTWIDTH(destWidth) | GDMA_CTRL_SRCBSIZE(srcBurstSize) | GDMA_CTRL_DESTBSIZE(destBurstSize) | \
57 GDMA_CTRL_LEN(length))
58
59 /*! @brief GDMA transfer width */
60 typedef enum _gdma_transfer_width
61 {
62 kGDMA_TransferWidth1Byte = 1U, /*!< 1 byte. */
63 kGDMA_TransferWidth2Byte = 2U, /*!< 2 bytes. */
64 kGDMA_TransferWidth4Byte = 3U, /*!< 4 bytes. */
65 } gdma_transfer_width_t;
66
67 /*! @brief GDMA burst size*/
68 typedef enum _gdma_burst_size
69 {
70 kGDMA_BurstSize1 = 0U, /*!< Burst 1. */
71 kGDMA_BurstSize4 = 1U, /*!< Burst 4. */
72 kGDMA_BurstSize8 = 2U, /*!< Burst 8. */
73 kGDMA_BurstSize16 = 3U, /*!< Burst 16. */
74 kGDMA_BurstSizeWrap4 = 5U, /*!< Wrap 4. */
75 kGDMA_BurstSizeWrap8 = 6U, /*!< Wrap 8. */
76 kGDMA_BurstSizeWrap16 = 7U, /*!< Wrap 16. */
77 } gdma_burst_size_t;
78
79 /*!
80 * @brief GDMA AHB HPROT flags.
81 * @anchor _gdma_ahb_prot
82 */
83 enum _gdma_ahb_prot
84 {
85 kGDMA_ProtUserMode = (0U << 0U), /*!< The access is in user mode. */
86 kGDMA_ProtPrevilegedMode = (1U << 0U), /*!< The access is in previleged mode. */
87 kGDMA_ProtUnbufferable = (0U << 1U), /*!< The access is not bufferable. */
88 kGDMA_ProtBufferable = (1U << 1U), /*!< The access is bufferable. */
89 kGDMA_ProtUncacheable = (0U << 2U), /*!< The access is not cacheable. */
90 kGDMA_ProtCacheable = (1U << 2U), /*!< The access is cacheable. */
91 };
92
93 /*! @brief GDMA channel link list descriptor structure */
94 typedef struct __ALIGNED(16) _gdma_descriptor
95 {
96 uint32_t srcAddr; /*!< Source address. */
97 uint32_t dstAddr; /*!< Destination address. */
98 uint32_t lli; /*!< Link list item. */
99 uint32_t ctrl; /*!< Transfer control. */
100 } gdma_descriptor_t;
101
102 /*! @brief GDMA channel priority */
103 typedef enum _gdma_priority
104 {
105 kGDMA_ChannelPriority0 = 0, /*!< Lowest channel priority - priority 0 */
106 kGDMA_ChannelPriority1, /*!< Channel priority 1 */
107 kGDMA_ChannelPriority2, /*!< Channel priority 2 */
108 kGDMA_ChannelPriority3, /*!< Channel priority 3 */
109 kGDMA_ChannelPriority4, /*!< Channel priority 4 */
110 kGDMA_ChannelPriority5, /*!< Channel priority 5 */
111 kGDMA_ChannelPriority6, /*!< Channel priority 6 */
112 kGDMA_ChannelPriority7, /*!< Channel priority 7 */
113 kGDMA_ChannelPriority8, /*!< Channel priority 8 */
114 kGDMA_ChannelPriority9, /*!< Channel priority 9 */
115 kGDMA_ChannelPriority10, /*!< Channel priority 10 */
116 kGDMA_ChannelPriority11, /*!< Channel priority 11 */
117 kGDMA_ChannelPriority12, /*!< Channel priority 12 */
118 kGDMA_ChannelPriority13, /*!< Channel priority 13 */
119 kGDMA_ChannelPriority14, /*!< Channel priority 14 */
120 kGDMA_ChannelPriority15, /*!< Highest channel priority - priority 15 */
121 } gdma_priority_t;
122
123 /*!
124 * @brief GDMA interrupts to enable
125 * @anchor _gdma_interrupt_enable
126 */
127 enum _gdma_interrupt_enable
128 {
129 /*!
130 * Descriptor transfer done interrupt. This happens when the descriptor
131 * is configured to generate interrupt when transfer done.
132 */
133 kGDMA_DescriptorTransferDoneInterruptEnable = GDMA_CHNL_INT_MASK_DESC_TFRINT_MASK,
134
135 /*! Channel source or destination address is not aligned to corresponding transfer width. */
136 kGDMA_AddressErrorInterruptEnable = GDMA_CHNL_INT_MASK_ADDRERRINT_MASK,
137
138 /*! AHB bus interrupt. */
139 kGDMA_BusErrorInterruptEnable = GDMA_CHNL_INT_MASK_BUSERRINT_MASK,
140
141 /*! DMA transfer done interrupt. */
142 kGDMA_TransferDoneInterruptEnable = GDMA_CHNL_INT_MASK_TFRINT_MASK,
143
144 /*! DMA block single/burst transfer done interrupt. */
145 kGDMA_BlockTransferDoneInterruptEnable = GDMA_CHNL_INT_MASK_BLOCKINT_MASK,
146
147 /*! All interrupt enable. */
148 kGDMA_AllInterruptEnable = kGDMA_DescriptorTransferDoneInterruptEnable | kGDMA_AddressErrorInterruptEnable |
149 kGDMA_BusErrorInterruptEnable | kGDMA_TransferDoneInterruptEnable |
150 kGDMA_BlockTransferDoneInterruptEnable,
151 };
152
153 /*!
154 * @brief GDMA interrupt status flags.
155 * @anchor _gdma_interrupt_flags
156 */
157 enum _gdma_interrupt_flags
158 {
159 /*!
160 * Descriptor transfer done interrupt. This happens when the descriptor
161 * is configured to generate interrupt when transfer done.
162 */
163 kGDMA_DescriptorTransferDoneFlag = GDMA_CHNL_INT_DESC_STATUS_TFRINT_MASK,
164
165 /*! OR of the content of the respective unmasked interrupt of channel. */
166 kGDMA_ChannelInterruptFlag = GDMA_CHNL_INT_STATUS_CHLINT_MASK,
167
168 /*! Channel source or destination address is not aligned to corresponding transfer width. */
169 kGDMA_AddressErrorFlag = GDMA_CHNL_INT_STATUS_ADDRERRINT_MASK,
170
171 /*! AHB bus interrupt. */
172 kGDMA_BusErrorFlag = GDMA_CHNL_INT_STATUS_BUSERRINT_MASK,
173
174 /*! DMA transfer done interrupt. */
175 kGDMA_TransferDoneFlag = GDMA_CHNL_INT_STATUS_TFRINT_MASK,
176
177 /*! DMA block single/burst transfer done interrupt. */
178 kGDMA_BlockTransferDoneFlag = GDMA_CHNL_INT_STATUS_BLOCKINT_MASK,
179
180 /*! All interrupt flags. */
181 kGDMA_AllInterruptFlag = kGDMA_DescriptorTransferDoneFlag | kGDMA_ChannelInterruptFlag | kGDMA_AddressErrorFlag |
182 kGDMA_BusErrorFlag | kGDMA_TransferDoneFlag | kGDMA_BlockTransferDoneFlag,
183 };
184
185 /*!
186 * @brief GDMA channel transfer configuration.
187 *
188 * @note The transfer configuration must follow the requirements:
189 * - SRCBSIZE * SRCWIDTH == DESTBSIZE * DESTWIDTH
190 * - If wrap not used, the address should align with WIDTH
191 * - If wrap used, the address should align with WIDTH * BURST_SIZE.
192 */
193 typedef struct _gdma_channel_xfer_config
194 {
195 uint32_t srcAddr; /*!< Source data address */
196 uint32_t destAddr; /*!< Destination data address */
197 uint8_t ahbProt; /*!< GDMA AHB HPROT flags, it could be OR'ed value of @ref _gdma_ahb_prot. */
198 gdma_burst_size_t srcBurstSize; /*!< Source address burst size. */
199 gdma_burst_size_t destBurstSize; /*!< Destination address burst size. */
200 gdma_transfer_width_t srcWidth; /*!< Source transfer width. */
201 gdma_transfer_width_t destWidth; /*!< Destination transfer width. */
202 bool srcAddrInc; /*!< Increase source address on each successive access. */
203 bool destAddrInc; /*!< Increase destination address on each successive access. */
204 uint16_t transferLen; /*!< Transfer length in bytes, max value is 8 * 1024 - 1, should align with transfer size. */
205 bool enableLinkList; /*!< Enable link list or not. */
206
207 /*! Generate interrupt when descriptor transfer finished, only used when @ref enableLinkList is true. */
208 bool enableDescInterrupt;
209
210 /*! Stop channel when descriptor transfer finished, only used when @ref enableLinkList is true. */
211 bool stopAfterDescFinished;
212
213 uint32_t linkListAddr; /*!< Link list address, only used when @ref enableLinkList is true. */
214 } gdma_channel_xfer_config_t;
215
216 /*! @brief Driver handle for GDMA */
217 struct _gdma_handle;
218
219 /*! @brief Define Callback function for GDMA.
220 *
221 * handle: Pointer to the GDMA driver handle.
222 * userData: The userData registered using @ref GDMA_SetCallback.
223 * interrupts: The interrupts flags of the specific channel.
224 */
225 typedef void (*gdma_callback_t)(struct _gdma_handle *handle, void *userData, uint32_t interrupts);
226
227 /*! @brief GDMA transfer handle structure */
228 typedef struct _gdma_handle
229 {
230 GDMA_Type *gdma; /*!< GDMA peripheral base address */
231 uint8_t channel; /*!< GDMA channel number */
232 gdma_callback_t callback; /*!< Callback function. Invoked interrupt happens. */
233 void *userData; /*!< Callback function parameter */
234 } gdma_handle_t;
235
236 /*******************************************************************************
237 * APIs
238 ******************************************************************************/
239 #if defined(__cplusplus)
240 extern "C" {
241 #endif /* __cplusplus */
242
243 /*!
244 * @name GDMA initialization and De-initialization
245 * @{
246 */
247
248 /*!
249 * @brief Initializes GDMA peripheral.
250 *
251 * It ungates the GDMA access clock, after this function, the GDMA module is
252 * ready to be used.
253 *
254 * @param base GDMA peripheral base address.
255 */
256 void GDMA_Init(GDMA_Type *base);
257
258 /*!
259 * @brief Deinitializes GDMA peripheral.
260 *
261 * @param base GDMA peripheral base address.
262 */
263 void GDMA_Deinit(GDMA_Type *base);
264
265 /*! @} */
266
267 /*!
268 * @name GDMA Channel Operation
269 * @{
270 */
271
272 /*!
273 * @brief Set GDMA channel source address.
274 *
275 * @param base GDMA peripheral base address.
276 * @param channel GDMA channel number.
277 * @param addr Source address.
278 */
GDMA_SetChannelSourceAddress(GDMA_Type * base,uint8_t channel,uint32_t addr)279 static inline void GDMA_SetChannelSourceAddress(GDMA_Type *base, uint8_t channel, uint32_t addr)
280 {
281 base->CH[channel].SADR = addr;
282 }
283
284 /*!
285 * @brief Set GDMA channel destination address.
286 *
287 * @param base GDMA peripheral base address.
288 * @param channel GDMA channel number.
289 * @param addr Destination address.
290 */
GDMA_SetChannelDestAddress(GDMA_Type * base,uint8_t channel,uint32_t addr)291 static inline void GDMA_SetChannelDestAddress(GDMA_Type *base, uint8_t channel, uint32_t addr)
292 {
293 base->CH[channel].DADR = addr;
294 }
295
296 /*!
297 * @brief Start GDMA channel to work.
298 *
299 * @param base GDMA peripheral base address.
300 * @param channel GDMA channel number.
301 */
GDMA_StartChannel(GDMA_Type * base,uint8_t channel)302 static inline void GDMA_StartChannel(GDMA_Type *base, uint8_t channel)
303 {
304 base->CH[channel].CHL_EN |= GDMA_CHL_EN_CHL_EN_MASK;
305 }
306
307 /*!
308 * @brief Stop GDMA channel.
309 *
310 * @param base GDMA peripheral base address.
311 * @param channel GDMA channel number.
312 */
GDMA_StopChannel(GDMA_Type * base,uint8_t channel)313 static inline void GDMA_StopChannel(GDMA_Type *base, uint8_t channel)
314 {
315 base->CH[channel].CHL_STOP = GDMA_CHL_STOP_CHL_STOP_MASK;
316 }
317
318 /*!
319 * @brief Return whether GDMA channel is processing transfer
320 *
321 * When @ref GDMA_StopChannel is called, if the channel is on service,
322 * it does not stop immediately, application could call this API to check
323 * whether the channel is stopped.
324 *
325 * @param base GDMA peripheral base address.
326 * @param channel GDMA channel number.
327 * @return True if the channel is busy, false if not.
328 */
GDMA_IsChannelBusy(GDMA_Type * base,uint8_t channel)329 static inline bool GDMA_IsChannelBusy(GDMA_Type *base, uint8_t channel)
330 {
331 return ((base->CH[channel].CHL_EN & GDMA_CHL_EN_CHL_EN_MASK) != 0UL);
332 }
333
334 /*!
335 * @brief Enables the interrupt for the GDMA transfer.
336 *
337 * @param base GDMA peripheral base address.
338 * @param channel GDMA channel number.
339 * @param interrupts The interrupts to enable, it is OR'ed value of @ref _gdma_interrupt_enable.
340 */
GDMA_EnableChannelInterrupts(GDMA_Type * base,uint8_t channel,uint32_t interrupts)341 static inline void GDMA_EnableChannelInterrupts(GDMA_Type *base, uint8_t channel, uint32_t interrupts)
342 {
343 base->CH[channel].CHNL_INT |= interrupts;
344 }
345
346 /*!
347 * @brief Disables the interrupt for the GDMA transfer.
348 *
349 * @param base GDMA peripheral base address.
350 * @param channel GDMA channel number.
351 * @param interrupts The interrupts to disable, it is OR'ed value of @ref _gdma_interrupt_enable.
352 */
GDMA_DisableChannelInterrupts(GDMA_Type * base,uint8_t channel,uint32_t interrupts)353 static inline void GDMA_DisableChannelInterrupts(GDMA_Type *base, uint8_t channel, uint32_t interrupts)
354 {
355 base->CH[channel].CHNL_INT &= ~interrupts;
356 }
357
358 /*!
359 * @brief Get the GDMA channel interrupt flags.
360 *
361 * @param base GDMA peripheral base address.
362 * @param channel GDMA channel number.
363 * @return The interrupt flags, it is OR'ed value of @ref _gdma_interrupt_flags.
364 */
GDMA_GetChannelInterruptFlags(GDMA_Type * base,uint8_t channel)365 static inline uint32_t GDMA_GetChannelInterruptFlags(GDMA_Type *base, uint8_t channel)
366 {
367 return base->CH[channel].CHNL_INT & (uint32_t)kGDMA_AllInterruptFlag;
368 }
369
370 /*!
371 * @brief Clear the GDMA channel interrupt flags.
372 *
373 * The @ref kGDMA_ChannelInterruptFlag is OR'ed status of all other unmasked interrupt flags,
374 * it could not be clear directly, it should be cleared by clear all other flags.
375 *
376 * @param base GDMA peripheral base address.
377 * @param channel GDMA channel number.
378 * @param flags The interrupt flags to clear, it is OR'ed value of @ref _gdma_interrupt_flags.
379 */
GDMA_ClearChannelInterruptFlags(GDMA_Type * base,uint8_t channel,uint32_t flags)380 static inline void GDMA_ClearChannelInterruptFlags(GDMA_Type *base, uint8_t channel, uint32_t flags)
381 {
382 base->CH[channel].CHNL_INT = (base->CH[channel].CHNL_INT & ~(uint32_t)kGDMA_AllInterruptFlag) | flags;
383 }
384
385 /*!
386 * @brief Get the number of finished descriptor.
387 *
388 * The counter increases when an item of descriptor is done in linklist mode.
389 *
390 * @param base GDMA peripheral base address.
391 * @param channel GDMA channel number.
392 * @return Number of finished descriptor.
393 */
GDMA_GetChannelFinishedDescriptorNumber(GDMA_Type * base,uint8_t channel)394 static inline uint32_t GDMA_GetChannelFinishedDescriptorNumber(GDMA_Type *base, uint8_t channel)
395 {
396 return base->CH[channel].NUM_OF_DESCRIPTOR;
397 }
398
399 /*!
400 * @brief Clear the number of finished descriptor.
401 *
402 * @param base GDMA peripheral base address.
403 * @param channel GDMA channel number.
404 */
GDMA_ClearChannelFinishedDescriptorNumber(GDMA_Type * base,uint8_t channel)405 static inline void GDMA_ClearChannelFinishedDescriptorNumber(GDMA_Type *base, uint8_t channel)
406 {
407 base->CH[channel].NUM_OF_DESCRIPTOR = 0UL;
408 }
409
410 /*!
411 * @brief Set priority of channel.
412 *
413 * @param base GDMA peripheral base address.
414 * @param channel GDMA channel number.
415 * @param priority Channel priority value.
416 */
GDMA_SetChannelPriority(GDMA_Type * base,uint8_t channel,gdma_priority_t priority)417 static inline void GDMA_SetChannelPriority(GDMA_Type *base, uint8_t channel, gdma_priority_t priority)
418 {
419 base->CH[channel].CHL_EN =
420 (base->CH[channel].CHL_EN & ~(GDMA_CHL_EN_CHL_PRIORITY_WEIGHT_MASK | GDMA_CHL_EN_CHL_EN_MASK)) |
421 (uint32_t)priority;
422 }
423
424 /*!
425 * @brief Set channel transfer configuration..
426 *
427 * This function configures the channel transfer, after configured, @ref GDMA_StartChannel
428 * could be called to start the transfer.
429 *
430 * This function must be called when previous transfer finished. Application can use
431 * @ref GDMA_IsChannelBusy to check whether the channel has finished the previous work.
432 *
433 * @note The transfer configuration must follow the requirements:
434 * - SRCBSIZE * SRCWIDTH == DESTBSIZE * DESTWIDTH
435 * - If wrap not used, the address should align with WIDTH
436 * - If wrap used, the address should align with WIDTH * BURST_SIZE.
437 *
438 * @param base GDMA base address.
439 * @param channel GDMA channel number.
440 * @config Pointer to the transfer configuration.
441 * @retval kStatus_Fail GDMA is busy with previous transfer.
442 * @retval kStatus_Success Configuration set successfully.
443 * @retval kStatus_InvalidArgument Configuration wrong.
444 */
445 status_t GDMA_SetChannelTransferConfig(GDMA_Type *base, uint8_t channel, const gdma_channel_xfer_config_t *config);
446
447 /*! @} */
448
449 /*!
450 * @name GDMA Transactional Operation
451 * @{
452 */
453
454 /*!
455 * @brief Creates the GDMA handle.
456 *
457 * This function is called if using transaction API for GDMA. This function
458 * initializes the internal state of GDMA handle.
459 *
460 * @param handle GDMA handle pointer. It stores callback function and parameters.
461 * @param base GDMA peripheral base address.
462 * @param channel GDMA channel number.
463 */
464 void GDMA_CreateHandle(gdma_handle_t *handle, GDMA_Type *base, uint8_t channel);
465
466 /*!
467 * @brief Installs a callback function for the GDMA transfer.
468 *
469 * This callback is called in GDMA IRQ handler to inform user the interrupt status.
470 *
471 * @param handle GDMA handle pointer.
472 * @param callback GDMA callback function pointer.
473 * @param userData Parameter for callback function.
474 */
475 void GDMA_SetCallback(gdma_handle_t *handle, gdma_callback_t callback, void *userData);
476
477 /*!
478 * @brief Submits the GDMA channel transfer request.
479 *
480 * After this function, user could call @ref GDMA_StartTransfer to start GDMA transfer.
481 *
482 * This function must be called when previous transfer finished. Application can use
483 * @ref GDMA_IsChannelBusy to check whether the channel has finished the previous work.
484 *
485 * @note The transfer configuration must follow the requirements:
486 * - SRCBSIZE * SRCWIDTH == DESTBSIZE * DESTWIDTH
487 * - If wrap not used, the address should align with WIDTH
488 * - If wrap used, the address should align with WIDTH * BURST_SIZE.
489 *
490 * @param handle GDMA handle pointer.
491 * @param config Pointer to GDMA transfer configuration structure.
492 * @retval kStatus_Fail GDMA is busy with previous transfer.
493 * @retval kStatus_Success Configuration set successfully.
494 * @retval kStatus_InvalidArgument Configuration wrong.
495 */
496 status_t GDMA_SubmitTransfer(gdma_handle_t *handle, gdma_channel_xfer_config_t *config);
497
498 /*!
499 * @brief GDMA start transfer.
500 *
501 * User can call this function after @ref GDMA_SubmitTransfer.
502 *
503 * @param handle GDMA handle pointer.
504 */
505 void GDMA_StartTransfer(gdma_handle_t *handle);
506
507 /*!
508 * @brief Abort running transfer by handle.
509 *
510 * When this function is called, if the channel is on service, it only
511 * stops when service finished.
512 *
513 * @param handle GDMA handle pointer.
514 */
515 void GDMA_AbortTransfer(gdma_handle_t *handle);
516
517 /*!
518 * @brief GDMA IRQ handler.
519 *
520 * This function checks all GDMA channel interrupts and inform application
521 * the interrupt flags through user registered callback.
522 *
523 * @param base GDMA peripheral.
524 */
525 void GDMA_IRQHandle(GDMA_Type *base);
526
527 /*! @} */
528
529 #if defined(__cplusplus)
530 }
531 #endif /* __cplusplus */
532
533 /*! @} */
534
535 #endif /*FSL_GDMA_H_*/
536