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