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