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