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 #include "fsl_dma.h"
10 #if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET)
11 #include "fsl_memory.h"
12 #endif
13
14 /*******************************************************************************
15 * Definitions
16 ******************************************************************************/
17
18 /* Component ID definition, used by tools. */
19 #ifndef FSL_COMPONENT_ID
20 #define FSL_COMPONENT_ID "platform.drivers.lpc_dma"
21 #endif
22
23 /*******************************************************************************
24 * Prototypes
25 ******************************************************************************/
26
27 /*!
28 * @brief Get instance number for DMA.
29 *
30 * @param base DMA peripheral base address.
31 */
32 static uint32_t DMA_GetInstance(DMA_Type *base);
33
34 /*!
35 * @brief Get virtual channel number.
36 *
37 * @param base DMA peripheral base address.
38 */
39 static uint32_t DMA_GetVirtualStartChannel(DMA_Type *base);
40
41 /*******************************************************************************
42 * Variables
43 ******************************************************************************/
44
45 /*! @brief Array to map DMA instance number to base pointer. */
46 static DMA_Type *const s_dmaBases[] = DMA_BASE_PTRS;
47
48 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
49 /*! @brief Array to map DMA instance number to clock name. */
50 static const clock_ip_name_t s_dmaClockName[] = DMA_CLOCKS;
51 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
52
53 #if !(defined(FSL_FEATURE_DMA_HAS_NO_RESET) && FSL_FEATURE_DMA_HAS_NO_RESET)
54 /*! @brief Pointers to DMA resets for each instance. */
55 static const reset_ip_name_t s_dmaResets[] = DMA_RSTS_N;
56 #endif /*! @brief Array to map DMA instance number to IRQ number. */
57 static const IRQn_Type s_dmaIRQNumber[] = DMA_IRQS;
58
59 /*! @brief Pointers to transfer handle for each DMA channel. */
60 static dma_handle_t *s_DMAHandle[FSL_FEATURE_DMA_ALL_CHANNELS];
61
62 /*! @brief DMA driver internal descriptor table */
63 #ifdef FSL_FEATURE_DMA0_DESCRIPTOR_ALIGN_SIZE
64 SDK_ALIGN(static dma_descriptor_t s_dma_descriptor_table0[FSL_FEATURE_DMA_MAX_CHANNELS],
65 FSL_FEATURE_DMA0_DESCRIPTOR_ALIGN_SIZE);
66 #else
67 #if (defined(CPU_MIMXRT685SEVKA_dsp) || defined(CPU_MIMXRT685SFVKB_dsp))
68 AT_NONCACHEABLE_SECTION_ALIGN(static dma_descriptor_t s_dma_descriptor_table0[FSL_FEATURE_DMA_MAX_CHANNELS],
69 FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE);
70 #else
71 SDK_ALIGN(static dma_descriptor_t s_dma_descriptor_table0[FSL_FEATURE_DMA_MAX_CHANNELS],
72 FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE);
73 #endif /* (defined(CPU_MIMXRT685SEVKA_dsp) || defined(CPU_MIMXRT685SFVKB_dsp)) */
74 #endif /* FSL_FEATURE_DMA0_DESCRIPTOR_ALIGN_SIZE */
75
76 #if defined(DMA1)
77 #ifdef FSL_FEATURE_DMA1_DESCRIPTOR_ALIGN_SIZE
78 SDK_ALIGN(static dma_descriptor_t s_dma_descriptor_table1[FSL_FEATURE_DMA_MAX_CHANNELS],
79 FSL_FEATURE_DMA1_DESCRIPTOR_ALIGN_SIZE);
80 #else
81 #if (defined(CPU_MIMXRT685SEVKA_dsp) || defined(CPU_MIMXRT685SFVKB_dsp))
82 AT_NONCACHEABLE_SECTION_ALIGN(static dma_descriptor_t s_dma_descriptor_table1[FSL_FEATURE_DMA_MAX_CHANNELS],
83 FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE);
84 #else
85 SDK_ALIGN(static dma_descriptor_t s_dma_descriptor_table1[FSL_FEATURE_DMA_MAX_CHANNELS],
86 FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE);
87 #endif /* (defined(CPU_MIMXRT685SEVKA_dsp) || defined(CPU_MIMXRT685SFVKB_dsp)) */
88 #endif /* FSL_FEATURE_DMA1_DESCRIPTOR_ALIGN_SIZE */
89 static dma_descriptor_t *s_dma_descriptor_table[] = {s_dma_descriptor_table0, s_dma_descriptor_table1};
90 #else
91 static dma_descriptor_t *s_dma_descriptor_table[] = {s_dma_descriptor_table0};
92 #endif
93
94 /*******************************************************************************
95 * Code
96 ******************************************************************************/
97
DMA_GetInstance(DMA_Type * base)98 static uint32_t DMA_GetInstance(DMA_Type *base)
99 {
100 uint32_t instance;
101 /* Find the instance index from base address mappings. */
102 for (instance = 0; instance < ARRAY_SIZE(s_dmaBases); instance++)
103 {
104 if (s_dmaBases[instance] == base)
105 {
106 break;
107 }
108 }
109 assert(instance < ARRAY_SIZE(s_dmaBases));
110
111 return instance;
112 }
113
DMA_GetVirtualStartChannel(DMA_Type * base)114 static uint32_t DMA_GetVirtualStartChannel(DMA_Type *base)
115 {
116 uint32_t startChannel = 0, instance = 0;
117 uint32_t i = 0;
118
119 instance = DMA_GetInstance(base);
120
121 /* Compute start channel */
122 for (i = 0; i < instance; i++)
123 {
124 startChannel += (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(s_dmaBases[i]);
125 }
126
127 return startChannel;
128 }
129
130 /*!
131 * brief Initializes DMA peripheral.
132 *
133 * This function enable the DMA clock, set descriptor table and
134 * enable DMA peripheral.
135 *
136 * param base DMA peripheral base address.
137 */
DMA_Init(DMA_Type * base)138 void DMA_Init(DMA_Type *base)
139 {
140 uint32_t instance = DMA_GetInstance(base);
141 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
142 /* enable dma clock gate */
143 CLOCK_EnableClock(s_dmaClockName[DMA_GetInstance(base)]);
144 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
145
146 #if !(defined(FSL_FEATURE_DMA_HAS_NO_RESET) && FSL_FEATURE_DMA_HAS_NO_RESET)
147 /* Reset the DMA module */
148 RESET_PeripheralReset(s_dmaResets[DMA_GetInstance(base)]);
149 #endif
150 /* set descriptor table */
151 #if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET)
152 base->SRAMBASE = MEMORY_ConvertMemoryMapAddress((uint32_t)s_dma_descriptor_table[instance], kMEMORY_Local2DMA);
153 #else
154 base->SRAMBASE = (uint32_t)s_dma_descriptor_table[instance];
155 #endif
156 /* enable dma peripheral */
157 base->CTRL |= DMA_CTRL_ENABLE_MASK;
158 }
159
160 /*!
161 * brief Deinitializes DMA peripheral.
162 *
163 * This function gates the DMA clock.
164 *
165 * param base DMA peripheral base address.
166 */
DMA_Deinit(DMA_Type * base)167 void DMA_Deinit(DMA_Type *base)
168 {
169 /* Disable DMA peripheral */
170 base->CTRL &= ~(DMA_CTRL_ENABLE_MASK);
171 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
172 CLOCK_DisableClock(s_dmaClockName[DMA_GetInstance(base)]);
173 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
174 }
175
176 /*!
177 * brief Set trigger settings of DMA channel.
178 * deprecated Do not use this function. It has been superceded by @ref DMA_SetChannelConfig.
179 *
180 * param base DMA peripheral base address.
181 * param channel DMA channel number.
182 * param trigger trigger configuration.
183 */
DMA_ConfigureChannelTrigger(DMA_Type * base,uint32_t channel,dma_channel_trigger_t * trigger)184 void DMA_ConfigureChannelTrigger(DMA_Type *base, uint32_t channel, dma_channel_trigger_t *trigger)
185 {
186 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base) != -1);
187 assert((channel < (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base)) && (NULL != trigger));
188
189 uint32_t tmpReg = (DMA_CHANNEL_CFG_HWTRIGEN_MASK | DMA_CHANNEL_CFG_TRIGPOL_MASK | DMA_CHANNEL_CFG_TRIGTYPE_MASK |
190 DMA_CHANNEL_CFG_TRIGBURST_MASK | DMA_CHANNEL_CFG_BURSTPOWER_MASK |
191 DMA_CHANNEL_CFG_SRCBURSTWRAP_MASK | DMA_CHANNEL_CFG_DSTBURSTWRAP_MASK);
192 tmpReg = base->CHANNEL[channel].CFG & (~tmpReg);
193 tmpReg |= (uint32_t)(trigger->type) | (uint32_t)(trigger->burst) | (uint32_t)(trigger->wrap);
194 base->CHANNEL[channel].CFG = tmpReg;
195 }
196
197 /*!
198 * brief Gets the remaining bytes of the current DMA descriptor transfer.
199 *
200 * param base DMA peripheral base address.
201 * param channel DMA channel number.
202 * return The number of bytes which have not been transferred yet.
203 */
DMA_GetRemainingBytes(DMA_Type * base,uint32_t channel)204 uint32_t DMA_GetRemainingBytes(DMA_Type *base, uint32_t channel)
205 {
206 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base) != -1);
207 assert(channel < (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
208
209 /* NOTE: when descriptors are chained, ACTIVE bit is set for whole chain. It makes
210 * impossible to distinguish between:
211 * - transfer finishes (represented by value '0x3FF')
212 * - and remaining 1024 bytes to transfer (value 0x3FF)
213 * for all descriptor in chain, except the last one.
214 * If you decide to use this function, please use 1023 transfers as maximal value */
215
216 /* Channel not active (transfer finished) and value is 0x3FF - nothing to transfer */
217 if ((!DMA_ChannelIsActive(base, channel)) &&
218 (0x3FFUL == ((base->CHANNEL[channel].XFERCFG & DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK) >>
219 DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT)))
220 {
221 return 0UL;
222 }
223
224 return ((base->CHANNEL[channel].XFERCFG & DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK) >>
225 DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT) +
226 1UL;
227 }
228
229 /* Verify and convert dma_xfercfg_t to XFERCFG register */
DMA_SetupXferCFG(dma_xfercfg_t * xfercfg,uint32_t * xfercfg_addr)230 static void DMA_SetupXferCFG(dma_xfercfg_t *xfercfg, uint32_t *xfercfg_addr)
231 {
232 assert(xfercfg != NULL);
233 /* check source increment */
234 assert((xfercfg->srcInc <= (uint8_t)kDMA_AddressInterleave4xWidth) &&
235 (xfercfg->dstInc <= (uint8_t)kDMA_AddressInterleave4xWidth));
236 /* check data width */
237 assert(xfercfg->byteWidth <= (uint8_t)kDMA_Transfer32BitWidth);
238 /* check transfer count */
239 assert(xfercfg->transferCount <= DMA_MAX_TRANSFER_COUNT);
240
241 uint32_t xfer = 0;
242
243 /* set valid flag - descriptor is ready now */
244 xfer |= DMA_CHANNEL_XFERCFG_CFGVALID(xfercfg->valid);
245 /* set reload - allow link to next descriptor */
246 xfer |= DMA_CHANNEL_XFERCFG_RELOAD(xfercfg->reload);
247 /* set swtrig flag - start transfer */
248 xfer |= DMA_CHANNEL_XFERCFG_SWTRIG(xfercfg->swtrig);
249 /* set transfer count */
250 xfer |= DMA_CHANNEL_XFERCFG_CLRTRIG(xfercfg->clrtrig);
251 /* set INTA */
252 xfer |= DMA_CHANNEL_XFERCFG_SETINTA(xfercfg->intA);
253 /* set INTB */
254 xfer |= DMA_CHANNEL_XFERCFG_SETINTB(xfercfg->intB);
255 /* set data width */
256 xfer |= DMA_CHANNEL_XFERCFG_WIDTH(xfercfg->byteWidth == 4U ? 2U : xfercfg->byteWidth - 1UL);
257 /* set source increment value */
258 xfer |= DMA_CHANNEL_XFERCFG_SRCINC(
259 (xfercfg->srcInc == (uint8_t)kDMA_AddressInterleave4xWidth) ? (xfercfg->srcInc - 1UL) : xfercfg->srcInc);
260 /* set destination increment value */
261 xfer |= DMA_CHANNEL_XFERCFG_DSTINC(
262 (xfercfg->dstInc == (uint8_t)kDMA_AddressInterleave4xWidth) ? (xfercfg->dstInc - 1UL) : xfercfg->dstInc);
263 /* set transfer count */
264 xfer |= DMA_CHANNEL_XFERCFG_XFERCOUNT(xfercfg->transferCount - 1UL);
265
266 /* store xferCFG */
267 *xfercfg_addr = xfer;
268 }
269
270 /*!
271 * brief setup dma descriptor
272 * Note: This function do not support configure wrap descriptor.
273 * param desc DMA descriptor address.
274 * param xfercfg Transfer configuration for DMA descriptor.
275 * param srcStartAddr Start address of source address.
276 * param dstStartAddr Start address of destination address.
277 * param nextDesc Address of next descriptor in chain.
278 */
DMA_SetupDescriptor(dma_descriptor_t * desc,uint32_t xfercfg,void * srcStartAddr,void * dstStartAddr,void * nextDesc)279 void DMA_SetupDescriptor(
280 dma_descriptor_t *desc, uint32_t xfercfg, void *srcStartAddr, void *dstStartAddr, void *nextDesc)
281 {
282 assert((((uint32_t)(uint32_t *)nextDesc) & ((uint32_t)FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE - 1UL)) == 0UL);
283
284 #if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET)
285 srcStartAddr = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)srcStartAddr, kMEMORY_Local2DMA);
286 dstStartAddr = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)dstStartAddr, kMEMORY_Local2DMA);
287 nextDesc = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)nextDesc, kMEMORY_Local2DMA);
288 #endif
289
290 uint32_t width = 0, srcInc = 0, dstInc = 0, transferCount = 0;
291
292 width = (xfercfg & DMA_CHANNEL_XFERCFG_WIDTH_MASK) >> DMA_CHANNEL_XFERCFG_WIDTH_SHIFT;
293 srcInc = (xfercfg & DMA_CHANNEL_XFERCFG_SRCINC_MASK) >> DMA_CHANNEL_XFERCFG_SRCINC_SHIFT;
294 dstInc = (xfercfg & DMA_CHANNEL_XFERCFG_DSTINC_MASK) >> DMA_CHANNEL_XFERCFG_DSTINC_SHIFT;
295 transferCount = ((xfercfg & DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK) >> DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT) + 1U;
296
297 /* covert register value to actual value */
298 if (width == 2U)
299 {
300 width = kDMA_Transfer32BitWidth;
301 }
302 else
303 {
304 width += 1U;
305 }
306
307 /*
308 * Transfers of 16 bit width require an address alignment to a multiple of 2 bytes.
309 * Transfers of 32 bit width require an address alignment to a multiple of 4 bytes.
310 * Transfers of 8 bit width can be at any address
311 */
312 if (((NULL != srcStartAddr) && (0UL == ((uint32_t)(uint32_t *)srcStartAddr) % width)) &&
313 ((NULL != dstStartAddr) && (0UL == ((uint32_t)(uint32_t *)dstStartAddr) % width)))
314 {
315 if (srcInc == 3U)
316 {
317 srcInc = kDMA_AddressInterleave4xWidth;
318 }
319
320 if (dstInc == 3U)
321 {
322 dstInc = kDMA_AddressInterleave4xWidth;
323 }
324
325 desc->xfercfg = xfercfg;
326 desc->srcEndAddr = DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)srcStartAddr, srcInc, transferCount * width, width);
327 desc->dstEndAddr = DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)dstStartAddr, dstInc, transferCount * width, width);
328 desc->linkToNextDesc = nextDesc;
329 }
330 else
331 {
332 /* if address alignment not satisfy the requirement, reset the descriptor to make sure DMA generate error */
333 desc->xfercfg = 0U;
334 desc->srcEndAddr = NULL;
335 desc->dstEndAddr = NULL;
336 }
337 }
338
339 /*!
340 * brief setup dma channel descriptor
341 * Note: This function support configure wrap descriptor.
342 * param desc DMA descriptor address.
343 * param xfercfg Transfer configuration for DMA descriptor.
344 * param srcStartAddr Start address of source address.
345 * param dstStartAddr Start address of destination address.
346 * param nextDesc Address of next descriptor in chain.
347 * param wrapType burst wrap type.
348 * param burstSize burst size, reference _dma_burst_size.
349 */
DMA_SetupChannelDescriptor(dma_descriptor_t * desc,uint32_t xfercfg,void * srcStartAddr,void * dstStartAddr,void * nextDesc,dma_burst_wrap_t wrapType,uint32_t burstSize)350 void DMA_SetupChannelDescriptor(dma_descriptor_t *desc,
351 uint32_t xfercfg,
352 void *srcStartAddr,
353 void *dstStartAddr,
354 void *nextDesc,
355 dma_burst_wrap_t wrapType,
356 uint32_t burstSize)
357 {
358 assert((((uint32_t)(uint32_t *)nextDesc) & ((uint32_t)FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE - 1UL)) == 0UL);
359
360 #if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET)
361 srcStartAddr = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)srcStartAddr, kMEMORY_Local2DMA);
362 dstStartAddr = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)dstStartAddr, kMEMORY_Local2DMA);
363 nextDesc = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)nextDesc, kMEMORY_Local2DMA);
364 #endif
365
366 uint32_t width = 0, srcInc = 0, dstInc = 0, transferCount = 0;
367
368 width = (xfercfg & DMA_CHANNEL_XFERCFG_WIDTH_MASK) >> DMA_CHANNEL_XFERCFG_WIDTH_SHIFT;
369 srcInc = (xfercfg & DMA_CHANNEL_XFERCFG_SRCINC_MASK) >> DMA_CHANNEL_XFERCFG_SRCINC_SHIFT;
370 dstInc = (xfercfg & DMA_CHANNEL_XFERCFG_DSTINC_MASK) >> DMA_CHANNEL_XFERCFG_DSTINC_SHIFT;
371 transferCount = ((xfercfg & DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK) >> DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT) + 1U;
372
373 /* covert register value to actual value */
374 if (width == 2U)
375 {
376 width = kDMA_Transfer32BitWidth;
377 }
378 else
379 {
380 width += 1U;
381 }
382
383 /*
384 * Transfers of 16 bit width require an address alignment to a multiple of 2 bytes.
385 * Transfers of 32 bit width require an address alignment to a multiple of 4 bytes.
386 * Transfers of 8 bit width can be at any address
387 */
388 if (((NULL != srcStartAddr) && (0UL == ((uint32_t)(uint32_t *)srcStartAddr) % width)) &&
389 ((NULL != dstStartAddr) && (0UL == ((uint32_t)(uint32_t *)dstStartAddr) % width)))
390 {
391 if (srcInc == 3U)
392 {
393 srcInc = kDMA_AddressInterleave4xWidth;
394 }
395
396 if (dstInc == 3U)
397 {
398 dstInc = kDMA_AddressInterleave4xWidth;
399 }
400
401 desc->xfercfg = xfercfg;
402
403 if (wrapType == kDMA_NoWrap)
404 {
405 desc->srcEndAddr =
406 DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)srcStartAddr, srcInc, transferCount * width, width);
407 desc->dstEndAddr =
408 DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)dstStartAddr, dstInc, transferCount * width, width);
409 }
410 /* for the wrap transfer, the destination address should be determined by the burstSize/width/interleave size */
411 if (wrapType == kDMA_SrcWrap)
412 {
413 desc->srcEndAddr =
414 (uint32_t *)((uint32_t)(uint32_t *)srcStartAddr + ((1UL << burstSize) - 1UL) * width * srcInc);
415 desc->dstEndAddr =
416 DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)dstStartAddr, dstInc, transferCount * width, width);
417 }
418 if (wrapType == kDMA_DstWrap)
419 {
420 desc->srcEndAddr =
421 DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)srcStartAddr, srcInc, transferCount * width, width);
422 desc->dstEndAddr =
423 (uint32_t *)((uint32_t)(uint32_t *)dstStartAddr + ((1UL << burstSize) - 1UL) * width * dstInc);
424 }
425 if (wrapType == kDMA_SrcAndDstWrap)
426 {
427 desc->srcEndAddr =
428 (uint32_t *)(((uint32_t)(uint32_t *)srcStartAddr) + ((1UL << burstSize) - 1UL) * width * srcInc);
429 desc->dstEndAddr =
430 (uint32_t *)(((uint32_t)(uint32_t *)dstStartAddr) + ((1UL << burstSize) - 1UL) * width * dstInc);
431 }
432
433 desc->linkToNextDesc = nextDesc;
434 }
435 else
436 {
437 /* if address alignment not satisfy the requirement, reset the descriptor to make sure DMA generate error */
438 desc->xfercfg = 0U;
439 desc->srcEndAddr = NULL;
440 desc->dstEndAddr = NULL;
441 }
442 }
443
444 /*!
445 * brief Create application specific DMA descriptor
446 * to be used in a chain in transfer
447 * deprecated Do not use this function. It has been superceded by @ref DMA_SetupDescriptor
448 * param desc DMA descriptor address.
449 * param xfercfg Transfer configuration for DMA descriptor.
450 * param srcAddr Address of last item to transmit
451 * param dstAddr Address of last item to receive.
452 * param nextDesc Address of next descriptor in chain.
453 */
DMA_CreateDescriptor(dma_descriptor_t * desc,dma_xfercfg_t * xfercfg,void * srcAddr,void * dstAddr,void * nextDesc)454 void DMA_CreateDescriptor(dma_descriptor_t *desc, dma_xfercfg_t *xfercfg, void *srcAddr, void *dstAddr, void *nextDesc)
455 {
456 assert((((uint32_t)(uint32_t *)nextDesc) & ((uint32_t)FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE - 1UL)) == 0UL);
457 assert((NULL != srcAddr) && (0UL == ((uint32_t)(uint32_t *)srcAddr) % xfercfg->byteWidth));
458 assert((NULL != dstAddr) && (0UL == ((uint32_t)(uint32_t *)dstAddr) % xfercfg->byteWidth));
459
460 uint32_t xfercfg_reg = 0;
461
462 DMA_SetupXferCFG(xfercfg, &xfercfg_reg);
463
464 /* Set descriptor structure */
465 DMA_SetupDescriptor(desc, xfercfg_reg, srcAddr, dstAddr, nextDesc);
466 }
467
468 /*!
469 * brief Abort running transfer by handle.
470 *
471 * This function aborts DMA transfer specified by handle.
472 *
473 * param handle DMA handle pointer.
474 */
DMA_AbortTransfer(dma_handle_t * handle)475 void DMA_AbortTransfer(dma_handle_t *handle)
476 {
477 assert(NULL != handle);
478
479 DMA_DisableChannel(handle->base, handle->channel);
480 while ((DMA_COMMON_CONST_REG_GET(handle->base, handle->channel, BUSY) &
481 (1UL << DMA_CHANNEL_INDEX(handle->base, handle->channel))) != 0UL)
482 {
483 }
484 DMA_COMMON_REG_SET(handle->base, handle->channel, ABORT, 1UL << DMA_CHANNEL_INDEX(handle->base, handle->channel));
485 DMA_EnableChannel(handle->base, handle->channel);
486 }
487
488 /*!
489 * brief Creates the DMA handle.
490 *
491 * This function is called if using transaction API for DMA. This function
492 * initializes the internal state of DMA handle.
493 *
494 * param handle DMA handle pointer. The DMA handle stores callback function and
495 * parameters.
496 * param base DMA peripheral base address.
497 * param channel DMA channel number.
498 */
DMA_CreateHandle(dma_handle_t * handle,DMA_Type * base,uint32_t channel)499 void DMA_CreateHandle(dma_handle_t *handle, DMA_Type *base, uint32_t channel)
500 {
501 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base) != -1);
502 assert((NULL != handle) && (channel < (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base)));
503
504 uint32_t dmaInstance;
505 uint32_t startChannel = 0;
506 /* base address is invalid DMA instance */
507 dmaInstance = DMA_GetInstance(base);
508 startChannel = DMA_GetVirtualStartChannel(base);
509
510 (void)memset(handle, 0, sizeof(*handle));
511 handle->base = base;
512 handle->channel = (uint8_t)channel;
513 s_DMAHandle[startChannel + channel] = handle;
514 /* Enable NVIC interrupt */
515 (void)EnableIRQ(s_dmaIRQNumber[dmaInstance]);
516 /* Enable channel interrupt */
517 DMA_EnableChannelInterrupts(handle->base, channel);
518 }
519
520 /*!
521 * brief Installs a callback function for the DMA transfer.
522 *
523 * This callback is called in DMA IRQ handler. Use the callback to do something after
524 * the current major loop transfer completes.
525 *
526 * param handle DMA handle pointer.
527 * param callback DMA callback function pointer.
528 * param userData Parameter for callback function.
529 */
DMA_SetCallback(dma_handle_t * handle,dma_callback callback,void * userData)530 void DMA_SetCallback(dma_handle_t *handle, dma_callback callback, void *userData)
531 {
532 assert(handle != NULL);
533
534 handle->callback = callback;
535 handle->userData = userData;
536 }
537
538 /*!
539 * brief Prepares the DMA transfer structure.
540 * deprecated Do not use this function. It has been superceded by @ref DMA_PrepareChannelTransfer and
541 * DMA_PrepareChannelXfer.
542 * This function prepares the transfer configuration structure according to the user input.
543 *
544 * param config The user configuration structure of type dma_transfer_t.
545 * param srcAddr DMA transfer source address.
546 * param dstAddr DMA transfer destination address.
547 * param byteWidth DMA transfer destination address width(bytes).
548 * param transferBytes DMA transfer bytes to be transferred.
549 * param type DMA transfer type.
550 * param nextDesc Chain custom descriptor to transfer.
551 * note The data address and the data width must be consistent. For example, if the SRC
552 * is 4 bytes, so the source address must be 4 bytes aligned, or it shall result in
553 * source address error(SAE).
554 */
DMA_PrepareTransfer(dma_transfer_config_t * config,void * srcAddr,void * dstAddr,uint32_t byteWidth,uint32_t transferBytes,dma_transfer_type_t type,void * nextDesc)555 void DMA_PrepareTransfer(dma_transfer_config_t *config,
556 void *srcAddr,
557 void *dstAddr,
558 uint32_t byteWidth,
559 uint32_t transferBytes,
560 dma_transfer_type_t type,
561 void *nextDesc)
562 {
563 uint32_t xfer_count;
564 assert((NULL != config) && (NULL != srcAddr) && (NULL != dstAddr));
565 assert((byteWidth == 1UL) || (byteWidth == 2UL) || (byteWidth == 4UL));
566 assert((((uint32_t)(uint32_t *)nextDesc) & ((uint32_t)FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE - 1UL)) == 0UL);
567
568 /* check max */
569 xfer_count = transferBytes / byteWidth;
570 assert((xfer_count <= DMA_MAX_TRANSFER_COUNT) && (0UL == transferBytes % byteWidth));
571
572 (void)memset(config, 0, sizeof(*config));
573
574 if (type == kDMA_MemoryToMemory)
575 {
576 config->xfercfg.srcInc = 1;
577 config->xfercfg.dstInc = 1;
578 config->isPeriph = false;
579 }
580
581 else if (type == kDMA_PeripheralToMemory)
582 {
583 /* Peripheral register - source doesn't increment */
584 config->xfercfg.srcInc = 0;
585 config->xfercfg.dstInc = 1;
586 config->isPeriph = true;
587 }
588 else if (type == kDMA_MemoryToPeripheral)
589 {
590 /* Peripheral register - destination doesn't increment */
591 config->xfercfg.srcInc = 1;
592 config->xfercfg.dstInc = 0;
593 config->isPeriph = true;
594 }
595 /* kDMA_StaticToStatic */
596 else
597 {
598 config->xfercfg.srcInc = 0;
599 config->xfercfg.dstInc = 0;
600 config->isPeriph = true;
601 }
602
603 config->dstAddr = (uint8_t *)dstAddr;
604 config->srcAddr = (uint8_t *)srcAddr;
605 config->nextDesc = (uint8_t *)nextDesc;
606 config->xfercfg.transferCount = (uint16_t)xfer_count;
607 config->xfercfg.byteWidth = (uint8_t)byteWidth;
608 config->xfercfg.intA = true;
609 config->xfercfg.reload = nextDesc != NULL;
610 config->xfercfg.valid = true;
611 }
612
613 /*!
614 * brief set channel config.
615 *
616 * This function provide a interface to configure channel configuration reisters.
617 *
618 * param base DMA base address.
619 * param channel DMA channel number.
620 * param config channel configurations structure.
621 */
DMA_SetChannelConfig(DMA_Type * base,uint32_t channel,dma_channel_trigger_t * trigger,bool isPeriph)622 void DMA_SetChannelConfig(DMA_Type *base, uint32_t channel, dma_channel_trigger_t *trigger, bool isPeriph)
623 {
624 assert(channel < (uint32_t)FSL_FEATURE_DMA_MAX_CHANNELS);
625
626 uint32_t tmpReg = DMA_CHANNEL_CFG_PERIPHREQEN_MASK;
627
628 if (trigger != NULL)
629 {
630 tmpReg |= DMA_CHANNEL_CFG_HWTRIGEN_MASK | DMA_CHANNEL_CFG_TRIGPOL_MASK | DMA_CHANNEL_CFG_TRIGTYPE_MASK |
631 DMA_CHANNEL_CFG_TRIGBURST_MASK | DMA_CHANNEL_CFG_BURSTPOWER_MASK | DMA_CHANNEL_CFG_SRCBURSTWRAP_MASK |
632 DMA_CHANNEL_CFG_DSTBURSTWRAP_MASK;
633 }
634
635 tmpReg = base->CHANNEL[channel].CFG & (~tmpReg);
636
637 if (trigger != NULL)
638 {
639 tmpReg |= (uint32_t)(trigger->type) | (uint32_t)(trigger->burst) | (uint32_t)(trigger->wrap);
640 }
641
642 tmpReg |= DMA_CHANNEL_CFG_PERIPHREQEN(isPeriph);
643
644 base->CHANNEL[channel].CFG = tmpReg;
645 }
646
647 /*!
648 * brief Prepare channel transfer configurations.
649 *
650 * This function used to prepare channel transfer configurations.
651 *
652 * param config Pointer to DMA channel transfer configuration structure.
653 * param srcStartAddr source start address.
654 * param dstStartAddr destination start address.
655 * param xferCfg xfer configuration, user can reference DMA_CHANNEL_XFER about to how to get xferCfg value.
656 * param type transfer type.
657 * param trigger DMA channel trigger configurations.
658 * param nextDesc address of next descriptor.
659 */
DMA_PrepareChannelTransfer(dma_channel_config_t * config,void * srcStartAddr,void * dstStartAddr,uint32_t xferCfg,dma_transfer_type_t type,dma_channel_trigger_t * trigger,void * nextDesc)660 void DMA_PrepareChannelTransfer(dma_channel_config_t *config,
661 void *srcStartAddr,
662 void *dstStartAddr,
663 uint32_t xferCfg,
664 dma_transfer_type_t type,
665 dma_channel_trigger_t *trigger,
666 void *nextDesc)
667 {
668 assert((NULL != config) && (NULL != srcStartAddr) && (NULL != dstStartAddr));
669 assert((((uint32_t)(uint32_t *)nextDesc) & ((uint32_t)FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE - 1UL)) == 0UL);
670
671 /* check max */
672 (void)memset(config, 0, sizeof(*config));
673
674 if (type == kDMA_MemoryToMemory)
675 {
676 config->isPeriph = false;
677 }
678 else if (type == kDMA_PeripheralToMemory)
679 {
680 config->isPeriph = true;
681 }
682 else if (type == kDMA_MemoryToPeripheral)
683 {
684 config->isPeriph = true;
685 }
686 /* kDMA_StaticToStatic */
687 else
688 {
689 config->isPeriph = true;
690 }
691
692 config->dstStartAddr = (uint8_t *)dstStartAddr;
693 config->srcStartAddr = (uint8_t *)srcStartAddr;
694 config->nextDesc = (uint8_t *)nextDesc;
695 config->trigger = trigger;
696 config->xferCfg = xferCfg;
697 }
698
699 /*!
700 * brief load channel transfer decriptor.
701 *
702 * This function can be used to load desscriptor to driver internal channel descriptor that is used to start DMA
703 * transfer, the head descriptor table is defined in DMA driver, it is useful for the case:
704 * 1. for the polling transfer, application can allocate a local descriptor memory table to prepare a descriptor firstly
705 * and then call this api to load the configured descriptor to driver descriptor table. code DMA_Init(DMA0);
706 * DMA_EnableChannel(DMA0, DEMO_DMA_CHANNEL);
707 * DMA_SetupDescriptor(desc, xferCfg, s_srcBuffer, &s_destBuffer[0], NULL);
708 * DMA_LoadChannelDescriptor(DMA0, DEMO_DMA_CHANNEL, (dma_descriptor_t *)desc);
709 * DMA_DoChannelSoftwareTrigger(DMA0, DEMO_DMA_CHANNEL);
710 * while(DMA_ChannelIsBusy(DMA0, DEMO_DMA_CHANNEL))
711 * {}
712 * endcode
713 *
714 * param base DMA base address.
715 * param channel DMA channel.
716 * param descriptor configured DMA descriptor.
717 */
DMA_LoadChannelDescriptor(DMA_Type * base,uint32_t channel,dma_descriptor_t * descriptor)718 void DMA_LoadChannelDescriptor(DMA_Type *base, uint32_t channel, dma_descriptor_t *descriptor)
719 {
720 assert(NULL != descriptor);
721 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base) != -1);
722 assert(channel < (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
723
724 uint32_t instance = DMA_GetInstance(base);
725 dma_descriptor_t *channelDescriptor = (dma_descriptor_t *)(&s_dma_descriptor_table[instance][channel]);
726
727 channelDescriptor->xfercfg = descriptor->xfercfg;
728 channelDescriptor->srcEndAddr = descriptor->srcEndAddr;
729 channelDescriptor->dstEndAddr = descriptor->dstEndAddr;
730 channelDescriptor->linkToNextDesc = descriptor->linkToNextDesc;
731
732 /* Set channel XFERCFG register according first channel descriptor. */
733 base->CHANNEL[channel].XFERCFG = descriptor->xfercfg;
734 }
735
736 /*!
737 * brief Install DMA descriptor memory.
738 *
739 * This function used to register DMA descriptor memory for linked transfer, a typical case is ping pong
740 * transfer which will request more than one DMA descriptor memory space, althrough current DMA driver has
741 * a default DMA descriptor buffer, but it support one DMA descriptor for one channel only.
742 * User should be take care about the address of DMA descriptor pool which required align with 512BYTE.
743 *
744 * param handle Pointer to DMA channel transfer handle.
745 * param addr DMA descriptor address
746 * param num DMA descriptor number.
747 */
DMA_InstallDescriptorMemory(DMA_Type * base,void * addr)748 void DMA_InstallDescriptorMemory(DMA_Type *base, void *addr)
749 {
750 assert(addr != NULL);
751
752 #if defined FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZEn
753 assert((((uint32_t)(uint32_t *)addr) & ((uint32_t)FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZEn(base) - 1UL)) == 0U);
754 #else
755 assert((((uint32_t)(uint32_t *)addr) & ((uint32_t)FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE - 1UL)) == 0U);
756 #endif
757 /* reconfigure the DMA descriptor base address */
758 base->SRAMBASE = (uint32_t)(uint32_t *)addr;
759 }
760
761 /*!
762 * brief Submit channel transfer paramter directly.
763 *
764 * This function used to configue channel head descriptor that is used to start DMA transfer, the head descriptor table
765 * is defined in DMA driver, it is useful for the case:
766 * 1. for the single transfer, application doesn't need to allocate descriptor table, the head descriptor can be used
767 for it.
768 * code
769 DMA_SetChannelConfig(base, channel, trigger, isPeriph);
770 DMA_CreateHandle(handle, base, channel)
771 DMA_SubmitChannelTransferParameter(handle, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc,
772 bytes), srcStartAddr, dstStartAddr, NULL);
773 DMA_StartTransfer(handle)
774 * endcode
775 *
776 * 2. for the linked transfer, application should responsible for link descriptor, for example, if 4 transfer is
777 required, then application should prepare
778 * three descriptor table with macro , the head descriptor in driver can be used for the first transfer descriptor.
779 * code
780 define link descriptor table in application with macro
781 DMA_ALLOCATE_LINK_DESCRIPTOR(nextDesc[3]);
782
783 DMA_SetupDescriptor(nextDesc0, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
784 srcStartAddr, dstStartAddr, nextDesc1);
785 DMA_SetupDescriptor(nextDesc1, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
786 srcStartAddr, dstStartAddr, nextDesc2);
787 DMA_SetupDescriptor(nextDesc2, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
788 srcStartAddr, dstStartAddr, NULL);
789 DMA_SetChannelConfig(base, channel, trigger, isPeriph);
790 DMA_CreateHandle(handle, base, channel)
791 DMA_SubmitChannelTransferParameter(handle, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc,
792 bytes), srcStartAddr, dstStartAddr, nextDesc0);
793 DMA_StartTransfer(handle);
794 * endcode
795 *
796 * param handle Pointer to DMA handle.
797 * param xferCfg xfer configuration, user can reference DMA_CHANNEL_XFER about to how to get xferCfg value.
798 * param srcStartAddr source start address.
799 * param dstStartAddr destination start address.
800 * param nextDesc address of next descriptor.
801 */
DMA_SubmitChannelTransferParameter(dma_handle_t * handle,uint32_t xferCfg,void * srcStartAddr,void * dstStartAddr,void * nextDesc)802 void DMA_SubmitChannelTransferParameter(
803 dma_handle_t *handle, uint32_t xferCfg, void *srcStartAddr, void *dstStartAddr, void *nextDesc)
804 {
805 assert((NULL != srcStartAddr) && (NULL != dstStartAddr));
806 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base) != -1);
807 assert(handle->channel < (uint8_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base));
808
809 uint32_t instance = DMA_GetInstance(handle->base);
810 dma_descriptor_t *descriptor = (dma_descriptor_t *)(&s_dma_descriptor_table[instance][handle->channel]);
811
812 DMA_SetupDescriptor(descriptor, xferCfg, srcStartAddr, dstStartAddr, nextDesc);
813
814 /* Set channel XFERCFG register according first channel descriptor. */
815 handle->base->CHANNEL[handle->channel].XFERCFG = xferCfg;
816 }
817
818 /*!
819 * brief Submit channel descriptor.
820 *
821 * This function used to configue channel head descriptor that is used to start DMA transfer, the head descriptor table
822 is defined in
823 * DMA driver, this functiono is typical for the ping pong case:
824 *
825 * 1. for the ping pong case, application should responsible for the descriptor, for example, application should
826 * prepare two descriptor table with macro.
827 * code
828 define link descriptor table in application with macro
829 DMA_ALLOCATE_LINK_DESCRIPTOR(nextDesc[2]);
830
831 DMA_SetupDescriptor(nextDesc0, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
832 srcStartAddr, dstStartAddr, nextDesc1);
833 DMA_SetupDescriptor(nextDesc1, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
834 srcStartAddr, dstStartAddr, nextDesc0);
835 DMA_SetChannelConfig(base, channel, trigger, isPeriph);
836 DMA_CreateHandle(handle, base, channel)
837 DMA_SubmitChannelDescriptor(handle, nextDesc0);
838 DMA_StartTransfer(handle);
839 * endcode
840 *
841 * param handle Pointer to DMA handle.
842 * param descriptor descriptor to submit.
843 */
DMA_SubmitChannelDescriptor(dma_handle_t * handle,dma_descriptor_t * descriptor)844 void DMA_SubmitChannelDescriptor(dma_handle_t *handle, dma_descriptor_t *descriptor)
845 {
846 assert((NULL != handle) && (NULL != descriptor));
847
848 DMA_LoadChannelDescriptor(handle->base, handle->channel, descriptor);
849 }
850
851 /*!
852 * brief Submits the DMA channel transfer request.
853 *
854 * This function submits the DMA transfer request according to the transfer configuration structure.
855 * If the user submits the transfer request repeatedly, this function packs an unprocessed request as
856 * a TCD and enables scatter/gather feature to process it in the next time.
857 * It is used for the case:
858 * 1. for the single transfer, application doesn't need to allocate descriptor table, the head descriptor can be used
859 for it.
860 * code
861 DMA_CreateHandle(handle, base, channel)
862 DMA_PrepareChannelTransfer(config,srcStartAddr,dstStartAddr,xferCfg,type,trigger,NULL);
863 DMA_SubmitChannelTransfer(handle, config)
864 DMA_StartTransfer(handle)
865 * endcode
866 *
867 * 2. for the linked transfer, application should responsible for link descriptor, for example, if 4 transfer is
868 required, then application should prepare
869 * three descriptor table with macro , the head descriptor in driver can be used for the first transfer descriptor.
870 * code
871 define link descriptor table in application with macro
872 DMA_ALLOCATE_LINK_DESCRIPTOR(nextDesc);
873
874 DMA_SetupDescriptor(nextDesc0, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
875 srcStartAddr, dstStartAddr, nextDesc1);
876 DMA_SetupDescriptor(nextDesc1, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
877 srcStartAddr, dstStartAddr, nextDesc2);
878 DMA_SetupDescriptor(nextDesc2, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
879 srcStartAddr, dstStartAddr, NULL);
880 DMA_CreateHandle(handle, base, channel)
881 DMA_PrepareChannelTransfer(config,srcStartAddr,dstStartAddr,xferCfg,type,trigger,nextDesc0);
882 DMA_SubmitChannelTransfer(handle, config)
883 DMA_StartTransfer(handle)
884 * endcode
885 *
886 * 3. for the ping pong case, application should responsible for link descriptor, for example, application should
887 prepare
888 * two descriptor table with macro , the head descriptor in driver can be used for the first transfer descriptor.
889 * code
890 define link descriptor table in application with macro
891 DMA_ALLOCATE_LINK_DESCRIPTOR(nextDesc);
892
893 DMA_SetupDescriptor(nextDesc0, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
894 srcStartAddr, dstStartAddr, nextDesc1);
895 DMA_SetupDescriptor(nextDesc1, DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes),
896 srcStartAddr, dstStartAddr, nextDesc0);
897 DMA_CreateHandle(handle, base, channel)
898 DMA_PrepareChannelTransfer(config,srcStartAddr,dstStartAddr,xferCfg,type,trigger,nextDesc0);
899 DMA_SubmitChannelTransfer(handle, config)
900 DMA_StartTransfer(handle)
901 * endcode
902 * param handle DMA handle pointer.
903 * param config Pointer to DMA transfer configuration structure.
904 * retval kStatus_DMA_Success It means submit transfer request succeed.
905 * retval kStatus_DMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
906 * retval kStatus_DMA_Busy It means the given channel is busy, need to submit request later.
907 */
DMA_SubmitChannelTransfer(dma_handle_t * handle,dma_channel_config_t * config)908 status_t DMA_SubmitChannelTransfer(dma_handle_t *handle, dma_channel_config_t *config)
909 {
910 assert((NULL != handle) && (NULL != config));
911 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base) != -1);
912 assert(handle->channel < (uint8_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base));
913 uint32_t instance = DMA_GetInstance(handle->base);
914 dma_descriptor_t *descriptor = (dma_descriptor_t *)(&s_dma_descriptor_table[instance][handle->channel]);
915
916 /* Previous transfer has not finished */
917 if (DMA_ChannelIsActive(handle->base, handle->channel))
918 {
919 return kStatus_DMA_Busy;
920 }
921
922 /* setup channgel trigger configurations */
923 DMA_SetChannelConfig(handle->base, handle->channel, config->trigger, config->isPeriph);
924
925 DMA_SetupChannelDescriptor(
926 descriptor, config->xferCfg, config->srcStartAddr, config->dstStartAddr, config->nextDesc,
927 config->trigger == NULL ? kDMA_NoWrap : config->trigger->wrap,
928 (config->trigger == NULL ? (uint32_t)kDMA_BurstSize1 :
929 ((uint32_t)config->trigger->burst & (DMA_CHANNEL_CFG_BURSTPOWER_MASK)) >>
930 DMA_CHANNEL_CFG_BURSTPOWER_SHIFT));
931
932 /* Set channel XFERCFG register according first channel descriptor. */
933 handle->base->CHANNEL[handle->channel].XFERCFG = config->xferCfg;
934
935 return kStatus_Success;
936 }
937
938 /*!
939 * brief Submits the DMA transfer request.
940 * deprecated Do not use this function. It has been superceded by @ref DMA_SubmitChannelTransfer.
941 *
942 * This function submits the DMA transfer request according to the transfer configuration structure.
943 * If the user submits the transfer request repeatedly, this function packs an unprocessed request as
944 * a TCD and enables scatter/gather feature to process it in the next time.
945 *
946 * param handle DMA handle pointer.
947 * param config Pointer to DMA transfer configuration structure.
948 * retval kStatus_DMA_Success It means submit transfer request succeed.
949 * retval kStatus_DMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
950 * retval kStatus_DMA_Busy It means the given channel is busy, need to submit request later.
951 */
DMA_SubmitTransfer(dma_handle_t * handle,dma_transfer_config_t * config)952 status_t DMA_SubmitTransfer(dma_handle_t *handle, dma_transfer_config_t *config)
953 {
954 assert((NULL != handle) && (NULL != config));
955 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base) != -1);
956 assert(handle->channel < (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base));
957
958 uint32_t instance = DMA_GetInstance(handle->base);
959 dma_descriptor_t *descriptor = (dma_descriptor_t *)(&s_dma_descriptor_table[instance][handle->channel]);
960
961 /* Previous transfer has not finished */
962 if (DMA_ChannelIsActive(handle->base, handle->channel))
963 {
964 return kStatus_DMA_Busy;
965 }
966
967 /* enable/disable peripheral request */
968 if (config->isPeriph)
969 {
970 DMA_EnableChannelPeriphRq(handle->base, handle->channel);
971 }
972 else
973 {
974 DMA_DisableChannelPeriphRq(handle->base, handle->channel);
975 }
976
977 DMA_CreateDescriptor(descriptor, &config->xfercfg, config->srcAddr, config->dstAddr, config->nextDesc);
978 /* Set channel XFERCFG register according first channel descriptor. */
979 handle->base->CHANNEL[handle->channel].XFERCFG = descriptor->xfercfg;
980
981 return kStatus_Success;
982 }
983
984 /*!
985 * brief DMA start transfer.
986 *
987 * This function enables the channel request. User can call this function after submitting the transfer request
988 * It will trigger transfer start with software trigger only when hardware trigger is not used.
989 *
990 * param handle DMA handle pointer.
991 */
DMA_StartTransfer(dma_handle_t * handle)992 void DMA_StartTransfer(dma_handle_t *handle)
993 {
994 assert(NULL != handle);
995 assert(FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base) != -1);
996
997 uint32_t channel = handle->channel;
998 assert(channel < (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(handle->base));
999
1000 /* enable channel */
1001 DMA_EnableChannel(handle->base, channel);
1002
1003 /* Do software trigger only when HW trigger is not enabled. */
1004 if ((handle->base->CHANNEL[handle->channel].CFG & DMA_CHANNEL_CFG_HWTRIGEN_MASK) == 0U)
1005 {
1006 handle->base->CHANNEL[channel].XFERCFG |= DMA_CHANNEL_XFERCFG_SWTRIG_MASK;
1007 }
1008 }
1009
DMA_IRQHandle(DMA_Type * base)1010 void DMA_IRQHandle(DMA_Type *base)
1011 {
1012 dma_handle_t *handle;
1013 uint8_t channel_index;
1014 uint32_t startChannel = DMA_GetVirtualStartChannel(base);
1015 uint32_t i = 0;
1016 bool intEnabled = false, intA = false, intB = false;
1017
1018 /* Find channels that have completed transfer */
1019 for (i = 0; i < (uint32_t)FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base); i++)
1020 {
1021 handle = s_DMAHandle[i + startChannel];
1022 /* Handle is not present */
1023 if (NULL == handle)
1024 {
1025 continue;
1026 }
1027 channel_index = DMA_CHANNEL_INDEX(base, handle->channel);
1028 /* Channel uses INTA flag */
1029 intEnabled = ((DMA_COMMON_REG_GET(handle->base, handle->channel, INTENSET) & (1UL << channel_index)) != 0UL);
1030 intA = ((DMA_COMMON_REG_GET(handle->base, handle->channel, INTA) & (1UL << channel_index)) != 0UL);
1031 if (intEnabled && intA)
1032 {
1033 /* Clear INTA flag */
1034 DMA_COMMON_REG_SET(handle->base, handle->channel, INTA, (1UL << channel_index));
1035 if (handle->callback != NULL)
1036 {
1037 (handle->callback)(handle, handle->userData, true, kDMA_IntA);
1038 }
1039 }
1040
1041 intB = ((DMA_COMMON_REG_GET(handle->base, handle->channel, INTB) & (1UL << channel_index)) != 0UL);
1042 /* Channel uses INTB flag */
1043 if (intEnabled && intB)
1044 {
1045 /* Clear INTB flag */
1046 DMA_COMMON_REG_SET(handle->base, handle->channel, INTB, (1UL << channel_index));
1047 if (handle->callback != NULL)
1048 {
1049 (handle->callback)(handle, handle->userData, true, kDMA_IntB);
1050 }
1051 }
1052 /* Error flag */
1053 if ((DMA_COMMON_REG_GET(handle->base, handle->channel, ERRINT) & (1UL << channel_index)) != 0UL)
1054 {
1055 /* Clear error flag */
1056 DMA_COMMON_REG_SET(handle->base, handle->channel, ERRINT, (1UL << channel_index));
1057 if (handle->callback != NULL)
1058 {
1059 (handle->callback)(handle, handle->userData, false, kDMA_IntError);
1060 }
1061 }
1062 }
1063 }
1064
1065 void DMA0_DriverIRQHandler(void);
DMA0_DriverIRQHandler(void)1066 void DMA0_DriverIRQHandler(void)
1067 {
1068 DMA_IRQHandle(DMA0);
1069 SDK_ISR_EXIT_BARRIER;
1070 }
1071
1072 #if defined(DMA1)
1073 void DMA1_DriverIRQHandler(void);
DMA1_DriverIRQHandler(void)1074 void DMA1_DriverIRQHandler(void)
1075 {
1076 DMA_IRQHandle(DMA1);
1077 SDK_ISR_EXIT_BARRIER;
1078 }
1079 #endif
1080