1 /*
2  * Copyright 2018-2022, NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include <string.h>
10 
11 #include "srtm_sai_sdma_adapter.h"
12 #include "srtm_heap.h"
13 #if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET)
14 #include "fsl_memory.h"
15 #endif
16 #include "fsl_sai.h"
17 #include "fsl_sai_sdma.h"
18 #include "srtm_dispatcher.h"
19 #include "srtm_message.h"
20 #include "srtm_message_struct.h"
21 #include "srtm_service_struct.h"
22 #include "fsl_sdma_script.h"
23 /*******************************************************************************
24  * Definitions
25  ******************************************************************************/
26 #define SRTM_SDMA_MAX_TRANSFER_SIZE UINT16_MAX
27 
28 typedef enum _srtm_sai_sdma_suspend_state
29 {
30     SRTM_NotSuspended,
31     SRTM_Suspended,
32     SRTM_WakingUp,
33 } srtm_sai_sdma_suspend_state;
34 
35 typedef struct _srtm_sai_sdma_buf_runtime
36 {
37     uint32_t leadIdx;          /* ready period index for playback or recording. */
38     uint32_t chaseIdx;         /* consumed period index for playback or recording. */
39     uint32_t loadIdx;          /* used to indicate period index preloaded either to DMA transfer or to local buffer. */
40     uint32_t remainingPeriods; /* periods to be consumed/filled */
41     uint32_t remainingLoadPeriods; /* periods to be preloaded either to DMA transfer or to local buffer. */
42     uint32_t offset;               /* period offset to copy */
43 } * srtm_sai_sdma_buf_runtime_t;
44 
45 #if SRTM_SAI_CONFIG_SupportLocalBuf
46 struct _srtm_sai_sdma_local_period
47 {
48     uint32_t dataSize;     /* bytes of copied data */
49     uint32_t endRemoteIdx; /* period index of remote buffer if local period contains remote buffer end. */
50     uint32_t remoteIdx;    /* save remote period index which the local period end points to */
51     uint32_t remoteOffset; /* save remote period offset which the local period end points to */
52 };
53 
54 struct _srtm_sai_sdma_local_runtime
55 {
56     uint32_t periodSize;
57     struct _srtm_sai_sdma_buf_runtime bufRtm;
58     struct _srtm_sai_sdma_local_period periodsInfo[SRTM_SAI_SDMA_MAX_LOCAL_BUF_PERIODS];
59 };
60 #endif
61 
62 typedef struct _srtm_sai_sdma_runtime
63 {
64     srtm_audio_state_t state;
65     sai_sdma_handle_t saiHandle;
66     uint8_t bitWidth;
67     uint8_t format;
68     sai_mono_stereo_t streamMode;
69     uint32_t srate;
70     uint8_t *bufAddr;
71     uint32_t bufSize;
72     uint32_t periodSize;
73     uint32_t periods;
74     uint32_t readyIdx; /* period ready index. */
75     uint32_t
76         maxXferSize; /* The maximum bytes can be transfered by each DMA transmission with given channels and format. */
77     uint32_t
78         countsPerPeriod;   /* The DMA transfer count for each period. If the periodSize is larger than maxXferSize,
79                               the period will be splited into multiple transmissions. Not used if localBuf is enabled. */
80     uint32_t curXferIdx;   /* The current transmission index in countsPerPeriod. Not used if localBuf is enabled. */
81     srtm_procedure_t proc; /* proc message to trigger DMA transfer in SRTM context. */
82     struct _srtm_sai_sdma_buf_runtime bufRtm; /* buffer provided by audio client. */
83 #if SRTM_SAI_CONFIG_SupportLocalBuf
84     srtm_sai_sdma_local_buf_t localBuf;
85     struct _srtm_sai_sdma_local_runtime localRtm; /* buffer set by application. */
86 #endif
87     bool freeRun; /* flag to indicate that no periodReady will be sent by audio client. */
88     bool stoppedOnSuspend;
89     bool paramSet;
90     uint32_t finishedBufOffset;               /* offset from bufAddr where the data transfer has completed. */
91     srtm_sai_sdma_suspend_state suspendState; /* service state in client suspend. */
92 #if SRTM_SAI_CONFIG_Rx_Enabled
93     srtm_sai_sdma_data_callback_t dataCallback; /* Callback function to provide data */
94     void *dataCallbackParam;                    /* Callback function argument to be passed back to application */
95 #endif
96 } * srtm_sai_sdma_runtime_t;
97 
98 /* SAI SDMA adapter */
99 typedef struct _srtm_sai_sdma_adapter
100 {
101     struct _srtm_sai_adapter adapter;
102     uint32_t index;
103 
104     I2S_Type *sai;
105     SDMAARM_Type *dma;
106     srtm_sai_sdma_config_t txConfig;
107     sdma_handle_t txDmaHandle;
108     struct _srtm_sai_sdma_runtime txRtm;
109 #if SRTM_SAI_CONFIG_Rx_Enabled
110     srtm_sai_sdma_config_t rxConfig;
111     sdma_handle_t rxDmaHandle;
112     struct _srtm_sai_sdma_runtime rxRtm;
113 #endif
114 } * srtm_sai_sdma_adapter_t;
115 
116 /*******************************************************************************
117  * Prototypes
118  ******************************************************************************/
119 #if (SRTM_SAI_CONFIG_Rx_Enabled && SRTM_SAI_CONFIG_SupportLocalBuf)
120 static void SRTM_SaiSdmaAdapter_RxCopyData(srtm_sai_sdma_adapter_t handle);
121 #endif
122 static void SRTM_SaiSdmaAdapter_AddNewPeriods(srtm_sai_sdma_runtime_t rtm, uint32_t periodIdx);
123 /*******************************************************************************
124  * Variables
125  ******************************************************************************/
126 
127 static const sai_mono_stereo_t saiChannelMap[] = {kSAI_MonoLeft, kSAI_MonoRight, kSAI_Stereo};
128 #ifdef SRTM_DEBUG_MESSAGE_FUNC
129 static const char *saiDirection[] = {"Rx", "Tx"};
130 #endif
131 #ifdef SRTM_SINGLE_SDMA_MULTI_FIFO_SCRIPT
132 short g_sdma_multi_fifo_script[] = FSL_SDMA_MULTI_FIFO_SCRIPT;
133 #else
134 static short g_sdma_multi_fifo_script[] = FSL_SDMA_MULTI_FIFO_SCRIPT;
135 #endif
136 
137 /*******************************************************************************
138  * Code
139  ******************************************************************************/
SRTM_SaiSdmaAdapter_GetAudioServiceState(srtm_sai_adapter_t adapter,srtm_audio_state_t * pTxState,srtm_audio_state_t * pRxState)140 void SRTM_SaiSdmaAdapter_GetAudioServiceState(srtm_sai_adapter_t adapter,
141                                               srtm_audio_state_t *pTxState,
142                                               srtm_audio_state_t *pRxState)
143 {
144     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
145 
146     *pTxState = handle->txRtm.state;
147 #if SRTM_SAI_CONFIG_Rx_Enabled
148     *pRxState = handle->rxRtm.state;
149 #else
150     *pRxState                          = SRTM_AudioStateClosed;
151 #endif
152 }
153 
154 #if SRTM_SAI_CONFIG_SupportLocalBuf
SRTM_SaidmaAdapter_LocalBufferUpdate(uint32_t * dest,uint32_t * src,uint32_t count)155 static void SRTM_SaidmaAdapter_LocalBufferUpdate(uint32_t *dest, uint32_t *src, uint32_t count)
156 {
157     while (count != 0U)
158     {
159         *dest = *src;
160         dest++;
161         src++;
162         count--;
163     }
164 }
165 #endif
166 
SRTM_SaiSdmaAdapter_RecycleTxMessage(srtm_message_t msg,void * param)167 static void SRTM_SaiSdmaAdapter_RecycleTxMessage(srtm_message_t msg, void *param)
168 {
169     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)param;
170 
171     assert(handle->txRtm.proc == NULL);
172 
173     handle->txRtm.proc = msg;
174 }
175 
176 #if SRTM_SAI_CONFIG_Rx_Enabled
SRTM_SaiSdmaAdapter_RecycleRxMessage(srtm_message_t msg,void * param)177 static void SRTM_SaiSdmaAdapter_RecycleRxMessage(srtm_message_t msg, void *param)
178 {
179     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)param;
180     assert(handle->rxRtm.proc == NULL);
181 
182     handle->rxRtm.proc = msg;
183 }
184 #endif
185 
186 #if SRTM_SAI_CONFIG_SupportLocalBuf
SRTM_SaiSdmaAdaptor_ResetLocalBuf(srtm_sai_sdma_runtime_t rtm,srtm_audio_dir_t dir)187 static void SRTM_SaiSdmaAdaptor_ResetLocalBuf(srtm_sai_sdma_runtime_t rtm, srtm_audio_dir_t dir)
188 {
189     uint32_t i, n, alignment, maxPeriodSize;
190 
191     alignment = ((uint32_t)(rtm->bitWidth) >> 3U) * (rtm->streamMode == kSAI_Stereo ? 2UL : 1UL);
192 
193     if ((alignment % SRTM_SAI_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT) != 0U)
194     {
195         alignment *= SRTM_SAI_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT;
196     }
197 
198     if (rtm->localBuf.buf != NULL)
199     {
200         (void)memset(&rtm->localRtm.bufRtm, 0, sizeof(struct _srtm_sai_sdma_buf_runtime));
201         maxPeriodSize =
202             (rtm->localBuf.bufSize / rtm->localBuf.periods) & (~SRTM_SAI_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT_MASK);
203 
204         if (dir == SRTM_AudioDirTx)
205         {
206             /* Calculate how many local periods each remote period */
207             n = (rtm->periodSize + maxPeriodSize - 1U) / maxPeriodSize;
208             /* Calculate local period size per remote period */
209             rtm->localRtm.periodSize =
210                 ((rtm->periodSize + n - 1U) / n + SRTM_SAI_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT_MASK) &
211                 (~SRTM_SAI_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT_MASK);
212             /* The period size should be a multiple of bytes per sample */
213             rtm->localRtm.periodSize = (rtm->localRtm.periodSize + alignment - 1U) / alignment * alignment;
214             if (rtm->localRtm.periodSize > maxPeriodSize)
215             {
216                 rtm->localRtm.periodSize -= alignment;
217             }
218 
219             for (i = 0U; i < SRTM_SAI_SDMA_MAX_LOCAL_BUF_PERIODS; i++)
220             {
221                 rtm->localRtm.periodsInfo[i].dataSize     = 0U;
222                 rtm->localRtm.periodsInfo[i].endRemoteIdx = UINT32_MAX;
223                 rtm->localRtm.periodsInfo[i].remoteIdx    = 0U;
224                 rtm->localRtm.periodsInfo[i].remoteOffset = 0U;
225             }
226         }
227 #if SRTM_SAI_CONFIG_Rx_Enabled
228         else /* RX */
229         {
230             rtm->localRtm.periodSize = rtm->localBuf.bufSize / rtm->localBuf.periods;
231             rtm->localRtm.periodSize = rtm->localRtm.periodSize / alignment * alignment;
232 
233             rtm->localRtm.bufRtm.remainingLoadPeriods = rtm->localBuf.periods;
234             rtm->localRtm.bufRtm.remainingPeriods     = rtm->localBuf.periods;
235 
236             for (i = 0U; i < SRTM_SAI_SDMA_MAX_LOCAL_BUF_PERIODS; i++)
237             {
238                 rtm->localRtm.periodsInfo[i].dataSize = rtm->localRtm.periodSize;
239             }
240         }
241 #endif /* SRTM_SAI_CONFIG_Rx_Enabled */
242     }
243 }
244 #endif
245 
SRTM_SaiSdmaAdapter_PeriodTransferSDMA(srtm_sai_sdma_adapter_t handle,srtm_audio_dir_t dir)246 static status_t SRTM_SaiSdmaAdapter_PeriodTransferSDMA(srtm_sai_sdma_adapter_t handle, srtm_audio_dir_t dir)
247 {
248     status_t status = kStatus_Success;
249     uint32_t count;
250     sai_transfer_t xfer;
251 #if SRTM_SAI_CONFIG_Rx_Enabled
252     srtm_sai_sdma_runtime_t rtm = (dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm);
253 #else
254     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
255 #endif
256     srtm_sai_sdma_buf_runtime_t bufRtm;
257 
258 #if SRTM_SAI_CONFIG_SupportLocalBuf
259     if (rtm->localBuf.buf != NULL)
260     {
261         bufRtm = &rtm->localRtm.bufRtm;
262 
263         /* The period size in local buffer should be smaller than the max size of one DMA transfer. */
264         xfer.dataSize = rtm->localRtm.periodsInfo[bufRtm->loadIdx].dataSize;
265         xfer.data     = rtm->localBuf.buf + bufRtm->loadIdx * rtm->localRtm.periodSize;
266 
267         if (dir == SRTM_AudioDirTx)
268         {
269             status = SAI_TransferSendSDMA(handle->sai, &rtm->saiHandle, &xfer);
270         }
271 #if SRTM_SAI_CONFIG_Rx_Enabled
272         else
273         {
274             status = SAI_TransferReceiveSDMA(handle->sai, &rtm->saiHandle, &xfer);
275         }
276 #endif
277         if (status != kStatus_Success)
278         {
279             /* Audio queue full */
280             return status;
281         }
282         bufRtm->loadIdx = (bufRtm->loadIdx + 1U) % rtm->localBuf.periods;
283         bufRtm->remainingLoadPeriods--;
284     }
285     else
286 #endif /* SRTM_SAI_CONFIG_SupportLocalBuf */
287     {
288         bufRtm = &rtm->bufRtm;
289 
290         count = rtm->periodSize - bufRtm->offset;
291         while (count > rtm->maxXferSize) /* Split the period into several DMA transfer. */
292         {
293             xfer.dataSize = rtm->maxXferSize;
294             xfer.data     = rtm->bufAddr + bufRtm->loadIdx * rtm->periodSize + bufRtm->offset;
295             if (dir == SRTM_AudioDirTx)
296             {
297                 status = SAI_TransferSendSDMA(handle->sai, &rtm->saiHandle, &xfer);
298             }
299 #if SRTM_SAI_CONFIG_Rx_Enabled
300             else
301             {
302                 status = SAI_TransferReceiveSDMA(handle->sai, &rtm->saiHandle, &xfer);
303             }
304 #endif
305 
306             if (status == kStatus_Success)
307             {
308                 count = count - rtm->maxXferSize;
309                 bufRtm->offset += rtm->maxXferSize;
310             }
311             else
312             {
313                 return status;
314             }
315         }
316         if (count > 0U)
317         {
318             xfer.dataSize = count;
319             xfer.data     = rtm->bufAddr + bufRtm->loadIdx * rtm->periodSize + bufRtm->offset;
320 
321             if (dir == SRTM_AudioDirTx)
322             {
323                 status = SAI_TransferSendSDMA(handle->sai, &rtm->saiHandle, &xfer);
324             }
325 #if SRTM_SAI_CONFIG_Rx_Enabled
326             else
327             {
328                 status = SAI_TransferReceiveSDMA(handle->sai, &rtm->saiHandle, &xfer);
329             }
330 #endif
331 
332             if (status != kStatus_Success)
333             {
334                 return status;
335             }
336             bufRtm->offset = 0; /* All the transfers for the one period are submitted. */
337         }
338 
339         if (bufRtm->offset == 0U) /* All transmissions in a preiod are submitted successfully. */
340         {
341             bufRtm->loadIdx = (bufRtm->loadIdx + 1U) % rtm->periods;
342             bufRtm->remainingLoadPeriods--;
343         }
344     }
345 
346     return kStatus_Success;
347 }
348 
SRTM_SaiSdmaAdapter_DmaTransfer(srtm_sai_sdma_adapter_t handle,srtm_audio_dir_t dir)349 static void SRTM_SaiSdmaAdapter_DmaTransfer(srtm_sai_sdma_adapter_t handle, srtm_audio_dir_t dir)
350 {
351 #if SRTM_SAI_CONFIG_Rx_Enabled
352     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
353 #else
354     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
355 #endif
356 #if SRTM_SAI_CONFIG_SupportLocalBuf
357     srtm_sai_sdma_buf_runtime_t bufRtm = (rtm->localBuf.buf != NULL) ? &rtm->localRtm.bufRtm : &rtm->bufRtm;
358 #else
359     srtm_sai_sdma_buf_runtime_t bufRtm = &rtm->bufRtm;
360 #endif
361     uint32_t i;
362     status_t status;
363     uint32_t num;
364 
365     num = bufRtm->remainingLoadPeriods;
366 
367     for (i = 0U; i < num; i++)
368     {
369         status = SRTM_SaiSdmaAdapter_PeriodTransferSDMA(handle, dir);
370         if (status != kStatus_Success)
371         {
372             /* Audio queue full */
373             break;
374         }
375     }
376 }
377 
378 #if SRTM_SAI_CONFIG_SupportLocalBuf
SRTM_SaiSdmaAdapter_CopyData(srtm_sai_sdma_adapter_t handle)379 static void SRTM_SaiSdmaAdapter_CopyData(srtm_sai_sdma_adapter_t handle)
380 {
381     srtm_sai_sdma_runtime_t rtm;
382     uint32_t srcSize, dstSize, size;
383     srtm_sai_sdma_buf_runtime_t srcRtm, dstRtm;
384     uint8_t *src, *dst;
385 
386     rtm    = &handle->txRtm;
387     srcRtm = &rtm->bufRtm;
388     dstRtm = &rtm->localRtm.bufRtm;
389 
390     while ((srcRtm->remainingLoadPeriods != 0U) && ((rtm->localBuf.periods - dstRtm->remainingPeriods) != 0U))
391     {
392         src     = rtm->bufAddr + srcRtm->loadIdx * rtm->periodSize;
393         dst     = rtm->localBuf.buf + dstRtm->leadIdx * rtm->localRtm.periodSize;
394         srcSize = rtm->periodSize - srcRtm->offset;
395         dstSize = rtm->localRtm.periodSize - dstRtm->offset;
396         size    = MIN(srcSize, dstSize);
397         SRTM_SaidmaAdapter_LocalBufferUpdate((uint32_t *)(void *)(dst + dstRtm->offset),
398                                              (uint32_t *)(void *)(src + srcRtm->offset), size / 4U);
399 
400         srcRtm->offset += size;
401         dstRtm->offset += size;
402         if (srcRtm->offset == rtm->periodSize) /* whole remote buffer loaded */
403         {
404             rtm->localRtm.periodsInfo[dstRtm->leadIdx].endRemoteIdx = srcRtm->loadIdx;
405             srcRtm->loadIdx                                         = (srcRtm->loadIdx + 1U) % rtm->periods;
406             srcRtm->offset                                          = 0U;
407             srcRtm->remainingLoadPeriods--;
408         }
409 
410         if ((dstRtm->offset == rtm->localRtm.periodSize) || (srcRtm->offset == 0U))
411         {
412             /* local period full or remote period ends */
413             rtm->localRtm.periodsInfo[dstRtm->leadIdx].dataSize     = dstRtm->offset;
414             rtm->localRtm.periodsInfo[dstRtm->leadIdx].remoteIdx    = srcRtm->loadIdx;
415             rtm->localRtm.periodsInfo[dstRtm->leadIdx].remoteOffset = srcRtm->offset;
416             dstRtm->leadIdx                                         = (dstRtm->leadIdx + 1U) % rtm->localBuf.periods;
417             dstRtm->remainingPeriods++;
418             dstRtm->remainingLoadPeriods++;
419             dstRtm->offset = 0U;
420         }
421     }
422 }
423 #endif
424 
425 #if (SRTM_SAI_CONFIG_Rx_Enabled && SRTM_SAI_CONFIG_SupportLocalBuf)
SRTM_SaiSdmaAdapter_RxPeriodCopyAndNotify(srtm_sai_sdma_adapter_t handle)426 static void SRTM_SaiSdmaAdapter_RxPeriodCopyAndNotify(srtm_sai_sdma_adapter_t handle)
427 {
428     srtm_sai_adapter_t adapter = &handle->adapter;
429     srtm_sai_sdma_runtime_t rtm;
430     uint32_t srcSize, dstSize, size;
431     srtm_sai_sdma_buf_runtime_t srcRtm, dstRtm;
432     uint8_t *src, *dst;
433     uint32_t primask;
434     rtm    = &handle->rxRtm;
435     srcRtm = &rtm->localRtm.bufRtm;
436     dstRtm = &rtm->bufRtm;
437 
438     /* Local buffer is not empty and remote buffer is not full. */
439     if ((srcRtm->remainingPeriods != rtm->localBuf.periods) && (dstRtm->remainingPeriods != 0U))
440     {
441         src     = rtm->localBuf.buf + srcRtm->leadIdx * rtm->localRtm.periodSize;
442         dst     = rtm->bufAddr + dstRtm->chaseIdx * rtm->periodSize;
443         srcSize = rtm->localRtm.periodSize - srcRtm->offset;
444         dstSize = rtm->periodSize - dstRtm->offset;
445         size    = MIN(srcSize, dstSize);
446         SRTM_SaidmaAdapter_LocalBufferUpdate((uint32_t *)(void *)(dst + dstRtm->offset),
447                                              (uint32_t *)(void *)(src + srcRtm->offset), size / 4U);
448 
449         srcRtm->offset += size;
450         dstRtm->offset += size;
451         if (srcRtm->offset == rtm->localRtm.periodSize) /* whole local buffer copied */
452         {
453             srcRtm->leadIdx = (srcRtm->leadIdx + 1U) % rtm->localBuf.periods;
454             srcRtm->offset  = 0U;
455             primask         = DisableGlobalIRQ();
456             srcRtm->remainingPeriods++;
457             srcRtm->remainingLoadPeriods++;
458             EnableGlobalIRQ(primask);
459         }
460 
461         if (dstRtm->offset == rtm->periodSize)
462         {
463             /* One period is filled. */
464             dstRtm->chaseIdx = (dstRtm->chaseIdx + 1U) % rtm->periods;
465             dstRtm->remainingPeriods--; /* Now one of the remote buffer has been consumed. Assume the ready period is
466                                            consumed by host immediately. */
467             dstRtm->remainingLoadPeriods--; /* Unused. */
468             rtm->finishedBufOffset = dstRtm->chaseIdx * rtm->periodSize;
469             dstRtm->offset         = 0U;
470 
471             SRTM_SaiSdmaAdapter_AddNewPeriods(rtm, dstRtm->chaseIdx);
472 
473             if ((adapter->service != NULL) && (adapter->periodDone != NULL))
474             {
475                 if (((rtm->suspendState != SRTM_Suspended) || (rtm->dataCallback == NULL)))
476                 {
477                     (void)adapter->periodDone(adapter->service, SRTM_AudioDirRx, handle->index, rtm->bufRtm.chaseIdx);
478                 }
479             }
480         }
481     }
482 }
483 
SRTM_SaiSdmaAdapter_RxDataCopyProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)484 static void SRTM_SaiSdmaAdapter_RxDataCopyProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
485 {
486     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)param1;
487 
488     /* More data need to be copied. */
489     SRTM_SaiSdmaAdapter_RxCopyData(handle);
490 }
491 
SRTM_SaiSdmaAdapter_RxCopyData(srtm_sai_sdma_adapter_t handle)492 static void SRTM_SaiSdmaAdapter_RxCopyData(srtm_sai_sdma_adapter_t handle)
493 {
494     srtm_sai_adapter_t adapter = &handle->adapter;
495     srtm_sai_sdma_runtime_t rtm;
496     srtm_sai_sdma_buf_runtime_t srcRtm, dstRtm;
497     rtm    = &handle->rxRtm;
498     srcRtm = &rtm->localRtm.bufRtm;
499     dstRtm = &rtm->bufRtm;
500     srtm_procedure_t proc;
501 
502     SRTM_SaiSdmaAdapter_RxPeriodCopyAndNotify(handle);
503 
504     /* More data need to be copied. */
505     if ((srcRtm->remainingPeriods != rtm->localBuf.periods) && (dstRtm->remainingPeriods != 0U))
506     {
507         proc = SRTM_Procedure_Create(SRTM_SaiSdmaAdapter_RxDataCopyProc, handle, NULL);
508         if ((adapter->service != NULL) && (proc != NULL))
509         {
510             (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
511         }
512     }
513 }
514 #endif
515 
SRTM_SaiSdmaAdapter_AddNewPeriods(srtm_sai_sdma_runtime_t rtm,uint32_t periodIdx)516 static void SRTM_SaiSdmaAdapter_AddNewPeriods(srtm_sai_sdma_runtime_t rtm, uint32_t periodIdx)
517 {
518     srtm_sai_sdma_buf_runtime_t bufRtm = &rtm->bufRtm;
519     uint32_t newPeriods;
520     uint32_t primask;
521 
522     assert(periodIdx < rtm->periods);
523 
524     newPeriods = (periodIdx + rtm->periods - bufRtm->leadIdx) % rtm->periods;
525     if (newPeriods == 0U) /* in case buffer is empty and filled all */
526     {
527         newPeriods = rtm->periods;
528     }
529 
530     bufRtm->leadIdx = periodIdx;
531     primask         = DisableGlobalIRQ();
532     bufRtm->remainingPeriods += newPeriods;
533     EnableGlobalIRQ(primask);
534     bufRtm->remainingLoadPeriods += newPeriods;
535 }
536 
SRTM_SaiSdmaAdapter_Transfer(srtm_sai_sdma_adapter_t handle,srtm_audio_dir_t dir)537 static void SRTM_SaiSdmaAdapter_Transfer(srtm_sai_sdma_adapter_t handle, srtm_audio_dir_t dir)
538 {
539 #if SRTM_SAI_CONFIG_Rx_Enabled
540     srtm_sai_sdma_runtime_t rtm = (dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm);
541 #else
542     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
543 #endif
544 
545 #if SRTM_SAI_CONFIG_SupportLocalBuf
546     if (rtm->localBuf.buf != NULL)
547     {
548         if ((dir == SRTM_AudioDirTx) && (rtm->localRtm.bufRtm.remainingPeriods <= rtm->localBuf.threshold))
549         {
550             /* Copy data from remote buffer to local buffer. */
551             SRTM_SaiSdmaAdapter_CopyData(handle);
552         }
553     }
554 #endif
555 
556     /* Trigger DMA if having more data to playback/record. */
557     SRTM_SaiSdmaAdapter_DmaTransfer(handle, dir);
558 
559 #if (SRTM_SAI_CONFIG_Rx_Enabled && SRTM_SAI_CONFIG_SupportLocalBuf)
560     if ((rtm->localBuf.buf != NULL) && (dir == SRTM_AudioDirRx))
561     {
562         if ((rtm->localRtm.bufRtm.remainingPeriods < rtm->localBuf.periods) &&
563             ((rtm->suspendState != SRTM_Suspended) || (rtm->dataCallback == NULL)))
564         {
565             /* Copy data from local buffer to remote buffer and notify remote. */
566             SRTM_SaiSdmaAdapter_RxCopyData(handle);
567         }
568     }
569 #endif
570 
571     if (rtm->freeRun && (rtm->bufRtm.remainingPeriods < rtm->periods))
572     {
573         /* In free run, we assume consumed period is filled immediately. */
574         SRTM_SaiSdmaAdapter_AddNewPeriods(rtm, rtm->bufRtm.chaseIdx);
575     }
576 }
577 
SRTM_SaiSdmaAdapter_TxTransferProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)578 static void SRTM_SaiSdmaAdapter_TxTransferProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
579 {
580     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)param1;
581     srtm_sai_sdma_runtime_t rtm    = &handle->txRtm;
582 
583     if (rtm->state == SRTM_AudioStateStarted)
584     {
585         SRTM_SaiSdmaAdapter_Transfer(handle, SRTM_AudioDirTx);
586     }
587 }
588 
589 #if SRTM_SAI_CONFIG_Rx_Enabled
SRTM_SaiSdmaAdapter_RxTransferProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)590 static void SRTM_SaiSdmaAdapter_RxTransferProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
591 {
592     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)param1;
593     srtm_sai_sdma_runtime_t rtm    = &handle->rxRtm;
594     srtm_sai_adapter_t adapter     = &handle->adapter;
595     uint32_t chaseIdx              = (uint32_t)(uint8_t *)param2;
596     uint8_t *bufAddr;
597     uint32_t bufSize;
598 
599     if ((rtm->suspendState == SRTM_Suspended) && (rtm->dataCallback != NULL) && (chaseIdx != UINT32_MAX))
600     {
601 #if SRTM_SAI_CONFIG_SupportLocalBuf
602         if (rtm->localBuf.buf != NULL)
603         {
604             bufAddr = rtm->localBuf.buf + chaseIdx * rtm->localRtm.periodSize;
605             bufSize = rtm->localRtm.periodsInfo[chaseIdx].dataSize;
606         }
607         else
608 #endif
609         {
610             bufAddr = rtm->bufAddr + chaseIdx * rtm->periodSize;
611             bufSize = rtm->periodSize;
612         }
613         rtm->dataCallback(adapter, (void *)bufAddr, bufSize, rtm->dataCallbackParam);
614     }
615 
616     if (rtm->state == SRTM_AudioStateStarted)
617     {
618         /* Trigger DMA if having more buffer to record. */
619         SRTM_SaiSdmaAdapter_Transfer(handle, SRTM_AudioDirRx);
620     }
621 }
622 #endif
623 
SRTM_SaiSdmaTxCallback(I2S_Type * sai,sai_sdma_handle_t * sdmaHandle,status_t status,void * userData)624 static void SRTM_SaiSdmaTxCallback(I2S_Type *sai, sai_sdma_handle_t *sdmaHandle, status_t status, void *userData)
625 {
626     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)userData;
627     srtm_sai_sdma_runtime_t rtm    = &handle->txRtm;
628     srtm_sai_adapter_t adapter     = &handle->adapter;
629     bool consumed                  = true;
630     bool periodDone                = false;
631 
632 #if SRTM_SAI_CONFIG_SupportLocalBuf
633     if (rtm->localBuf.buf != NULL)
634     {
635         if (rtm->localRtm.periodsInfo[rtm->localRtm.bufRtm.chaseIdx].endRemoteIdx < rtm->periods)
636         {
637             /* The local buffer contains data from remote buffer end */
638             rtm->bufRtm.remainingPeriods--; /* Now one of the remote buffer has been consumed. */
639             rtm->bufRtm.chaseIdx = (rtm->bufRtm.chaseIdx + 1U) % rtm->periods;
640             rtm->localRtm.periodsInfo[rtm->localRtm.bufRtm.chaseIdx].endRemoteIdx = UINT32_MAX;
641         }
642         else
643         {
644             /* Remote period not consumed. */
645             consumed = false;
646         }
647 
648         rtm->finishedBufOffset = rtm->localRtm.periodsInfo[rtm->localRtm.bufRtm.chaseIdx].remoteIdx * rtm->periodSize +
649                                  rtm->localRtm.periodsInfo[rtm->localRtm.bufRtm.chaseIdx].remoteOffset;
650         rtm->localRtm.bufRtm.remainingPeriods--;
651         rtm->localRtm.bufRtm.chaseIdx = (rtm->localRtm.bufRtm.chaseIdx + 1U) % rtm->localBuf.periods;
652 
653         periodDone = true;
654     }
655     else
656 #endif
657     {
658         if (rtm->curXferIdx == rtm->countsPerPeriod)
659         {
660             rtm->curXferIdx = 1U;
661             periodDone      = true;
662 
663             rtm->bufRtm.remainingPeriods--;
664             rtm->bufRtm.chaseIdx   = (rtm->bufRtm.chaseIdx + 1U) % rtm->periods;
665             rtm->finishedBufOffset = rtm->bufRtm.chaseIdx * rtm->periodSize;
666         }
667         else
668         {
669             rtm->curXferIdx++;
670             periodDone = false;
671             SRTM_SaiSdmaAdapter_DmaTransfer(handle, SRTM_AudioDirTx);
672         }
673     }
674 
675     if (periodDone)
676     {
677         /* Notify period done message */
678         if ((adapter->service != NULL) && (adapter->periodDone != NULL) && consumed &&
679             (rtm->freeRun || (rtm->bufRtm.remainingPeriods <= handle->txConfig.threshold) ||
680              (rtm->suspendState != SRTM_Suspended)))
681         {
682             /* In free run, we need to make buffer as full as possible, threshold is ignored. */
683             (void)adapter->periodDone(adapter->service, SRTM_AudioDirTx, handle->index, rtm->bufRtm.chaseIdx);
684         }
685 
686         if ((adapter->service != NULL) && (rtm->proc != NULL))
687         {
688             /* Fill data or add buffer to DMA scatter-gather list if there's remaining buffer to send */
689             (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, rtm->proc);
690             rtm->proc = NULL;
691         }
692         else if (rtm->proc == NULL)
693         {
694             SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: proc busy!\r\n", __func__);
695         }
696         else
697         {
698             ; /* Intentional empty */
699         }
700     }
701 }
702 
703 #if SRTM_SAI_CONFIG_Rx_Enabled
SRTM_SaiSdmaRxCallback(I2S_Type * sai,sai_sdma_handle_t * sdmaHandle,status_t status,void * userData)704 static void SRTM_SaiSdmaRxCallback(I2S_Type *sai, sai_sdma_handle_t *sdmaHandle, status_t status, void *userData)
705 {
706     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)userData;
707     srtm_sai_sdma_runtime_t rtm    = &handle->rxRtm;
708     srtm_sai_adapter_t adapter     = &handle->adapter;
709     uint32_t chaseIdx              = UINT32_MAX;
710 
711     bool periodDone = false; /* One period transfer is finished. Indicating local period when localBuf is used. */
712 #if SRTM_SAI_CONFIG_SupportLocalBuf
713     /* When localBuf is used, the period size should not exceed the max size supported by one DMA tranfer. */
714     if (rtm->localBuf.buf != NULL)
715     {
716         rtm->localRtm.bufRtm.remainingPeriods--; /* One of the local period is filled */
717 
718         chaseIdx                      = rtm->localRtm.bufRtm.chaseIdx; /* For callback */
719         rtm->localRtm.bufRtm.chaseIdx = (rtm->localRtm.bufRtm.chaseIdx + 1U) % rtm->localBuf.periods;
720 
721         /* Rx is always freeRun, we assume filled period is consumed immediately. */
722         periodDone = true;
723         if ((rtm->suspendState == SRTM_Suspended) && (rtm->dataCallback != NULL))
724         {
725             /* Local RX buffer is full. Allow overwrite. remainingPeriods should be 0*/
726             if (rtm->localRtm.bufRtm.chaseIdx == rtm->localRtm.bufRtm.leadIdx)
727             {
728                 rtm->localRtm.bufRtm.leadIdx = (rtm->localRtm.bufRtm.leadIdx + 1U) % rtm->localBuf.periods;
729                 rtm->localRtm.bufRtm.remainingLoadPeriods =
730                     (rtm->localRtm.bufRtm.remainingLoadPeriods + 1U) % rtm->localBuf.periods;
731                 rtm->localRtm.bufRtm.remainingPeriods =
732                     (rtm->localRtm.bufRtm.remainingPeriods + 1U) % rtm->localBuf.periods;
733             }
734         }
735     }
736     else /* The localBuf is not used, the period size may exceed the max size supported by one DMA tranfer.*/
737 #endif
738     {
739         if (rtm->curXferIdx == rtm->countsPerPeriod) /* All the transfer in a period is done. */
740         {
741             rtm->curXferIdx = 1U;
742             periodDone      = true;
743 
744             rtm->bufRtm.remainingPeriods--;
745             chaseIdx               = rtm->bufRtm.chaseIdx; /* For callback */
746             rtm->bufRtm.chaseIdx   = (rtm->bufRtm.chaseIdx + 1U) % rtm->periods;
747             rtm->finishedBufOffset = rtm->bufRtm.chaseIdx * rtm->periodSize;
748 
749             /* Rx is always freeRun, we assume filled period is consumed immediately. */
750             SRTM_SaiSdmaAdapter_AddNewPeriods(rtm, rtm->bufRtm.chaseIdx);
751 
752             if ((adapter->service != NULL) && (adapter->periodDone != NULL))
753             {
754                 /* Rx is always freeRun */
755                 if ((rtm->suspendState != SRTM_Suspended) || (rtm->dataCallback == NULL))
756                 {
757                     (void)adapter->periodDone(adapter->service, SRTM_AudioDirRx, handle->index, rtm->bufRtm.chaseIdx);
758                 }
759             }
760         }
761         else
762         {
763             rtm->curXferIdx++;
764             SRTM_SaiSdmaAdapter_DmaTransfer(handle, SRTM_AudioDirRx);
765         }
766     }
767 
768     if (periodDone)
769     {
770         if ((adapter->service != NULL) && (rtm->proc != NULL))
771         {
772             rtm->proc->procMsg.param2 = (void *)(uint8_t *)chaseIdx;
773             /* Add buffer to DMA scatter-gather list if there's remaining buffer to record. */
774             (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, rtm->proc);
775             rtm->proc = NULL;
776         }
777         else if (rtm->proc == NULL)
778         {
779             SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: proc busy!\r\n", __func__);
780         }
781         else
782         {
783             ; /* Intentional empty. */
784         }
785     }
786 }
787 #endif
788 
SRTM_SaiSdmaAdapter_InitSAI(srtm_sai_sdma_adapter_t handle,srtm_audio_dir_t dir)789 static void SRTM_SaiSdmaAdapter_InitSAI(srtm_sai_sdma_adapter_t handle, srtm_audio_dir_t dir)
790 {
791 #if SRTM_SAI_CONFIG_Rx_Enabled
792     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
793 #else
794     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
795 #endif
796 
797     if (dir == SRTM_AudioDirTx)
798     {
799         SDMA_CreateHandle(&handle->txDmaHandle, handle->dma, handle->txConfig.dmaChannel, &handle->txConfig.txcontext);
800         handle->txDmaHandle.priority = handle->txConfig.ChannelPriority;
801         if (rtm->format >= (uint8_t)SRTM_Audio_DSD8bits) /* DSD mode, need enable SDMA multi fifo */
802         {
803             SDMA_LoadScript(handle->dma, FSL_SDMA_SCRIPT_CODE_START_ADDR, (void *)g_sdma_multi_fifo_script,
804                             FSL_SDMA_SCRIPT_CODE_SIZE);
805         }
806         SAI_TransferTxCreateHandleSDMA(handle->sai, &handle->txRtm.saiHandle, SRTM_SaiSdmaTxCallback, (void *)handle,
807                                        &handle->txDmaHandle, handle->txConfig.eventSource);
808     }
809 #if SRTM_SAI_CONFIG_Rx_Enabled
810     else
811     {
812         SDMA_CreateHandle(&handle->rxDmaHandle, handle->dma, handle->rxConfig.dmaChannel, &handle->rxConfig.rxcontext);
813         handle->rxDmaHandle.priority = handle->rxConfig.ChannelPriority;
814         SAI_TransferRxCreateHandleSDMA(handle->sai, &handle->rxRtm.saiHandle, SRTM_SaiSdmaRxCallback, (void *)handle,
815                                        &handle->rxDmaHandle, handle->rxConfig.eventSource);
816     }
817 #endif
818 }
819 
SRTM_SaiSdmaAdapter_DeinitSAI(srtm_sai_sdma_adapter_t handle,srtm_audio_dir_t dir)820 static void SRTM_SaiSdmaAdapter_DeinitSAI(srtm_sai_sdma_adapter_t handle, srtm_audio_dir_t dir)
821 {
822     if (dir == SRTM_AudioDirTx)
823     {
824         SAI_TxReset(handle->sai);
825     }
826 #if SRTM_SAI_CONFIG_Rx_Enabled
827     else
828     {
829         SAI_RxReset(handle->sai);
830     }
831 #endif
832 }
833 
SRTM_SaiSdmaAdapter_ReconfigSAI(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t format,uint32_t srate)834 static void SRTM_SaiSdmaAdapter_ReconfigSAI(srtm_sai_adapter_t adapter,
835                                             srtm_audio_dir_t dir,
836                                             uint8_t format,
837                                             uint32_t srate)
838 {
839     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
840 #if SRTM_SAI_CONFIG_Rx_Enabled
841     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
842     srtm_sai_sdma_config_t *cfg = dir == SRTM_AudioDirTx ? &handle->txConfig : &handle->rxConfig;
843 #else
844     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
845     srtm_sai_sdma_config_t *cfg        = &handle->txConfig;
846 #endif
847     uint32_t saiSrcClk;
848 
849     if ((format >= (uint8_t)SRTM_Audio_DSD8bits) && (format <= (uint8_t)SRTM_Audio_DSD32bits))
850     {
851         srate = srate / 2U;
852     }
853 
854     if (((rtm->format != format) || (rtm->srate != srate)) && (cfg->extendConfig.audioDevConf != NULL))
855     {
856         saiSrcClk                       = cfg->extendConfig.audioDevConf((srtm_audio_format_type_t)format, srate);
857         cfg->mclkConfig.mclkSourceClkHz = saiSrcClk;
858         cfg->mclkConfig.mclkHz          = saiSrcClk;
859     }
860 }
861 
SRTM_SaiSdmaAdapter_SetFormat(srtm_sai_sdma_adapter_t handle,srtm_audio_dir_t dir)862 static void SRTM_SaiSdmaAdapter_SetFormat(srtm_sai_sdma_adapter_t handle, srtm_audio_dir_t dir)
863 {
864 #if SRTM_SAI_CONFIG_Rx_Enabled
865     srtm_sai_sdma_config_t *cfg = dir == SRTM_AudioDirTx ? &handle->txConfig : &handle->rxConfig;
866 #else
867     srtm_sai_sdma_config_t *cfg        = &handle->txConfig;
868 #endif
869     srtm_sai_sdma_runtime_t rtm, paramRtm;
870     uint8_t channels, bitWidth;
871     bool sync = cfg->config.syncMode == kSAI_ModeSync;
872 
873 #if SRTM_SAI_CONFIG_Rx_Enabled
874     if (dir == SRTM_AudioDirTx)
875     {
876         rtm = &handle->txRtm;
877         if (!rtm->paramSet)
878         {
879             /* There must be a path with param configured before start. */
880             assert(handle->rxRtm.paramSet);
881             paramRtm = &handle->rxRtm;
882         }
883         else
884         {
885             paramRtm = (sync && (handle->rxConfig.config.syncMode == kSAI_ModeAsync) && handle->rxRtm.paramSet) ?
886                            &handle->rxRtm :
887                            rtm;
888         }
889     }
890     else
891     {
892         rtm = &handle->rxRtm;
893         if (!rtm->paramSet)
894         {
895             /* There must be a path with param configured before start. */
896             assert(handle->txRtm.paramSet);
897             paramRtm = &handle->txRtm;
898         }
899         else
900         {
901             paramRtm = (sync && (handle->txConfig.config.syncMode == kSAI_ModeAsync) && handle->txRtm.paramSet) ?
902                            &handle->txRtm :
903                            rtm;
904         }
905     }
906 #else
907     rtm                                = &handle->txRtm;
908     paramRtm                           = rtm;
909 #endif
910 
911     channels                                   = paramRtm->streamMode == kSAI_Stereo ? 2U : 1U;
912     bitWidth                                   = paramRtm->bitWidth == 24U ? 32U : paramRtm->bitWidth;
913     cfg->config.serialData.dataMaskedWord      = (uint32_t)paramRtm->streamMode;
914     cfg->config.serialData.dataWord0Length     = bitWidth;
915     cfg->config.serialData.dataWordLength      = bitWidth;
916     cfg->config.serialData.dataWordNLength     = bitWidth;
917     cfg->config.serialData.dataFirstBitShifted = paramRtm->bitWidth;
918     cfg->config.frameSync.frameSyncWidth       = bitWidth;
919 
920     /* set master clock to async mclk. */
921     if (!sync)
922     {
923         SAI_SetMasterClockConfig(handle->sai, &cfg->mclkConfig);
924     }
925 
926     if (dir == SRTM_AudioDirTx)
927     {
928         if (rtm->format >= (uint8_t)SRTM_Audio_DSD8bits) /* DSD mode */
929         {
930             cfg->config.channelMask          = 1U << cfg->dataLine1 | 1U << cfg->dataLine2;
931             cfg->config.serialData.dataOrder = kSAI_DataLSB; /* LSB transfer first */
932             cfg->config.serialData.dataFirstBitShifted =
933                 1U; /* The value should be fixed to 1 when in LSB transfer mode */
934         }
935         else
936         {
937             cfg->config.channelMask          = 1U << cfg->dataLine1;
938             cfg->config.serialData.dataOrder = kSAI_DataMSB; /* MSB transfer first */
939         }
940         SAI_TransferTxSetConfigSDMA(handle->sai, &rtm->saiHandle, &cfg->config);
941         /* set bit clock */
942         SAI_TxSetBitClockRate(handle->sai, cfg->mclkConfig.mclkHz, paramRtm->srate, bitWidth, channels);
943     }
944 #if SRTM_SAI_CONFIG_Rx_Enabled
945     else
946     {
947         cfg->config.channelMask = 1U << cfg->dataLine1;
948         SAI_TransferRxSetConfigSDMA(handle->sai, &rtm->saiHandle, &cfg->config);
949         /* set bit clock */
950         SAI_RxSetBitClockRate(handle->sai, cfg->mclkConfig.mclkHz, paramRtm->srate, bitWidth, channels);
951     }
952 #endif
953 }
954 
955 /* Currently only 1 audio instance is adequate, so index is just ignored */
SRTM_SaiSdmaAdapter_Open(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)956 static srtm_status_t SRTM_SaiSdmaAdapter_Open(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
957 {
958     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
959 #if SRTM_SAI_CONFIG_Rx_Enabled
960     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
961     srtm_sai_sdma_config_t *thisCfg = dir == SRTM_AudioDirTx ? &handle->txConfig : &handle->rxConfig;
962 #else
963     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
964     srtm_sai_sdma_config_t *thisCfg    = &handle->txConfig;
965 #endif
966 
967     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
968 
969     /* Record the index */
970     handle->index = index;
971 
972     if (rtm->state != SRTM_AudioStateClosed)
973     {
974         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
975                            rtm->state);
976         return SRTM_Status_InvalidState;
977     }
978 
979     rtm->state    = SRTM_AudioStateOpened;
980     rtm->freeRun  = true;
981     rtm->paramSet = false;
982 
983     if (thisCfg->extendConfig.audioMclkConf != NULL)
984     {
985         thisCfg->extendConfig.audioMclkConf(handle->sai, &thisCfg->mclkConfig);
986     }
987 
988     return SRTM_Status_Success;
989 }
990 
SRTM_SaiSdmaAdapter_Start(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)991 static srtm_status_t SRTM_SaiSdmaAdapter_Start(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
992 {
993     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
994     srtm_sai_sdma_runtime_t thisRtm;
995     srtm_sai_sdma_config_t *thisCfg;
996 #if SRTM_SAI_CONFIG_Rx_Enabled
997     srtm_sai_sdma_runtime_t otherRtm;
998     srtm_sai_sdma_config_t *otherCfg;
999     srtm_audio_dir_t otherDir;
1000 #endif
1001 
1002 #if SRTM_SAI_CONFIG_Rx_Enabled
1003     uint32_t *threshold = dir == SRTM_AudioDirTx ? &handle->txConfig.threshold : &handle->rxConfig.threshold;
1004     uint32_t *guardTime = dir == SRTM_AudioDirTx ? &handle->txConfig.guardTime : &handle->rxConfig.guardTime;
1005 #else
1006     uint32_t *threshold                = &handle->txConfig.threshold;
1007     uint32_t *guardTime                = &handle->txConfig.guardTime;
1008 #endif
1009 
1010     uint8_t channelNum;
1011     uint32_t guardPeroids;
1012 
1013     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1014 #if SRTM_SAI_CONFIG_Rx_Enabled
1015     if (dir == SRTM_AudioDirTx)
1016     {
1017 #endif
1018         thisRtm = &handle->txRtm;
1019         thisCfg = &handle->txConfig;
1020 #if SRTM_SAI_CONFIG_Rx_Enabled
1021         otherRtm = &handle->rxRtm;
1022         otherCfg = &handle->rxConfig;
1023         otherDir = SRTM_AudioDirRx;
1024     }
1025     else
1026     {
1027         thisRtm  = &handle->rxRtm;
1028         otherRtm = &handle->txRtm;
1029         thisCfg  = &handle->rxConfig;
1030         otherCfg = &handle->txConfig;
1031         otherDir = SRTM_AudioDirTx;
1032     }
1033 #endif
1034 
1035     if (thisRtm->state != SRTM_AudioStateOpened)
1036     {
1037         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
1038                            thisRtm->state);
1039         return SRTM_Status_InvalidState;
1040     }
1041 
1042     if (thisRtm->periods == 0U)
1043     {
1044         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s valid buffer not set!\r\n", __func__, saiDirection[dir]);
1045         return SRTM_Status_InvalidState;
1046     }
1047 
1048     if (thisRtm->srate == 0U)
1049     {
1050         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s valid format param not set!\r\n", __func__,
1051                            saiDirection[dir]);
1052         return SRTM_Status_InvalidState;
1053     }
1054 
1055     /* Init the audio device. */
1056 #if SRTM_SAI_CONFIG_Rx_Enabled
1057     if (otherRtm->state != SRTM_AudioStateStarted)
1058     {
1059 #endif
1060         SAI_Init(handle->sai);
1061         if (thisCfg->extendConfig.audioDevInit != NULL)
1062         {
1063             thisCfg->extendConfig.audioDevInit(true);
1064         }
1065 #if SRTM_SAI_CONFIG_Rx_Enabled
1066     }
1067 
1068     if (otherCfg->config.syncMode == kSAI_ModeSync)
1069     {
1070         /* The other direction in sync mode, it will initialize both directions. */
1071         if (otherRtm->state != SRTM_AudioStateStarted)
1072         {
1073             /* Only when the other direction is not started, we can initialize, else the device setting is reused. */
1074             SRTM_SaiSdmaAdapter_InitSAI(handle, dir);
1075             /* Use our own format. */
1076             SRTM_SaiSdmaAdapter_SetFormat(handle, dir);
1077         }
1078     }
1079     else
1080 #endif
1081     {
1082         /* The other direction has dedicated clock, it will not initialize this direction.
1083            Do initialization by ourselves. */
1084         SRTM_SaiSdmaAdapter_InitSAI(handle, dir);
1085         /* Use our own format. */
1086         SRTM_SaiSdmaAdapter_SetFormat(handle, dir);
1087 
1088 #if SRTM_SAI_CONFIG_Rx_Enabled
1089         if ((thisCfg->config.syncMode == kSAI_ModeSync) && (otherRtm->state != SRTM_AudioStateStarted))
1090         {
1091             /* This direction in sync mode and the other not started, need to initialize the other direction. */
1092             SRTM_SaiSdmaAdapter_InitSAI(handle, otherDir);
1093             /* Set other direction format to ours. */
1094             SRTM_SaiSdmaAdapter_SetFormat(handle, otherDir);
1095         }
1096 #endif
1097     }
1098 
1099     if (thisRtm->streamMode == kSAI_Stereo)
1100     {
1101         channelNum = 2U;
1102     }
1103     else
1104     {
1105         channelNum = 1U;
1106     }
1107     /* Caculate the threshold based on the guardTime.*/
1108     if (*guardTime != 0U)
1109     {
1110         guardPeroids = (uint32_t)(((uint64_t)thisRtm->srate * thisRtm->bitWidth * channelNum * (*guardTime) +
1111                                    (uint64_t)thisRtm->periodSize * 8U * 1000U - 1U) /
1112                                   ((uint64_t)thisRtm->periodSize * 8U * 1000U));
1113         /* If the guardPeroids calculated based on the guardTime is larger than the threshold value ,
1114          * then the threshold should be enlarged to make sure there is enough time for A core resume and fill the DDR
1115          * buffer.
1116          */
1117         if (guardPeroids > *threshold)
1118         {
1119             *threshold = guardPeroids > thisRtm->periods ? thisRtm->periods : guardPeroids;
1120         }
1121     }
1122     thisRtm->state = SRTM_AudioStateStarted;
1123     /* Reset buffer index */
1124     thisRtm->bufRtm.loadIdx    = thisRtm->bufRtm.chaseIdx;
1125     thisRtm->bufRtm.offset     = 0;
1126     thisRtm->finishedBufOffset = thisRtm->bufRtm.chaseIdx * thisRtm->periodSize;
1127     if (thisRtm->freeRun)
1128     {
1129         /* Assume buffer full in free run */
1130         thisRtm->readyIdx = thisRtm->bufRtm.leadIdx;
1131     }
1132 #if SRTM_SAI_CONFIG_SupportLocalBuf
1133     SRTM_SaiSdmaAdaptor_ResetLocalBuf(thisRtm, dir);
1134 #endif
1135     SRTM_SaiSdmaAdapter_AddNewPeriods(thisRtm, thisRtm->readyIdx);
1136     SRTM_SaiSdmaAdapter_Transfer(handle, dir);
1137 
1138     return SRTM_Status_Success;
1139 }
1140 
SRTM_SaiSdmaAdapter_End(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,bool stop)1141 static srtm_status_t SRTM_SaiSdmaAdapter_End(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index, bool stop)
1142 {
1143     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1144     srtm_sai_sdma_runtime_t thisRtm;
1145     srtm_sai_sdma_config_t *thisCfg;
1146 #if SRTM_SAI_CONFIG_Rx_Enabled
1147     srtm_sai_sdma_runtime_t otherRtm;
1148     srtm_sai_sdma_config_t *otherCfg;
1149     srtm_audio_dir_t otherDir;
1150 #endif
1151 
1152     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1153 
1154 #if SRTM_SAI_CONFIG_Rx_Enabled
1155     if (dir == SRTM_AudioDirTx)
1156     {
1157 #endif
1158         thisRtm = &handle->txRtm;
1159         thisCfg = &handle->txConfig;
1160 #if SRTM_SAI_CONFIG_Rx_Enabled
1161         otherRtm = &handle->rxRtm;
1162         otherCfg = &handle->rxConfig;
1163         otherDir = SRTM_AudioDirRx;
1164     }
1165     else
1166     {
1167         thisRtm  = &handle->rxRtm;
1168         otherRtm = &handle->txRtm;
1169         thisCfg  = &handle->rxConfig;
1170         otherCfg = &handle->txConfig;
1171         otherDir = SRTM_AudioDirTx;
1172     }
1173 #endif
1174 
1175     if (thisRtm->state == SRTM_AudioStateClosed)
1176     {
1177         /* Stop may called when audio service reset. */
1178         return SRTM_Status_Success;
1179     }
1180 
1181     if (thisRtm->state == SRTM_AudioStateStarted)
1182     {
1183         if (dir == SRTM_AudioDirTx)
1184         {
1185             SAI_TransferTerminateSendSDMA(handle->sai, &thisRtm->saiHandle);
1186         }
1187 #if SRTM_SAI_CONFIG_Rx_Enabled
1188         else
1189         {
1190             SAI_TransferTerminateReceiveSDMA(handle->sai, &thisRtm->saiHandle);
1191         }
1192 #endif
1193 
1194 #if SRTM_SAI_CONFIG_Rx_Enabled
1195         if (otherCfg->config.syncMode == kSAI_ModeSync)
1196         {
1197             /* The other direction in sync mode, it will deinitialize this direction when it's stopped. */
1198             if (otherRtm->state != SRTM_AudioStateStarted)
1199             {
1200 #endif
1201                 /* The other direction not started, we can deinitialize this direction. */
1202                 SRTM_SaiSdmaAdapter_DeinitSAI(handle, dir);
1203 #if SRTM_SAI_CONFIG_Rx_Enabled
1204             }
1205         }
1206         else
1207         {
1208             /* The other direction has dedicated clock, its stop will not affect this direction.
1209                Do deinitialization by ourselves. */
1210             SRTM_SaiSdmaAdapter_DeinitSAI(handle, dir);
1211             if ((thisCfg->config.syncMode == kSAI_ModeSync) && (otherRtm->state != SRTM_AudioStateStarted))
1212             {
1213                 /* This direction in sync mode and the other not started, need to deinitialize the other direction. */
1214                 SRTM_SaiSdmaAdapter_DeinitSAI(handle, otherDir);
1215             }
1216         }
1217 
1218         if (otherRtm->state != SRTM_AudioStateStarted)
1219         {
1220 #endif
1221             /* If both Tx and Rx are not running, we can deinitialize this SAI instance. */
1222             SAI_Deinit(handle->sai);
1223             /* Deinit audio device. */
1224             if (thisCfg->extendConfig.audioDevInit != NULL)
1225             {
1226                 thisCfg->extendConfig.audioDevInit(false);
1227             }
1228 #if SRTM_SAI_CONFIG_Rx_Enabled
1229         }
1230 #endif
1231     }
1232 
1233     thisCfg->threshold               = 1U;
1234     thisRtm->bufRtm.remainingPeriods = thisRtm->bufRtm.remainingLoadPeriods = 0U;
1235     if (!thisRtm->freeRun)
1236     {
1237         thisRtm->readyIdx = thisRtm->bufRtm.leadIdx;
1238         thisRtm->freeRun  = stop; /* Reset to freeRun if stopped. */
1239     }
1240     thisRtm->bufRtm.leadIdx = thisRtm->bufRtm.chaseIdx;
1241 
1242     thisRtm->state = SRTM_AudioStateOpened;
1243 
1244     return SRTM_Status_Success;
1245 }
1246 
SRTM_SaiSdmaAdapter_Stop(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1247 static srtm_status_t SRTM_SaiSdmaAdapter_Stop(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1248 {
1249     return SRTM_SaiSdmaAdapter_End(adapter, dir, index, true);
1250 }
1251 
SRTM_SaiSdmaAdapter_Close(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1252 static srtm_status_t SRTM_SaiSdmaAdapter_Close(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1253 {
1254     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1255 #if SRTM_SAI_CONFIG_Rx_Enabled
1256     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
1257 #else
1258     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
1259 #endif
1260 
1261     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1262 
1263     if (rtm->state == SRTM_AudioStateClosed)
1264     {
1265         /* Stop may called when audio service reset. */
1266         return SRTM_Status_Success;
1267     }
1268 
1269     if (rtm->state != SRTM_AudioStateOpened)
1270     {
1271         (void)SRTM_SaiSdmaAdapter_End(adapter, dir, index, true);
1272     }
1273 
1274     rtm->state    = SRTM_AudioStateClosed;
1275     rtm->paramSet = false;
1276 
1277     return SRTM_Status_Success;
1278 }
1279 
SRTM_SaiSdmaAdapter_Pause(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1280 static srtm_status_t SRTM_SaiSdmaAdapter_Pause(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1281 {
1282     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1283 
1284     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1285 
1286     if (dir == SRTM_AudioDirTx)
1287     {
1288         /* Disable request */
1289         SAI_TxEnableDMA(handle->sai, kSAI_FIFORequestDMAEnable, false);
1290         /* Disable SAI */
1291         SAI_TxEnable(handle->sai, false);
1292     }
1293 #if SRTM_SAI_CONFIG_Rx_Enabled
1294     else
1295     {
1296         /* Disable request*/
1297         SAI_RxEnableDMA(handle->sai, kSAI_FIFORequestDMAEnable, false);
1298         /* Disable SAI*/
1299         SAI_RxEnable(handle->sai, false);
1300     }
1301 #endif
1302 
1303     return SRTM_Status_Success;
1304 }
1305 
SRTM_SaiSdmaAdapter_Restart(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1306 static srtm_status_t SRTM_SaiSdmaAdapter_Restart(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1307 {
1308     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1309 
1310     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1311 
1312     if (dir == SRTM_AudioDirTx)
1313     {
1314         /* Enable request */
1315         SAI_TxEnableDMA(handle->sai, kSAI_FIFORequestDMAEnable, true);
1316         /* Enable SAI */
1317         SAI_TxEnable(handle->sai, true);
1318     }
1319 #if SRTM_SAI_CONFIG_Rx_Enabled
1320     else
1321     {
1322         /* Enable request */
1323         SAI_RxEnableDMA(handle->sai, kSAI_FIFORequestDMAEnable, true);
1324         /* Enable SAI */
1325         SAI_RxEnable(handle->sai, true);
1326     }
1327 #endif
1328 
1329     return SRTM_Status_Success;
1330 }
1331 
SRTM_SaiSdmaAdapter_SetParam(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,uint8_t format,uint8_t channels,uint32_t srate)1332 static srtm_status_t SRTM_SaiSdmaAdapter_SetParam(
1333     srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index, uint8_t format, uint8_t channels, uint32_t srate)
1334 {
1335     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1336 #if SRTM_SAI_CONFIG_Rx_Enabled
1337     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
1338 #else
1339     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
1340 #endif
1341     uint32_t bytePerSample;
1342 
1343     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d. fmt %d, ch %d, srate %d\r\n", __func__, saiDirection[dir],
1344                        index, format, channels, srate);
1345 
1346     if (rtm->state != SRTM_AudioStateOpened)
1347     {
1348         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
1349                            rtm->state);
1350         return SRTM_Status_InvalidState;
1351     }
1352 
1353     if ((format > (uint8_t)SRTM_Audio_DSD32bits) || (channels >= ARRAY_SIZE(saiChannelMap)))
1354     {
1355         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s unsupported format or channels %d, %d!\r\n", __func__,
1356                            saiDirection[dir], format, channels);
1357         return SRTM_Status_InvalidParameter;
1358     }
1359 
1360     SRTM_SaiSdmaAdapter_ReconfigSAI(adapter, dir, format, srate);
1361 
1362     if (format >= (uint8_t)SRTM_Audio_DSD8bits)
1363     {
1364         /* DSD mode always two channels and get the sample frequcy to caculate the BCLK in the sai driver. */
1365         rtm->srate    = srate / 2U;
1366         rtm->bitWidth = saiFormatMap[format - 45U].bitwidth;
1367     }
1368     else if (format <= (uint8_t)SRTM_Audio_Stereo32Bits)
1369     {
1370         rtm->srate    = srate;
1371         rtm->bitWidth = saiFormatMap[format].bitwidth;
1372     }
1373     else
1374     {
1375         return SRTM_Status_Error;
1376     }
1377 
1378     /* Caluate the max bytes can be done by each SDMA transfer. */
1379     bytePerSample    = ((uint32_t)(rtm->bitWidth) >> 3U) * (channels != 0U ? (uint32_t)channels : 1UL);
1380     rtm->maxXferSize = (uint32_t)SRTM_SDMA_MAX_TRANSFER_SIZE / bytePerSample * bytePerSample;
1381 
1382     rtm->format     = format;
1383     rtm->streamMode = saiChannelMap[channels];
1384     rtm->paramSet   = true;
1385 
1386     return SRTM_Status_Success;
1387 }
1388 
SRTM_SaiSdmaAdapter_SetBuf(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,uint8_t * bufAddr,uint32_t bufSize,uint32_t periodSize,uint32_t periodIdx)1389 static srtm_status_t SRTM_SaiSdmaAdapter_SetBuf(srtm_sai_adapter_t adapter,
1390                                                 srtm_audio_dir_t dir,
1391                                                 uint8_t index,
1392                                                 uint8_t *bufAddr,
1393                                                 uint32_t bufSize,
1394                                                 uint32_t periodSize,
1395                                                 uint32_t periodIdx)
1396 {
1397     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1398 #if SRTM_SAI_CONFIG_Rx_Enabled
1399     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
1400 #else
1401     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
1402 #endif
1403     srtm_sai_sdma_buf_runtime_t bufRtm = &rtm->bufRtm;
1404 
1405     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d. buf [0x%x, 0x%x]; prd size 0x%x, idx %d\r\n", __func__,
1406                        saiDirection[dir], index, bufAddr, bufSize, periodSize, periodIdx);
1407     if (rtm->state != SRTM_AudioStateOpened)
1408     {
1409         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
1410                            rtm->state);
1411         return SRTM_Status_InvalidState;
1412     }
1413 
1414     rtm->bufAddr    = bufAddr;
1415     rtm->periodSize = periodSize;
1416     rtm->periods    = (periodSize != 0U) ? bufSize / periodSize : 0U;
1417     rtm->bufSize    = periodSize * rtm->periods;
1418 
1419     rtm->countsPerPeriod = (rtm->periodSize + rtm->maxXferSize - 1U) / rtm->maxXferSize;
1420     rtm->curXferIdx      = 1U;
1421 
1422     assert(periodIdx < rtm->periods);
1423 
1424     bufRtm->chaseIdx = periodIdx;
1425     bufRtm->leadIdx  = periodIdx;
1426 
1427     bufRtm->remainingPeriods = bufRtm->remainingLoadPeriods = 0U;
1428 
1429     return SRTM_Status_Success;
1430 }
1431 
SRTM_SaiSdmaAdapter_Suspend(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1432 static srtm_status_t SRTM_SaiSdmaAdapter_Suspend(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1433 {
1434     srtm_status_t status           = SRTM_Status_Success;
1435     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1436     srtm_sai_sdma_runtime_t thisRtm;
1437     srtm_sai_sdma_config_t *thisCfg;
1438 
1439     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1440 #if SRTM_SAI_CONFIG_Rx_Enabled
1441     if (dir == SRTM_AudioDirTx)
1442     {
1443 #endif
1444         thisRtm = &handle->txRtm;
1445         thisCfg = &handle->txConfig;
1446 #if SRTM_SAI_CONFIG_Rx_Enabled
1447     }
1448     else
1449     {
1450         thisRtm = &handle->rxRtm;
1451         thisCfg = &handle->rxConfig;
1452     }
1453 #endif
1454 
1455     if ((thisRtm->state == SRTM_AudioStateStarted) && thisCfg->stopOnSuspend)
1456     {
1457         thisRtm->stoppedOnSuspend = true;
1458         status                    = SRTM_SaiSdmaAdapter_End(adapter, dir, index, false);
1459     }
1460 
1461     thisRtm->suspendState = SRTM_Suspended;
1462 
1463     return status;
1464 }
1465 
1466 #if SRTM_SAI_CONFIG_Rx_Enabled
SRTM_SaiSdmaAdapter_HostWakeProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)1467 static void SRTM_SaiSdmaAdapter_HostWakeProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
1468 {
1469     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)param1;
1470     srtm_sai_sdma_runtime_t rtm    = &handle->rxRtm;
1471     srtm_sai_adapter_t adapter     = &handle->adapter;
1472 
1473     /* Notify application if the host is waken by other reason. */
1474     if ((rtm->suspendState == SRTM_NotSuspended) && (rtm->dataCallback != NULL))
1475     {
1476         rtm->dataCallback(adapter, (void *)(0), 0U, rtm->dataCallbackParam);
1477     }
1478 }
1479 #endif
1480 
SRTM_SaiSdmaAdapter_Resume(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1481 static srtm_status_t SRTM_SaiSdmaAdapter_Resume(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1482 {
1483     srtm_status_t status           = SRTM_Status_Success;
1484     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1485     srtm_sai_sdma_runtime_t thisRtm;
1486 #if SRTM_SAI_CONFIG_Rx_Enabled
1487     srtm_procedure_t proc;
1488 #endif
1489 
1490     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1491 
1492 #if SRTM_SAI_CONFIG_Rx_Enabled
1493     if (dir == SRTM_AudioDirTx)
1494     {
1495         thisRtm = &handle->txRtm;
1496     }
1497     else
1498     {
1499         thisRtm = &handle->rxRtm;
1500     }
1501 #else
1502     thisRtm                            = &handle->txRtm;
1503 #endif
1504 
1505     if (thisRtm->stoppedOnSuspend)
1506     {
1507         thisRtm->stoppedOnSuspend = false;
1508         status                    = SRTM_SaiSdmaAdapter_Start(adapter, dir, index);
1509     }
1510 
1511     thisRtm->suspendState = SRTM_NotSuspended;
1512 
1513 #if SRTM_SAI_CONFIG_Rx_Enabled
1514     if ((dir == SRTM_AudioDirRx) && (thisRtm->dataCallback != NULL))
1515     {
1516         /* Call the dataCallback to notify the host is wakeup. */
1517         proc = SRTM_Procedure_Create(SRTM_SaiSdmaAdapter_HostWakeProc, handle, NULL);
1518         if ((adapter->service != NULL) && (proc != NULL))
1519         {
1520             (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
1521         }
1522         else
1523         {
1524             SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: : proc busy!\r\n", __func__);
1525         }
1526     }
1527 #endif
1528     return status;
1529 }
1530 
SRTM_SaiSdmaAdapter_GetBufOffset(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,uint32_t * pOffset)1531 static srtm_status_t SRTM_SaiSdmaAdapter_GetBufOffset(srtm_sai_adapter_t adapter,
1532                                                       srtm_audio_dir_t dir,
1533                                                       uint8_t index,
1534                                                       uint32_t *pOffset)
1535 {
1536     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1537 #if SRTM_SAI_CONFIG_Rx_Enabled
1538     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
1539 #else
1540     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
1541 #endif
1542 
1543     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1544 
1545     *pOffset = rtm->finishedBufOffset;
1546 
1547     return SRTM_Status_Success;
1548 }
1549 
SRTM_SaiSdmaAdapter_PeriodReady(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,uint32_t periodIdx)1550 static srtm_status_t SRTM_SaiSdmaAdapter_PeriodReady(srtm_sai_adapter_t adapter,
1551                                                      srtm_audio_dir_t dir,
1552                                                      uint8_t index,
1553                                                      uint32_t periodIdx)
1554 {
1555     srtm_status_t status           = SRTM_Status_Success;
1556     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1557 #if SRTM_SAI_CONFIG_Rx_Enabled
1558     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
1559 #else
1560     srtm_sai_sdma_runtime_t rtm        = &handle->txRtm;
1561 #endif
1562 
1563     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d - period %d\r\n", __func__, saiDirection[dir], index,
1564                        periodIdx);
1565 
1566     if (rtm->state == SRTM_AudioStateStarted)
1567     {
1568         if (dir == SRTM_AudioDirTx)
1569         {
1570             SRTM_SaiSdmaAdapter_AddNewPeriods(rtm, periodIdx);
1571             /* Add buffer to DMA scatter-gather list if there's remaining buffer to send.
1572                Needed in case buffer xflow */
1573             SRTM_SaiSdmaAdapter_Transfer(handle, dir);
1574         }
1575     }
1576     else
1577     {
1578         /* The RX is alwasy free run. */
1579         if (dir == SRTM_AudioDirTx)
1580         {
1581             rtm->freeRun = false;
1582         }
1583         rtm->readyIdx = periodIdx;
1584     }
1585 
1586     return status;
1587 }
1588 
SRTM_SaiSdmaAdapter_Create(I2S_Type * sai,SDMAARM_Type * dma,srtm_sai_sdma_config_t * txConfig,srtm_sai_sdma_config_t * rxConfig)1589 srtm_sai_adapter_t SRTM_SaiSdmaAdapter_Create(I2S_Type *sai,
1590                                               SDMAARM_Type *dma,
1591                                               srtm_sai_sdma_config_t *txConfig,
1592                                               srtm_sai_sdma_config_t *rxConfig)
1593 {
1594     srtm_sai_sdma_adapter_t handle;
1595 
1596     assert((sai != NULL) && (dma != NULL));
1597 
1598     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1599 
1600     handle = (srtm_sai_sdma_adapter_t)SRTM_Heap_Malloc(sizeof(struct _srtm_sai_sdma_adapter));
1601     assert(handle != NULL);
1602     (void)memset(handle, 0, sizeof(struct _srtm_sai_sdma_adapter));
1603 
1604     handle->sai = sai;
1605     handle->dma = dma;
1606     if (txConfig != NULL)
1607     {
1608         (void)memcpy(&handle->txConfig, txConfig, sizeof(srtm_sai_sdma_config_t));
1609         handle->txRtm.proc = SRTM_Procedure_Create(SRTM_SaiSdmaAdapter_TxTransferProc, handle, NULL);
1610         assert(handle->txRtm.proc != NULL);
1611         SRTM_Message_SetFreeFunc(handle->txRtm.proc, SRTM_SaiSdmaAdapter_RecycleTxMessage, handle);
1612     }
1613 #if SRTM_SAI_CONFIG_Rx_Enabled
1614     if (rxConfig != NULL)
1615     {
1616         (void)memcpy(&handle->rxConfig, rxConfig, sizeof(srtm_sai_sdma_config_t));
1617         handle->rxRtm.proc = SRTM_Procedure_Create(SRTM_SaiSdmaAdapter_RxTransferProc, handle, NULL);
1618         assert(handle->rxRtm.proc != NULL);
1619         SRTM_Message_SetFreeFunc(handle->rxRtm.proc, SRTM_SaiSdmaAdapter_RecycleRxMessage, handle);
1620     }
1621 #endif
1622 
1623     /* Adapter interfaces. */
1624     handle->adapter.open         = SRTM_SaiSdmaAdapter_Open;
1625     handle->adapter.start        = SRTM_SaiSdmaAdapter_Start;
1626     handle->adapter.pause        = SRTM_SaiSdmaAdapter_Pause;
1627     handle->adapter.restart      = SRTM_SaiSdmaAdapter_Restart;
1628     handle->adapter.stop         = SRTM_SaiSdmaAdapter_Stop;
1629     handle->adapter.close        = SRTM_SaiSdmaAdapter_Close;
1630     handle->adapter.setParam     = SRTM_SaiSdmaAdapter_SetParam;
1631     handle->adapter.setBuf       = SRTM_SaiSdmaAdapter_SetBuf;
1632     handle->adapter.suspend      = SRTM_SaiSdmaAdapter_Suspend;
1633     handle->adapter.resume       = SRTM_SaiSdmaAdapter_Resume;
1634     handle->adapter.getBufOffset = SRTM_SaiSdmaAdapter_GetBufOffset;
1635     handle->adapter.periodReady  = SRTM_SaiSdmaAdapter_PeriodReady;
1636 
1637     return &handle->adapter;
1638 }
1639 
SRTM_SaiSdmaAdapter_Destroy(srtm_sai_adapter_t adapter)1640 void SRTM_SaiSdmaAdapter_Destroy(srtm_sai_adapter_t adapter)
1641 {
1642     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1643 
1644     assert(adapter != NULL);
1645 
1646     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1647 
1648     if (handle->txRtm.proc != NULL)
1649     {
1650         SRTM_Message_SetFreeFunc(handle->txRtm.proc, NULL, NULL);
1651         SRTM_Procedure_Destroy(handle->txRtm.proc);
1652     }
1653 
1654 #if SRTM_SAI_CONFIG_Rx_Enabled
1655     if (handle->rxRtm.proc != NULL)
1656     {
1657         SRTM_Message_SetFreeFunc(handle->rxRtm.proc, NULL, NULL);
1658         SRTM_Procedure_Destroy(handle->rxRtm.proc);
1659     }
1660 #endif
1661 
1662     SRTM_Heap_Free(handle);
1663 }
1664 
1665 #if SRTM_SAI_CONFIG_SupportLocalBuf
SRTM_SaiSdmaAdapter_SetLocalBuf(srtm_sai_adapter_t adapter,srtm_sai_sdma_local_buf_t * localBuf,srtm_audio_dir_t dir)1666 static inline void SRTM_SaiSdmaAdapter_SetLocalBuf(srtm_sai_adapter_t adapter,
1667                                                    srtm_sai_sdma_local_buf_t *localBuf,
1668                                                    srtm_audio_dir_t dir)
1669 {
1670     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1671 #if SRTM_SAI_CONFIG_Rx_Enabled
1672     srtm_sai_sdma_runtime_t rtm = dir == SRTM_AudioDirTx ? &handle->txRtm : &handle->rxRtm;
1673 #else
1674     srtm_sai_sdma_runtime_t rtm = &handle->txRtm;
1675 #endif
1676 
1677     assert(adapter != NULL);
1678 
1679     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1680 
1681     if (localBuf != NULL)
1682     {
1683         assert(localBuf->periods <= SRTM_SAI_SDMA_MAX_LOCAL_BUF_PERIODS);
1684         (void)memcpy(&rtm->localBuf, localBuf, sizeof(srtm_sai_sdma_local_buf_t));
1685     }
1686     else
1687     {
1688         rtm->localBuf.buf = NULL;
1689     }
1690 }
1691 
SRTM_SaiSdmaAdapter_SetTxLocalBuf(srtm_sai_adapter_t adapter,srtm_sai_sdma_local_buf_t * localBuf)1692 void SRTM_SaiSdmaAdapter_SetTxLocalBuf(srtm_sai_adapter_t adapter, srtm_sai_sdma_local_buf_t *localBuf)
1693 {
1694     SRTM_SaiSdmaAdapter_SetLocalBuf(adapter, localBuf, SRTM_AudioDirTx);
1695 }
1696 
1697 #if SRTM_SAI_CONFIG_Rx_Enabled
SRTM_SaiSdmaAdapter_SetRxLocalBuf(srtm_sai_adapter_t adapter,srtm_sai_sdma_local_buf_t * localBuf)1698 void SRTM_SaiSdmaAdapter_SetRxLocalBuf(srtm_sai_adapter_t adapter, srtm_sai_sdma_local_buf_t *localBuf)
1699 {
1700     SRTM_SaiSdmaAdapter_SetLocalBuf(adapter, localBuf, SRTM_AudioDirRx);
1701 }
1702 #endif /* SRTM_SAI_CONFIG_Rx_Enabled */
1703 #endif /* SRTM_SAI_CONFIG_SupportLocalBuf */
1704 
1705 #if SRTM_SAI_CONFIG_Rx_Enabled
SRTM_SaiSdmaAdapter_SetDataHandlerOnHostSuspend(srtm_sai_adapter_t adapter,srtm_sai_sdma_data_callback_t cb,void * param)1706 void SRTM_SaiSdmaAdapter_SetDataHandlerOnHostSuspend(srtm_sai_adapter_t adapter,
1707                                                      srtm_sai_sdma_data_callback_t cb,
1708                                                      void *param)
1709 {
1710     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1711 
1712     assert(adapter != NULL);
1713 
1714     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1715 
1716     handle->rxRtm.dataCallback      = cb;
1717     handle->rxRtm.dataCallbackParam = param;
1718 }
1719 
SRTM_SaiSdmaAdapter_ResumeHostProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)1720 static void SRTM_SaiSdmaAdapter_ResumeHostProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
1721 {
1722     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)param1;
1723 #if SRTM_SAI_CONFIG_SupportLocalBuf
1724     srtm_sai_sdma_runtime_t rtm = &handle->rxRtm;
1725 #endif
1726 
1727     if (handle->rxRtm.suspendState == SRTM_Suspended)
1728     {
1729         handle->rxRtm.suspendState = SRTM_WakingUp;
1730         /* Copy the audio data from the local buffer to the remote in case the local buffer is overwritten during host
1731          * wakeup. */
1732 #if SRTM_SAI_CONFIG_SupportLocalBuf
1733         if (rtm->localBuf.buf != NULL)
1734         {
1735             if (rtm->localRtm.bufRtm.remainingPeriods < rtm->localBuf.periods)
1736             {
1737                 SRTM_SaiSdmaAdapter_RxCopyData(handle);
1738             }
1739         }
1740 #endif
1741     }
1742 }
1743 
SRTM_SaiSdmaAdapter_ResumeHost(srtm_sai_adapter_t adapter)1744 void SRTM_SaiSdmaAdapter_ResumeHost(srtm_sai_adapter_t adapter)
1745 {
1746     srtm_sai_sdma_adapter_t handle = (srtm_sai_sdma_adapter_t)(void *)adapter;
1747     srtm_procedure_t proc;
1748 
1749     assert(adapter != NULL);
1750 
1751     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1752 
1753     proc = SRTM_Procedure_Create(SRTM_SaiSdmaAdapter_ResumeHostProc, handle, NULL);
1754     if ((adapter->service != NULL) && (proc != NULL))
1755     {
1756         (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
1757     }
1758 }
1759 #endif
1760