1 /*
2  * Copyright 2019-2021 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_asrc_sdma.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.easrc_sdma"
14 #endif
15 
16 /*******************************************************************************
17  * Definitations
18  ******************************************************************************/
19 /*<! Structure definition for uart_sdma_private_handle_t. The structure is private. */
20 typedef struct _asrc_sdma_private_handle
21 {
22     ASRC_Type *base;
23     asrc_sdma_handle_t *handle;
24 } asrc_sdma_private_handle_t;
25 /*! @brief Private handle only used for internally. */
26 static asrc_sdma_private_handle_t s_sdmaPrivateHandle[FSL_FEATURE_SOC_ASRC_COUNT]
27                                                      [ASRC_SUPPORT_MAXIMUM_CONTEXT_PROCESSOR_NUMBER];
28 /*******************************************************************************
29  * Prototypes
30  ******************************************************************************/
31 /*!
32  * @brief ASRC SDMA callback for input data transfer finished.
33  *
34  * @param handle pointer to asrc_sdma_handle_t structure which stores the transfer state.
35  * @param userData Parameter for user callback.
36  * @param done If the DMA transfer finished.
37  * @param tcds The TCD index.
38  */
39 static void ASRC_InSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex);
40 
41 /*!
42  * @brief ASRC SDMA callback for output data transfer finished.
43  *
44  * @param handle pointer to asrc_sdma_handle_t structure which stores the transfer state.
45  * @param userData Parameter for user callback.
46  * @param done If the DMA transfer finished.
47  * @param tcds The TCD index.
48  */
49 static void ASRC_OutSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex);
50 
51 /*!
52  * @brief ASRC submit output request .
53  *
54  * @param base ASRC base address.
55  * @param handle ASRC sdma handler.
56  * @param outDataAddr output peripheral fifo address.
57  * @param outDataSize output sdma transfer data size.
58  *
59  */
60 static status_t ASRC_TransferSubmitOutM2MSDMA(ASRC_Type *base,
61                                               asrc_sdma_handle_t *handle,
62                                               uint32_t *outDataAddr,
63                                               uint32_t outDataSize);
64 
65 /*!
66  * @brief ASRC sdma transfer output request .
67  *
68  * @param base ASRC base address.
69  * @param handle ASRC sdma handler.
70  * @param outDataAddr output peripheral fifo address.
71  * @param outDataSize output sdma transfer data size.
72  *
73  */
74 static status_t ASRC_TransferOutSDMA(ASRC_Type *base,
75                                      asrc_sdma_handle_t *handle,
76                                      uint32_t *outDataAddr,
77                                      uint32_t outDataSize);
78 
79 /*!
80  * @brief ASRC sdma transfer input request .
81  *
82  * @param base ASRC base address.
83  * @param handle ASRC sdma handler.
84  * @param inDataAddr ASRC input sdma source address.
85  * @param inDataSize input sdma transfer data size.
86  */
87 static status_t ASRC_TransferInSDMA(ASRC_Type *base,
88                                     asrc_sdma_handle_t *handle,
89                                     uint32_t *inDataAddr,
90                                     uint32_t inDataSize);
91 /*******************************************************************************
92  * Code
93  ******************************************************************************/
ASRC_InSDMACallback(sdma_handle_t * handle,void * userData,bool transferDone,uint32_t bdIndex)94 static void ASRC_InSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex)
95 {
96     asrc_sdma_private_handle_t *privHandle = (asrc_sdma_private_handle_t *)userData;
97     asrc_sdma_handle_t *asrcHandle         = privHandle->handle;
98     status_t callbackStatus                = kStatus_ASRCIdle;
99 
100     /* If finished a block, call the callback function */
101     asrcHandle->inDMAHandle.asrcQueue[asrcHandle->inDMAHandle.queueDriver] = NULL;
102 
103     asrcHandle->inDMAHandle.queueDriver = (asrcHandle->inDMAHandle.queueDriver + 1U) % ASRC_XFER_IN_QUEUE_SIZE;
104 
105     if (asrcHandle->inDMAHandle.asrcQueue[asrcHandle->inDMAHandle.queueDriver] == NULL)
106     {
107         ASRC_TransferAbortInSDMA(privHandle->base, asrcHandle);
108         callbackStatus = kStatus_ASRCQueueIdle;
109     }
110 
111     if (asrcHandle->inDMAHandle.callback != NULL)
112     {
113         (asrcHandle->inDMAHandle.callback)(privHandle->base, asrcHandle, callbackStatus,
114                                            asrcHandle->inDMAHandle.userData);
115     }
116 }
117 
ASRC_ReadFIFORemainedSampleSDMA(ASRC_Type * base,asrc_context_t context,uint32_t * outAddr,uint32_t outWidth,uint32_t size)118 static void ASRC_ReadFIFORemainedSampleSDMA(
119     ASRC_Type *base, asrc_context_t context, uint32_t *outAddr, uint32_t outWidth, uint32_t size)
120 {
121     uint32_t totalSize = size;
122     uint32_t *addr     = outAddr;
123     uint32_t i         = 0U;
124 
125     for (i = 0U; i < totalSize / outWidth; i++)
126     {
127         (void)ASRC_ReadFIFORemainedSample(base, context, addr, outWidth, 1U);
128         addr = (uint32_t *)((uint32_t)addr + outWidth);
129     }
130 }
131 
ASRC_OutSDMACallback(sdma_handle_t * handle,void * userData,bool transferDone,uint32_t bdIndex)132 static void ASRC_OutSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex)
133 {
134     asrc_sdma_private_handle_t *privHandle = (asrc_sdma_private_handle_t *)userData;
135     asrc_sdma_handle_t *asrcHandle         = privHandle->handle;
136     uint32_t queueDriverIndex              = asrcHandle->outDMAHandle.queueDriver;
137     status_t callbackStatus                = kStatus_ASRCIdle;
138 
139     /* If finished a block, call the callback function */
140     asrcHandle->outDMAHandle.asrcQueue[queueDriverIndex] = NULL;
141     asrcHandle->outDMAHandle.queueDriver                 = (uint8_t)(queueDriverIndex + 1U) % ASRC_XFER_OUT_QUEUE_SIZE;
142 
143     /* If all data finished, just stop the transfer */
144     if (asrcHandle->outDMAHandle.asrcQueue[asrcHandle->outDMAHandle.queueDriver] == NULL)
145     {
146         if (asrcHandle->outDMAHandle.nonAlignSize != 0U)
147         {
148             /* please note that when read buffered samples, input sample will be ingored */
149             ASRC_ReadFIFORemainedSampleSDMA(
150                 privHandle->base, asrcHandle->context, asrcHandle->outDMAHandle.nonAlignAddr,
151                 asrcHandle->outDMAHandle.bytesPerSample, asrcHandle->outDMAHandle.nonAlignSize);
152             asrcHandle->outDMAHandle.nonAlignSize = 0U;
153             asrcHandle->outDMAHandle.nonAlignAddr = NULL;
154         }
155         ASRC_TransferAbortOutSDMA(privHandle->base, asrcHandle);
156         callbackStatus = kStatus_ASRCQueueIdle;
157     }
158 
159     if (asrcHandle->outDMAHandle.callback != NULL)
160     {
161         (asrcHandle->outDMAHandle.callback)(privHandle->base, asrcHandle, callbackStatus,
162                                             asrcHandle->outDMAHandle.userData);
163     }
164 }
165 
166 /*!
167  * brief Initializes the ASRC input SDMA handle.
168  *
169  * This function initializes the ASRC input DMA handle, which can be used for other ASRC transactional APIs.
170  * Usually, for a specified ASRC context, call this API once to get the initialized handle.
171  *
172  * param base ASRC base pointer.
173  * param handle ASRC SDMA handle pointer.
174  * param base ASRC peripheral base address.
175  * param callback Pointer to user callback function.
176  * param dmaHandle SDMA handle pointer, this handle shall be static allocated by users.
177  * param eventSource ASRC input sdma event source.
178  * param context ASRC context number.
179  * param periphConfig peripheral configurations, used for peripheral to peripheral case.
180  * param userData User parameter passed to the callback function.
181  */
ASRC_TransferInCreateHandleSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle,asrc_sdma_callback_t callback,sdma_handle_t * dmaHandle,uint32_t eventSource,asrc_context_t context,const asrc_p2p_sdma_config_t * periphConfig,void * userData)182 void ASRC_TransferInCreateHandleSDMA(ASRC_Type *base,
183                                      asrc_sdma_handle_t *handle,
184                                      asrc_sdma_callback_t callback,
185                                      sdma_handle_t *dmaHandle,
186                                      uint32_t eventSource,
187                                      asrc_context_t context,
188                                      const asrc_p2p_sdma_config_t *periphConfig,
189                                      void *userData)
190 {
191     assert((handle != NULL) && (dmaHandle != NULL));
192 
193     uint32_t instance = ASRC_GetInstance(base);
194 
195     /* Zero the handle */
196     (void)memset(&handle->inDMAHandle, 0, sizeof(asrc_sdma_in_handle_t));
197 
198     /* Set asrc base to handle */
199     handle->inDMAHandle.sdmaHandle  = dmaHandle;
200     handle->inDMAHandle.callback    = callback;
201     handle->inDMAHandle.userData    = userData;
202     handle->inDMAHandle.eventSource = eventSource;
203 
204     /* Set ASRC state to idle */
205     handle->inDMAHandle.state            = kStatus_ASRCIdle;
206     handle->context                      = context;
207     handle->inDMAHandle.peripheralConfig = periphConfig;
208 
209     s_sdmaPrivateHandle[instance][context].base   = base;
210     s_sdmaPrivateHandle[instance][context].handle = handle;
211 
212     SDMA_InstallBDMemory(dmaHandle, handle->inDMAHandle.bdPool, ASRC_XFER_IN_QUEUE_SIZE);
213     /* Install callback for in dma channel */
214     SDMA_SetCallback(dmaHandle, ASRC_InSDMACallback, &s_sdmaPrivateHandle[instance][context]);
215 }
216 
217 /*!
218  * brief Initializes the ASRC output SDMA handle.
219  *
220  * This function initializes the ASRC out DMA handle, which can be used for other ASRC transactional APIs.
221  * Usually, for a specified ASRC context, call this API once to get the initialized handle.
222  *
223  * param base ASRC base pointer.
224  * param handle ASRC SDMA handle pointer.
225  * param callback, ASRC outcallback.
226  * param dmaHandle SDMA handle pointer, this handle shall be static allocated by users.
227  * param eventSource ASRC output event source.
228  * param context ASRC context number.
229  * param periphConfig peripheral configurations, used for  case.
230  * param userData User parameter passed to the callback function.
231  */
ASRC_TransferOutCreateHandleSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle,asrc_sdma_callback_t callback,sdma_handle_t * dmaHandle,uint32_t eventSource,asrc_context_t context,const asrc_p2p_sdma_config_t * periphConfig,void * userData)232 void ASRC_TransferOutCreateHandleSDMA(ASRC_Type *base,
233                                       asrc_sdma_handle_t *handle,
234                                       asrc_sdma_callback_t callback,
235                                       sdma_handle_t *dmaHandle,
236                                       uint32_t eventSource,
237                                       asrc_context_t context,
238                                       const asrc_p2p_sdma_config_t *periphConfig,
239                                       void *userData)
240 {
241     assert((handle != NULL) && (dmaHandle != NULL));
242 
243     uint32_t instance = ASRC_GetInstance(base);
244 
245     /* Zero the handle */
246     (void)memset(&handle->outDMAHandle, 0, sizeof(asrc_sdma_out_handle_t));
247 
248     /* Set asrc base to handle */
249     handle->outDMAHandle.sdmaHandle       = dmaHandle;
250     handle->outDMAHandle.callback         = callback;
251     handle->outDMAHandle.userData         = userData;
252     handle->outDMAHandle.eventSource      = eventSource;
253     handle->outDMAHandle.peripheralConfig = periphConfig;
254 
255     /* Set ASRC state to idle */
256     handle->outDMAHandle.state = kStatus_ASRCIdle;
257     handle->context            = context;
258 
259     s_sdmaPrivateHandle[instance][context].base   = base;
260     s_sdmaPrivateHandle[instance][context].handle = handle;
261 
262     /* Install callback for in dma channel */
263     SDMA_SetCallback(dmaHandle, ASRC_OutSDMACallback, &s_sdmaPrivateHandle[instance][context]);
264     SDMA_InstallBDMemory(dmaHandle, handle->outDMAHandle.bdPool, ASRC_XFER_OUT_QUEUE_SIZE);
265 }
266 
267 /*!
268  * brief Configures the ASRC context.
269  *
270  * param base ASRC base pointer.
271  * param handle ASRC SDMA handle pointer.
272  * param asrcConfig asrc context configurations.
273  */
ASRC_TransferSetContextConfigSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle,asrc_context_config_t * asrcConfig)274 status_t ASRC_TransferSetContextConfigSDMA(ASRC_Type *base,
275                                            asrc_sdma_handle_t *handle,
276                                            asrc_context_config_t *asrcConfig)
277 {
278     assert((handle != NULL) && (asrcConfig != NULL));
279 
280     /* Configure the audio format to ASRC registers */
281     if (ASRC_SetContextConfig(base, handle->context, asrcConfig) != kStatus_Success)
282     {
283         return kStatus_ASRCConfigureFailed;
284     }
285 
286     if (asrcConfig->contextInput.dataFormat.dataWidth == kASRC_DataWidth16Bit)
287     {
288         handle->inDMAHandle.bytesPerSample = 2U;
289     }
290     else
291     {
292         handle->inDMAHandle.bytesPerSample = 4U;
293     }
294 
295     if (asrcConfig->contextOutput.dataFormat.dataWidth == kASRC_DataWidth16Bit)
296     {
297         handle->outDMAHandle.bytesPerSample = 2U;
298     }
299     else
300     {
301         handle->outDMAHandle.bytesPerSample = 4U;
302     }
303 
304     handle->dataChannels                  = asrcConfig->contextChannelNums;
305     handle->outDMAHandle.asrcOutWatermark = (asrcConfig->contextOutput.watermark + 1U) * asrcConfig->contextChannelNums;
306     handle->inDMAHandle.asrcInWatermark   = (asrcConfig->contextInput.watermark + 1U) * asrcConfig->contextChannelNums;
307 
308     return kStatus_Success;
309 }
310 
ASRC_TransferSubmitOutM2MSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle,uint32_t * outDataAddr,uint32_t outDataSize)311 static status_t ASRC_TransferSubmitOutM2MSDMA(ASRC_Type *base,
312                                               asrc_sdma_handle_t *handle,
313                                               uint32_t *outDataAddr,
314                                               uint32_t outDataSize)
315 {
316     sdma_transfer_config_t outConfig = {0};
317     uint32_t asrcOutAddr             = ASRC_GetReadContextFifoAddr(base, handle->context);
318     sdma_handle_t *outDMAHandle      = handle->outDMAHandle.sdmaHandle;
319     uint32_t nonAlignSize            = 0U;
320     uint32_t *nonAlignAddr           = NULL;
321     uint32_t outWaterMarkSize = (uint32_t)handle->outDMAHandle.asrcOutWatermark * handle->outDMAHandle.bytesPerSample;
322 
323     if (handle->outDMAHandle.asrcQueue[handle->outDMAHandle.queueUser] != NULL)
324     {
325         return kStatus_ASRCQueueFull;
326     }
327 
328     if (outDataSize < outWaterMarkSize)
329     {
330         handle->outDMAHandle.nonAlignSize = outDataSize;
331         handle->outDMAHandle.nonAlignAddr = outDataAddr;
332 
333         return kStatus_Success;
334     }
335     else
336     {
337         nonAlignSize = outDataSize % outWaterMarkSize;
338         nonAlignAddr = (void *)(uint32_t *)((uint32_t)outDataAddr + outDataSize - nonAlignSize);
339     }
340 
341     if (handle->outDMAHandle.peripheralConfig == NULL)
342     {
343         /* since the ASRC output fifo will generate SDMA request only when output fifo sample number > output fifo
344          * watermark, so part of data may need to polling out.
345          */
346         if (handle->outDMAHandle.nonAlignSize != 0U)
347         {
348             SDMA_PrepareTransfer(&outConfig, (uint32_t)asrcOutAddr,
349                                  (uint32_t)(uint32_t *)handle->outDMAHandle.nonAlignAddr,
350                                  handle->outDMAHandle.bytesPerSample, handle->outDMAHandle.bytesPerSample,
351                                  outWaterMarkSize, handle->outDMAHandle.nonAlignSize, handle->outDMAHandle.eventSource,
352                                  kSDMA_PeripheralASRCP2M, kSDMA_PeripheralToMemory);
353 
354             if (handle->outDMAHandle.queueUser == ASRC_XFER_OUT_QUEUE_SIZE - 1U)
355             {
356                 SDMA_ConfigBufferDescriptor(
357                     &outDMAHandle->BDPool[handle->outDMAHandle.queueUser], (uint32_t)(asrcOutAddr),
358                     (uint32_t)(uint32_t *)handle->outDMAHandle.nonAlignAddr, outConfig.destTransferSize,
359                     handle->outDMAHandle.nonAlignSize, false, true, true, kSDMA_PeripheralToMemory);
360             }
361             else
362             {
363                 SDMA_ConfigBufferDescriptor(
364                     &outDMAHandle->BDPool[handle->outDMAHandle.queueUser], (uint32_t)(asrcOutAddr),
365                     (uint32_t)(uint32_t *)handle->outDMAHandle.nonAlignAddr, outConfig.destTransferSize,
366                     handle->outDMAHandle.nonAlignSize, false, true, false, kSDMA_PeripheralToMemory);
367             }
368 
369             handle->outDMAHandle.sdmaTransferSize[handle->outDMAHandle.queueUser] = handle->outDMAHandle.nonAlignSize;
370             handle->outDMAHandle.asrcQueue[handle->outDMAHandle.queueUser]        = handle->outDMAHandle.nonAlignAddr;
371             handle->outDMAHandle.queueUser    = (handle->outDMAHandle.queueUser + 1U) % ASRC_XFER_OUT_QUEUE_SIZE;
372             handle->outDMAHandle.nonAlignSize = 0U;
373             handle->outDMAHandle.nonAlignAddr = NULL;
374 
375             if (handle->outDMAHandle.asrcQueue[handle->outDMAHandle.queueUser] != NULL)
376             {
377                 return kStatus_ASRCQueueFull;
378             }
379         }
380         else
381         {
382             SDMA_PrepareTransfer(&outConfig, (uint32_t)asrcOutAddr, (uint32_t)outDataAddr,
383                                  handle->outDMAHandle.bytesPerSample, handle->outDMAHandle.bytesPerSample,
384                                  outWaterMarkSize, outDataSize - nonAlignSize, handle->outDMAHandle.eventSource,
385                                  kSDMA_PeripheralASRCP2M, kSDMA_PeripheralToMemory);
386         }
387 
388         if (handle->outDMAHandle.queueUser == ASRC_XFER_OUT_QUEUE_SIZE - 1U)
389         {
390             SDMA_ConfigBufferDescriptor(&outDMAHandle->BDPool[handle->outDMAHandle.queueUser], (uint32_t)(asrcOutAddr),
391                                         (uint32_t)outDataAddr, outConfig.destTransferSize, outDataSize - nonAlignSize,
392                                         false, true, true, kSDMA_PeripheralToMemory);
393         }
394         else
395         {
396             SDMA_ConfigBufferDescriptor(&outDMAHandle->BDPool[handle->outDMAHandle.queueUser], (uint32_t)(asrcOutAddr),
397                                         (uint32_t)outDataAddr, outConfig.destTransferSize, outDataSize - nonAlignSize,
398                                         false, true, false, kSDMA_PeripheralToMemory);
399         }
400 
401         handle->outDMAHandle.sdmaTransferSize[handle->outDMAHandle.queueUser] = outDataSize - nonAlignSize;
402         handle->outDMAHandle.asrcQueue[handle->outDMAHandle.queueUser]        = outDataAddr;
403         handle->outDMAHandle.nonAlignSize                                     = nonAlignSize;
404         handle->outDMAHandle.nonAlignAddr                                     = nonAlignAddr;
405 
406         handle->outDMAHandle.queueUser = (handle->outDMAHandle.queueUser + 1U) % ASRC_XFER_OUT_QUEUE_SIZE;
407 
408         if (handle->outDMAHandle.state != (uint32_t)kStatus_ASRCBusy)
409         {
410             /* submit ASRC transfer firstly */
411             SDMA_SubmitTransfer(outDMAHandle, &outConfig);
412             /* Start DMA transfer */
413             SDMA_StartTransfer(outDMAHandle);
414 
415             /* enable ASRC DMA request */
416             ASRC_EnableContextOutDMA(base, handle->context, true);
417             ASRC_ClearInterruptStatus(base, kASRC_ContextAllInterruptStatus);
418 
419             if ((handle->outDMAHandle.peripheralConfig != NULL) &&
420                 (handle->outDMAHandle.peripheralConfig->startPeripheral != NULL))
421             {
422                 /* start peripheral */
423                 handle->outDMAHandle.peripheralConfig->startPeripheral(true);
424             }
425 
426             handle->outDMAHandle.state = kStatus_ASRCBusy;
427         }
428     }
429 
430     return kStatus_Success;
431 }
432 
ASRC_TransferOutSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle,uint32_t * outDataAddr,uint32_t outDataSize)433 static status_t ASRC_TransferOutSDMA(ASRC_Type *base,
434                                      asrc_sdma_handle_t *handle,
435                                      uint32_t *outDataAddr,
436                                      uint32_t outDataSize)
437 {
438     sdma_transfer_config_t outConfig = {0};
439     uint32_t asrcOutAddr             = ASRC_GetReadContextFifoAddr(base, handle->context);
440     sdma_handle_t *outDMAHandle      = handle->outDMAHandle.sdmaHandle;
441     sdma_p2p_config_t p2pConfig      = {0U};
442 
443     if ((handle->outDMAHandle.peripheralConfig != NULL) && (handle->outDMAHandle.peripheralConfig->enableContinuous) &&
444         (handle->outDMAHandle.state == (uint32_t)kStatus_ASRCBusy))
445     {
446         return kStatus_Success;
447     }
448 
449     if (handle->outDMAHandle.asrcQueue[handle->outDMAHandle.queueUser] != NULL)
450     {
451         return kStatus_ASRCQueueFull;
452     }
453 
454     if (handle->outDMAHandle.peripheralConfig != NULL)
455     {
456         p2pConfig.sourceWatermark    = handle->outDMAHandle.asrcOutWatermark;
457         p2pConfig.destWatermark      = handle->outDMAHandle.peripheralConfig->watermark;
458         p2pConfig.continuousTransfer = handle->outDMAHandle.peripheralConfig->enableContinuous;
459         /* Prepare sdma configure */
460         SDMA_PrepareP2PTransfer(&outConfig, (uint32_t)asrcOutAddr, (uint32_t)outDataAddr,
461                                 handle->outDMAHandle.bytesPerSample, handle->outDMAHandle.bytesPerSample,
462                                 (uint32_t)handle->outDMAHandle.asrcOutWatermark * handle->outDMAHandle.bytesPerSample,
463                                 outDataSize, handle->outDMAHandle.eventSource,
464                                 handle->outDMAHandle.peripheralConfig->eventSource, kSDMA_PeripheralASRCP2P,
465                                 &p2pConfig);
466 
467         handle->outDMAHandle.sdmaTransferSize[handle->outDMAHandle.queueUser] = outDataSize;
468         handle->outDMAHandle.asrcQueue[handle->outDMAHandle.queueUser]        = outDataAddr;
469 
470         if (handle->outDMAHandle.queueUser == ASRC_XFER_OUT_QUEUE_SIZE - 1U)
471         {
472             SDMA_ConfigBufferDescriptor(&outDMAHandle->BDPool[handle->outDMAHandle.queueUser], (uint32_t)(asrcOutAddr),
473                                         (uint32_t)outDataAddr, outConfig.destTransferSize, outDataSize, false, true,
474                                         true, kSDMA_PeripheralToPeripheral);
475         }
476         else
477         {
478             SDMA_ConfigBufferDescriptor(&outDMAHandle->BDPool[handle->outDMAHandle.queueUser], (uint32_t)(asrcOutAddr),
479                                         (uint32_t)outDataAddr, outConfig.destTransferSize, outDataSize, false, true,
480                                         false, kSDMA_PeripheralToPeripheral);
481         }
482 
483         handle->outDMAHandle.queueUser = (handle->outDMAHandle.queueUser + 1U) % ASRC_XFER_OUT_QUEUE_SIZE;
484 
485         if (handle->outDMAHandle.state != (uint32_t)kStatus_ASRCBusy)
486         {
487             /* submit ASRC transfer firstly */
488             SDMA_SubmitTransfer(outDMAHandle, &outConfig);
489             /* Start DMA transfer */
490             SDMA_StartTransfer(outDMAHandle);
491 
492             /* enable ASRC DMA request */
493             ASRC_EnableContextOutDMA(base, handle->context, true);
494             ASRC_ClearInterruptStatus(base, kASRC_ContextAllInterruptStatus);
495 
496             if ((handle->outDMAHandle.peripheralConfig != NULL) &&
497                 (handle->outDMAHandle.peripheralConfig->startPeripheral != NULL))
498             {
499                 /* start peripheral */
500                 handle->outDMAHandle.peripheralConfig->startPeripheral(true);
501             }
502 
503             handle->outDMAHandle.state = kStatus_ASRCBusy;
504         }
505     }
506     else
507     {
508         return ASRC_TransferSubmitOutM2MSDMA(base, handle, outDataAddr, outDataSize);
509     }
510 
511     return kStatus_Success;
512 }
513 
ASRC_TransferInSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle,uint32_t * inDataAddr,uint32_t inDataSize)514 static status_t ASRC_TransferInSDMA(ASRC_Type *base,
515                                     asrc_sdma_handle_t *handle,
516                                     uint32_t *inDataAddr,
517                                     uint32_t inDataSize)
518 {
519     sdma_transfer_config_t inConfig = {0};
520     uint32_t asrcInAddr             = ASRC_GetWriteContextFifoAddr(base, handle->context);
521     sdma_handle_t *inDMAHandle      = handle->inDMAHandle.sdmaHandle;
522     sdma_p2p_config_t p2pConfig     = {0U};
523 
524     if ((handle->inDMAHandle.peripheralConfig != NULL) && (handle->inDMAHandle.peripheralConfig->enableContinuous) &&
525         (handle->inDMAHandle.state == (uint32_t)kStatus_ASRCBusy))
526     {
527         return kStatus_Success;
528     }
529 
530     if (handle->inDMAHandle.asrcQueue[handle->inDMAHandle.queueUser] != NULL)
531     {
532         return kStatus_ASRCQueueFull;
533     }
534 
535     if (handle->inDMAHandle.peripheralConfig != NULL)
536     {
537         p2pConfig.sourceWatermark    = handle->inDMAHandle.peripheralConfig->watermark;
538         p2pConfig.destWatermark      = handle->inDMAHandle.asrcInWatermark;
539         p2pConfig.continuousTransfer = handle->inDMAHandle.peripheralConfig->enableContinuous;
540 
541         /* Prepare sdma configure */
542         SDMA_PrepareP2PTransfer(&inConfig, (uint32_t)inDataAddr, asrcInAddr,
543                                 handle->inDMAHandle.peripheralConfig->fifoWidth, handle->inDMAHandle.bytesPerSample,
544                                 (uint32_t)handle->inDMAHandle.asrcInWatermark * handle->inDMAHandle.bytesPerSample,
545                                 inDataSize, handle->inDMAHandle.peripheralConfig->eventSource,
546                                 handle->inDMAHandle.eventSource, kSDMA_PeripheralASRCP2P, &p2pConfig);
547     }
548     else
549     {
550         SDMA_PrepareTransfer(&inConfig, (uint32_t)inDataAddr, asrcInAddr, handle->inDMAHandle.bytesPerSample,
551                              handle->inDMAHandle.bytesPerSample,
552                              (uint32_t)handle->inDMAHandle.asrcInWatermark * handle->inDMAHandle.bytesPerSample,
553                              inDataSize, handle->inDMAHandle.eventSource, kSDMA_PeripheralASRCM2P,
554                              kSDMA_MemoryToPeripheral);
555     }
556 
557     handle->inDMAHandle.sdmaTransferSize[handle->inDMAHandle.queueUser] = inDataSize;
558     handle->inDMAHandle.asrcQueue[handle->inDMAHandle.queueUser]        = inDataAddr;
559 
560     if (handle->inDMAHandle.queueUser == ASRC_XFER_IN_QUEUE_SIZE - 1U)
561     {
562         SDMA_ConfigBufferDescriptor(&inDMAHandle->BDPool[handle->inDMAHandle.queueUser], (uint32_t)inDataAddr,
563                                     asrcInAddr, inConfig.destTransferSize, inDataSize, true, true, true,
564                                     kSDMA_MemoryToPeripheral);
565     }
566     else
567     {
568         SDMA_ConfigBufferDescriptor(&inDMAHandle->BDPool[handle->inDMAHandle.queueUser], (uint32_t)inDataAddr,
569                                     asrcInAddr, inConfig.destTransferSize, inDataSize, true, true, false,
570                                     kSDMA_MemoryToPeripheral);
571     }
572 
573     handle->inDMAHandle.queueUser = (handle->inDMAHandle.queueUser + 1U) % ASRC_XFER_IN_QUEUE_SIZE;
574 
575     if (handle->inDMAHandle.state != (uint32_t)kStatus_ASRCBusy)
576     {
577         /* submit ASRC write transfer */
578         SDMA_SubmitTransfer(inDMAHandle, &inConfig);
579         /* Start DMA transfer */
580         SDMA_StartTransfer(inDMAHandle);
581 
582         /* enable ASRC DMA request */
583         ASRC_EnableContextInDMA(base, handle->context, true);
584         ASRC_ClearInterruptStatus(base, kASRC_ContextAllInterruptStatus);
585         /* enable context run */
586         ASRC_EnableContextRun(base, handle->context, true);
587 
588         if ((handle->inDMAHandle.peripheralConfig != NULL) &&
589             (handle->inDMAHandle.peripheralConfig->startPeripheral != NULL))
590         {
591             /* start peripheral */
592             handle->inDMAHandle.peripheralConfig->startPeripheral(true);
593         }
594 
595         handle->inDMAHandle.state = kStatus_ASRCBusy;
596     }
597 
598     return kStatus_Success;
599 }
600 
601 /*!
602  * brief Performs a non-blocking ASRC transfer using DMA.
603  *
604  *
605  * param base ASRC base pointer.
606  * param handle ASRC SDMA handle pointer.
607  * param xfer ASRC xfer configurations pointer.
608  * retval kStatus_Success Start a ASRC SDMA send successfully.
609  * retval kStatus_InvalidArgument The input argument is invalid.
610  * retval kStatus_TxBusy ASRC is busy sending data.
611  */
ASRC_TransferSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle,asrc_transfer_t * xfer)612 status_t ASRC_TransferSDMA(ASRC_Type *base, asrc_sdma_handle_t *handle, asrc_transfer_t *xfer)
613 {
614     assert((handle != NULL) && (xfer != NULL));
615 
616     uint32_t *inPtr = xfer->inDataAddr, *outPtr = xfer->outDataAddr;
617     uint32_t inSize = xfer->inDataSize, inOneTimeSize = 0U;
618     uint32_t outSize = xfer->outDataSize, outOneTimeSize = 0U;
619     uint32_t outWaterMarkSize = ((uint32_t)handle->outDMAHandle.asrcOutWatermark * handle->outDMAHandle.bytesPerSample);
620 
621     while ((inSize != 0U) || (outSize != 0U))
622     {
623         if (outSize != 0U)
624         {
625             outOneTimeSize = outSize > 64000U ? (64000U - 64000U % outWaterMarkSize) : outSize;
626             if (ASRC_TransferOutSDMA(base, handle, outPtr, outOneTimeSize) == kStatus_Success)
627             {
628                 outSize -= outOneTimeSize;
629                 outPtr = (uint32_t *)((uint32_t)outPtr + outOneTimeSize);
630             }
631         }
632 
633         if (inSize != 0U)
634         {
635             inOneTimeSize = inSize > 64000U ? 64000U : inSize;
636             if (ASRC_TransferInSDMA(base, handle, inPtr, inOneTimeSize) == kStatus_Success)
637             {
638                 inSize -= inOneTimeSize;
639                 inPtr = (uint32_t *)((uint32_t)inPtr + inOneTimeSize);
640             }
641         }
642     }
643 
644     return kStatus_Success;
645 }
646 
647 /*!
648  * brief Aborts a ASRC in transfer using SDMA.
649  *
650  * param base ASRC base pointer.
651  * param handle ASRC SDMA handle pointer.
652  */
ASRC_TransferAbortInSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle)653 void ASRC_TransferAbortInSDMA(ASRC_Type *base, asrc_sdma_handle_t *handle)
654 {
655     assert(handle != NULL);
656 
657     /* Disable dma */
658     SDMA_AbortTransfer(handle->inDMAHandle.sdmaHandle);
659 
660     /* enable context run */
661     ASRC_EnableContextRunStop(base, handle->context, true);
662     /* stop peripheral */
663     if ((handle->inDMAHandle.peripheralConfig != NULL) &&
664         (handle->inDMAHandle.peripheralConfig->startPeripheral != NULL))
665     {
666         handle->inDMAHandle.peripheralConfig->startPeripheral(false);
667     }
668     /* Set the handle state */
669     handle->inDMAHandle.state = kStatus_ASRCIdle;
670 }
671 
672 /*!
673  * brief Aborts a ASRC out transfer using SDMA.
674  *
675  * param base ASRC base pointer.
676  * param handle ASRC SDMA handle pointer.
677  */
ASRC_TransferAbortOutSDMA(ASRC_Type * base,asrc_sdma_handle_t * handle)678 void ASRC_TransferAbortOutSDMA(ASRC_Type *base, asrc_sdma_handle_t *handle)
679 {
680     assert(handle != NULL);
681 
682     /* Disable dma */
683     SDMA_AbortTransfer(handle->outDMAHandle.sdmaHandle);
684     /* enable ASRC DMA request */
685     ASRC_EnableContextOutDMA(base, handle->context, false);
686     /* enable context run */
687     ASRC_EnableContextRun(base, handle->context, false);
688     ASRC_EnableContextRunStop(base, handle->context, false);
689     /* stop peripheral */
690     if ((handle->outDMAHandle.peripheralConfig != NULL) &&
691         (handle->outDMAHandle.peripheralConfig->startPeripheral != NULL))
692     {
693         handle->outDMAHandle.peripheralConfig->startPeripheral(false);
694     }
695     /* Set the handle state */
696     handle->outDMAHandle.state = kStatus_ASRCIdle;
697 }
698