1 /*
2 * Copyright 2021-2022 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <string.h>
9
10 #include "srtm_pdm_sdma_adapter.h"
11 #include "srtm_heap.h"
12 #if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET)
13 #include "fsl_memory.h"
14 #endif
15 #include "fsl_pdm.h"
16 #include "fsl_pdm_sdma.h"
17 #include "srtm_dispatcher.h"
18 #include "srtm_message.h"
19 #include "srtm_message_struct.h"
20 #include "srtm_service_struct.h"
21
22 /*******************************************************************************
23 * Definitions
24 ******************************************************************************/
25
26 #define SRTM_SDMA_MAX_TRANSFER_SIZE 0xFFFFU
27
28 typedef enum _srtm_pdm_sdma_suspend_state
29 {
30 SRTM_NotSuspended,
31 SRTM_Suspended,
32 SRTM_WakingUp,
33 } srtm_pdm_sdma_suspend_state;
34
35 typedef struct _srtm_pdm_sdma_buf_runtime
36 {
37 uint32_t leadIdx; /* ready period index for playback or recording. */
38 uint32_t chaseIdx; /* consumed period index for 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, non-zero value means current period is not finished. */
43 } *srtm_pdm_sdma_buf_runtime_t;
44
45 struct _srtm_pdm_sdma_local_runtime
46 {
47 uint32_t periodSize;
48 struct _srtm_pdm_sdma_buf_runtime bufRtm;
49 };
50
51 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
52 struct _srtm_pdm_ext_buf_sdma_handle
53 {
54 sdma_handle_t rDmaHandle; /* Extra buffer read DMA handle. */
55 sdma_handle_t wDmaHandle; /* Extra buffer write DMA handle. */
56 sdma_context_data_t rDmaCtx; /* Extra buffer read DMA context. */
57 sdma_context_data_t wDmaCtx; /* Extra buffer write DMA context. */
58 sdma_buffer_descriptor_t bd[2U]; /* SDMA buffer descriptor used for extra buffer write. */
59 };
60 #endif
61
62 typedef struct _srtm_pdm_sdma_runtime
63 {
64 srtm_audio_state_t state;
65 pdm_sdma_handle_t pdmHandle;
66 uint8_t bitWidth;
67 uint8_t format;
68 uint8_t pdmChannels; /* Enabled PDM channels. */
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 countsPerPeriod; /* The DMA transfer count for each period. If the periodSize is larger than maxXferSize,
78 the period will be splited into multiple transmissions. */
79 uint32_t curXferIdx; /* The current transmission index in countsPerPeriod. */
80 srtm_procedure_t proc; /* proc message to trigger DMA transfer in SRTM context. */
81 struct _srtm_pdm_sdma_buf_runtime bufRtm; /* buffer provided by audio client. */
82 srtm_pdm_sdma_local_buf_t localBuf;
83 struct _srtm_pdm_sdma_local_runtime localRtm; /* buffer set by application. */
84 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
85 srtm_pdm_sdma_ext_buf_t extBuf;
86 struct _srtm_pdm_sdma_local_runtime extBufRtm; /* Extra buffer set by application. */
87 bool extBufPumpRunning; /* Extra buffer pump is running. */
88 #endif
89 bool freeRun; /* flag to indicate that no periodReady will be sent by audio client. */
90 bool stoppedOnSuspend;
91 bool paramSet;
92 uint32_t finishedBufOffset; /* offset from bufAddr where the data transfer has completed. */
93 srtm_pdm_sdma_suspend_state suspendState; /* service state in client suspend. */
94 srtm_pdm_sdma_data_callback_t dataCallback; /* Callback function to provide data when client is suspend */
95 void *dataCallbackParam; /* Callback function argument to be passed back to application */
96 #if SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
97 srtm_pdm_sdma_hwvad_callback_t hwvadCallback; /* Callback function which is called when voice detacted by HWVAD. */
98 void *hwvadCallbackParam; /* Callback function argument to be passed back to application */
99 #endif
100 } *srtm_pdm_sdma_runtime_t;
101
102 /* SAI SDMA adapter */
103 typedef struct _srtm_pdm_sdma_adapter
104 {
105 struct _srtm_sai_adapter adapter;
106 uint32_t index;
107
108 PDM_Type *pdm;
109 SDMAARM_Type *dma;
110 srtm_pdm_sdma_config_t rxConfig;
111 sdma_handle_t rxDmaHandle;
112 struct _srtm_pdm_sdma_runtime rxRtm;
113 #if SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
114 srtm_pdm_hwvad_config_t hwvadConfig;
115 #endif
116 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
117 struct _srtm_pdm_ext_buf_sdma_handle extBufDmaHandle; /* Extra buffer read/write DMA handle. */
118 #endif
119 } *srtm_pdm_sdma_adapter_t;
120 /*******************************************************************************
121 * Prototypes
122 ******************************************************************************/
123 #if SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
124 static void SRTM_PdmSdmaAdapter_HwvadCallback(status_t status, void *userData);
125 #endif
126 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
127 static void SRTM_PdmSdmaAdapter_PumpExtraBuf(srtm_pdm_sdma_adapter_t handle);
128 static void SRTM_PdmSdmaAdapter_ExtPeriodCopyAndNotifyProc(srtm_dispatcher_t dispatcher, void *param1, void *param2);
129 #endif
130 static void SRTM_PdmSdmaAdapter_CopyData(srtm_pdm_sdma_adapter_t handle);
131 static void SRTM_PdmSdmaAdapter_AddNewPeriods(srtm_pdm_sdma_runtime_t rtm, uint32_t periodIdx);
132 /*******************************************************************************
133 * Variables
134 ******************************************************************************/
135 #ifdef SRTM_DEBUG_MESSAGE_FUNC
136 static const char *saiDirection[] = {"Rx", "Tx"};
137 #endif
138
139 /*******************************************************************************
140 * Code
141 ******************************************************************************/
SRTM_PdmSdmaAdapter_GetAudioServiceState(srtm_sai_adapter_t adapter,srtm_audio_state_t * pRxState)142 void SRTM_PdmSdmaAdapter_GetAudioServiceState(srtm_sai_adapter_t adapter, srtm_audio_state_t *pRxState)
143 {
144 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
145
146 *pRxState = handle->rxRtm.state;
147 }
148
SRTM_PdmSdmaAdapter_LocalBufferUpdate(uint32_t * dest,uint32_t * src,uint32_t count)149 static void SRTM_PdmSdmaAdapter_LocalBufferUpdate(uint32_t *dest, uint32_t *src, uint32_t count)
150 {
151 while (count != 0U)
152 {
153 *dest = *src;
154 dest++;
155 src++;
156 count--;
157 }
158 }
159
SRTM_PdmSdmaAdapter_RecycleRxMessage(srtm_message_t msg,void * param)160 static void SRTM_PdmSdmaAdapter_RecycleRxMessage(srtm_message_t msg, void *param)
161 {
162 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param;
163 assert(handle->rxRtm.proc == NULL);
164
165 handle->rxRtm.proc = msg;
166 }
167
SRTM_PdmSdmaAdaptor_ResetLocalBuf(srtm_pdm_sdma_runtime_t rtm)168 static void SRTM_PdmSdmaAdaptor_ResetLocalBuf(srtm_pdm_sdma_runtime_t rtm)
169 {
170 uint8_t bytePerSample;
171
172 if (rtm->localBuf.buf != NULL)
173 {
174 (void)memset(&rtm->localRtm.bufRtm, 0, sizeof(struct _srtm_pdm_sdma_buf_runtime));
175
176 bytePerSample = (rtm->bitWidth >> 3U) * rtm->pdmChannels;
177
178 if (rtm->localBuf.samplesPerPeriod == 0U)
179 {
180 /* default: use numbers of periods defined for this buffer */
181 if ((bytePerSample % SRTM_PDM_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT) != 0U)
182 {
183 bytePerSample *= SRTM_PDM_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT;
184 }
185 rtm->localRtm.periodSize = rtm->localBuf.bufSize / rtm->localBuf.periods;
186 rtm->localRtm.periodSize = rtm->localRtm.periodSize / bytePerSample * bytePerSample;
187 }
188 else
189 {
190 /* Compute number of periods in the buffer based on its size and the size of each period
191 * which depends on the number of samples and the size of each sample */
192 rtm->localRtm.periodSize = bytePerSample * rtm->localBuf.samplesPerPeriod;
193 rtm->localBuf.periods = rtm->localBuf.bufSize / rtm->localRtm.periodSize;
194 }
195
196 rtm->localRtm.bufRtm.remainingLoadPeriods = rtm->localBuf.periods;
197 rtm->localRtm.bufRtm.remainingPeriods = rtm->localBuf.periods;
198 }
199 }
200
SRTM_PdmSdmaAdapter_PeriodReceiveSDMA(srtm_pdm_sdma_adapter_t handle)201 static status_t SRTM_PdmSdmaAdapter_PeriodReceiveSDMA(srtm_pdm_sdma_adapter_t handle)
202 {
203 status_t status = kStatus_Success;
204 uint32_t count;
205 pdm_transfer_t xfer;
206 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
207 srtm_pdm_sdma_buf_runtime_t bufRtm;
208
209 #if SRTM_PDM_SDMA_ADAPTER_FORCE_LOCAL_AND_EXTRA_BUFFERS
210 if (rtm->localBuf.buf == NULL)
211 {
212 /* Compiler can remove all code below supporting case where local buf isn't used. */
213 return kStatus_Fail;
214 }
215 #endif
216
217 if (rtm->localBuf.buf != NULL)
218 {
219 bufRtm = &rtm->localRtm.bufRtm;
220
221 xfer.dataSize = rtm->localRtm.periodSize;
222 xfer.data = rtm->localBuf.buf + bufRtm->loadIdx * rtm->localRtm.periodSize;
223 status = PDM_TransferReceiveSDMA(handle->pdm, &rtm->pdmHandle, &xfer);
224
225 if (status != kStatus_Success)
226 {
227 /* Audio queue full */
228 return status;
229 }
230 bufRtm->loadIdx = (bufRtm->loadIdx + 1U) % rtm->localBuf.periods;
231 bufRtm->remainingLoadPeriods--;
232 }
233 else
234 {
235 bufRtm = &rtm->bufRtm;
236
237 count = rtm->periodSize - bufRtm->offset;
238 while (count > rtm->maxXferSize) /* Split the period into several DMA transfer. */
239 {
240 xfer.dataSize = rtm->maxXferSize;
241 xfer.data = rtm->bufAddr + bufRtm->loadIdx * rtm->periodSize + bufRtm->offset;
242 status = PDM_TransferReceiveSDMA(handle->pdm, &rtm->pdmHandle, &xfer);
243 if (status == kStatus_Success)
244 {
245 count = count - rtm->maxXferSize;
246 bufRtm->offset += rtm->maxXferSize;
247 }
248 else
249 {
250 return status;
251 }
252 }
253 if (count > 0U)
254 {
255 xfer.dataSize = count;
256 xfer.data = rtm->bufAddr + bufRtm->loadIdx * rtm->periodSize + bufRtm->offset;
257 status = PDM_TransferReceiveSDMA(handle->pdm, &rtm->pdmHandle, &xfer);
258 if (status != kStatus_Success)
259 {
260 return status;
261 }
262 bufRtm->offset = 0; /* All the transfers for the one period is done. */
263 }
264
265 if (bufRtm->offset == 0U) /* The whole period is finished. */
266 {
267 bufRtm->loadIdx = (bufRtm->loadIdx + 1U) % rtm->periods;
268 bufRtm->remainingLoadPeriods--;
269 }
270 }
271
272 return kStatus_Success;
273 }
274
SRTM_PdmSdmaAdapter_DmaTransfer(srtm_pdm_sdma_adapter_t handle)275 static void SRTM_PdmSdmaAdapter_DmaTransfer(srtm_pdm_sdma_adapter_t handle)
276 {
277 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
278 srtm_pdm_sdma_buf_runtime_t bufRtm = (rtm->localBuf.buf != NULL) ? &rtm->localRtm.bufRtm : &rtm->bufRtm;
279 uint32_t i;
280 status_t status;
281 uint32_t num;
282
283 num = bufRtm->remainingLoadPeriods;
284
285 for (i = 0U; i < num; i++)
286 {
287 status = SRTM_PdmSdmaAdapter_PeriodReceiveSDMA(handle);
288
289 if (status != kStatus_Success)
290 {
291 /* Audio queue full. */
292 break;
293 }
294 }
295 }
296
SRTM_PdmSdmaAdapter_PeriodCopyAndNotify(srtm_pdm_sdma_adapter_t handle)297 static void SRTM_PdmSdmaAdapter_PeriodCopyAndNotify(srtm_pdm_sdma_adapter_t handle)
298 {
299 srtm_sai_adapter_t adapter = &handle->adapter;
300 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
301 uint32_t srcSize, dstSize, size;
302 srtm_pdm_sdma_buf_runtime_t srcRtm, dstRtm;
303
304 uint8_t *src, *dst;
305 uint32_t primask;
306
307 srcRtm = &rtm->localRtm.bufRtm;
308 dstRtm = &rtm->bufRtm;
309
310 if ((srcRtm->remainingPeriods != rtm->localBuf.periods) && (dstRtm->remainingPeriods != 0U))
311 {
312 src = rtm->localBuf.buf + srcRtm->leadIdx * rtm->localRtm.periodSize;
313 dst = rtm->bufAddr + dstRtm->chaseIdx * rtm->periodSize;
314 srcSize = rtm->localRtm.periodSize - srcRtm->offset;
315 dstSize = rtm->periodSize - dstRtm->offset;
316 size = MIN(srcSize, dstSize);
317 SRTM_PdmSdmaAdapter_LocalBufferUpdate((uint32_t *)(void *)(dst + dstRtm->offset),
318 (uint32_t *)(void *)(src + srcRtm->offset), size / 4U);
319
320 srcRtm->offset += size;
321 dstRtm->offset += size;
322 if (srcRtm->offset == rtm->localRtm.periodSize) /* whole local buffer copied */
323 {
324 srcRtm->leadIdx = (srcRtm->leadIdx + 1U) % rtm->localBuf.periods;
325 srcRtm->offset = 0U;
326 primask = DisableGlobalIRQ();
327 srcRtm->remainingPeriods++;
328 srcRtm->remainingLoadPeriods++;
329 EnableGlobalIRQ(primask);
330 }
331
332 if (dstRtm->offset == rtm->periodSize)
333 {
334 /* One period is filled. */
335 dstRtm->chaseIdx = (dstRtm->chaseIdx + 1U) % rtm->periods;
336 dstRtm->remainingPeriods--; /* Now one of the remote buffer has been consumed. Assume the ready period is
337 consumed by host immediately. */
338 dstRtm->remainingLoadPeriods--; /* Unused. */
339 rtm->finishedBufOffset = dstRtm->chaseIdx * rtm->periodSize;
340 dstRtm->offset = 0U;
341
342 /* Rx is always freeRun, we assume filled period is consumed immediately. */
343 SRTM_PdmSdmaAdapter_AddNewPeriods(rtm, dstRtm->chaseIdx);
344
345 if ((adapter->service != NULL) && (adapter->periodDone != NULL))
346 {
347 (void)adapter->periodDone(adapter->service, SRTM_AudioDirRx, handle->index, rtm->bufRtm.chaseIdx);
348 }
349 }
350 }
351 }
352
SRTM_PdmSdmaAdapter_DataCopyProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)353 static void SRTM_PdmSdmaAdapter_DataCopyProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
354 {
355 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param1;
356
357 /* More data need to be copied. */
358 SRTM_PdmSdmaAdapter_CopyData(handle);
359 }
360
SRTM_PdmSdmaAdapter_CopyData(srtm_pdm_sdma_adapter_t handle)361 static void SRTM_PdmSdmaAdapter_CopyData(srtm_pdm_sdma_adapter_t handle)
362 {
363 srtm_sai_adapter_t adapter = &handle->adapter;
364
365 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
366 srtm_pdm_sdma_buf_runtime_t srcRtm, dstRtm;
367 srcRtm = &rtm->localRtm.bufRtm;
368 dstRtm = &rtm->bufRtm;
369 srtm_procedure_t proc;
370
371 SRTM_PdmSdmaAdapter_PeriodCopyAndNotify(handle);
372
373 /* More data need to be copied. */
374 if ((srcRtm->remainingPeriods != rtm->localBuf.periods) && (dstRtm->remainingPeriods != 0U))
375 {
376 proc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_DataCopyProc, handle, NULL);
377 if ((adapter->service != NULL) && (proc != NULL))
378 {
379 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
380 }
381 }
382 }
383
SRTM_PdmSdmaAdapter_AddNewPeriods(srtm_pdm_sdma_runtime_t rtm,uint32_t periodIdx)384 static void SRTM_PdmSdmaAdapter_AddNewPeriods(srtm_pdm_sdma_runtime_t rtm, uint32_t periodIdx)
385 {
386 srtm_pdm_sdma_buf_runtime_t bufRtm = &rtm->bufRtm;
387 uint32_t newPeriods;
388 uint32_t primask;
389
390 assert(periodIdx < rtm->periods);
391
392 newPeriods = (periodIdx + rtm->periods - bufRtm->leadIdx) % rtm->periods;
393 if (newPeriods == 0U) /* In case buffer is empty and filled all. */
394 {
395 newPeriods = rtm->periods;
396 }
397
398 bufRtm->leadIdx = periodIdx;
399 primask = DisableGlobalIRQ();
400 bufRtm->remainingPeriods += newPeriods;
401 EnableGlobalIRQ(primask);
402 bufRtm->remainingLoadPeriods += newPeriods;
403 }
404
SRTM_PdmSdmaAdapter_Transfer(srtm_pdm_sdma_adapter_t handle)405 static void SRTM_PdmSdmaAdapter_Transfer(srtm_pdm_sdma_adapter_t handle)
406 {
407 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
408
409 /* Trigger DMA if having more data to playback/record. */
410 SRTM_PdmSdmaAdapter_DmaTransfer(handle);
411
412 if (rtm->localBuf.buf != NULL)
413 {
414 if ((rtm->localRtm.bufRtm.remainingPeriods < rtm->localBuf.periods) &&
415 ((rtm->suspendState != SRTM_Suspended) || (rtm->dataCallback == NULL)))
416 {
417 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
418 if (!rtm->extBufPumpRunning)
419 #endif
420 {
421 SRTM_PdmSdmaAdapter_CopyData(handle);
422 }
423 }
424 }
425
426 if (rtm->freeRun && (rtm->bufRtm.remainingPeriods < rtm->periods))
427 {
428 /* In free run, we assume consumed period is filled immediately. */
429 SRTM_PdmSdmaAdapter_AddNewPeriods(rtm, rtm->bufRtm.chaseIdx);
430 }
431 }
432
SRTM_PdmSdmaAdapter_RxTransferProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)433 static void SRTM_PdmSdmaAdapter_RxTransferProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
434 {
435 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param1;
436 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
437 srtm_sai_adapter_t adapter = &handle->adapter;
438 uint32_t chaseIdx = (uint32_t)(uint8_t *)param2;
439 uint8_t *bufAddr;
440 uint32_t bufSize;
441
442 if ((rtm->suspendState == SRTM_Suspended) && (rtm->dataCallback != NULL) && (chaseIdx != UINT32_MAX))
443 {
444 if (rtm->localBuf.buf != NULL)
445 {
446 bufAddr = rtm->localBuf.buf + chaseIdx * rtm->localRtm.periodSize;
447 bufSize = rtm->localRtm.periodSize;
448 }
449 else
450 {
451 bufAddr = rtm->bufAddr + chaseIdx * rtm->periodSize;
452 bufSize = rtm->periodSize;
453 }
454
455 rtm->dataCallback(adapter, (void *)(bufAddr), bufSize, rtm->dataCallbackParam);
456 }
457
458 if (rtm->state == SRTM_AudioStateStarted)
459 {
460 /* Trigger DMA if having more buffer to record. */
461 SRTM_PdmSdmaAdapter_Transfer(handle);
462 }
463 }
464
465 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
SRTM_PdmSdmaAdaptor_ResetExtBuf(srtm_pdm_sdma_runtime_t rtm)466 static void SRTM_PdmSdmaAdaptor_ResetExtBuf(srtm_pdm_sdma_runtime_t rtm)
467 {
468 uint32_t periods = 0U;
469
470 if ((rtm->extBuf.buf != NULL) && (rtm->localBuf.buf != NULL))
471 {
472 (void)memset(&rtm->extBufRtm.bufRtm, 0, sizeof(struct _srtm_pdm_sdma_buf_runtime));
473 periods =
474 rtm->localBuf.periods - rtm->localBuf.threshold; /* Local buffer periods for each ext buffer period. */
475 rtm->extBufRtm.periodSize = rtm->localRtm.periodSize * periods;
476 assert(rtm->extBufRtm.periodSize <= SRTM_SDMA_MAX_TRANSFER_SIZE);
477 rtm->extBuf.periods = rtm->extBuf.bufSize / rtm->extBufRtm.periodSize;
478 rtm->extBufRtm.bufRtm.remainingPeriods = rtm->extBuf.periods;
479
480 if (rtm->extBuf.periods == 0U)
481 {
482 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "The extra buffer is too small.\r\n");
483 }
484 }
485 }
486
SRTM_PdmSdmaAdapter_LocalBufFullDMACb(sdma_handle_t * dmahandle,void * param,bool transferDone,uint32_t tcds)487 static void SRTM_PdmSdmaAdapter_LocalBufFullDMACb(sdma_handle_t *dmahandle,
488 void *param,
489 bool transferDone,
490 uint32_t tcds)
491 {
492 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param;
493 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
494 uint32_t periodsPerExt =
495 rtm->localBuf.periods - rtm->localBuf.threshold; /* The number of localBuf periods for each extra buffer. */
496
497 if (transferDone)
498 {
499 rtm->extBufRtm.bufRtm.remainingPeriods--; /* A period is filled. */
500 rtm->extBufRtm.bufRtm.chaseIdx =
501 (rtm->extBufRtm.bufRtm.chaseIdx + 1U) % rtm->extBuf.periods; /* Move the write pointer. */
502
503 if (rtm->extBufRtm.bufRtm.chaseIdx == rtm->extBufRtm.bufRtm.leadIdx) /* Extra buffer overwrite. */
504 {
505 rtm->extBufRtm.bufRtm.leadIdx = (rtm->extBufRtm.bufRtm.leadIdx + 1U) % rtm->extBuf.periods;
506 rtm->extBufRtm.bufRtm.remainingPeriods++;
507 }
508
509 rtm->localRtm.bufRtm.leadIdx = (rtm->localRtm.bufRtm.leadIdx + periodsPerExt) % rtm->localBuf.periods;
510 rtm->localRtm.bufRtm.remainingLoadPeriods = rtm->localRtm.bufRtm.remainingLoadPeriods + periodsPerExt;
511 rtm->localRtm.bufRtm.remainingPeriods = rtm->localRtm.bufRtm.remainingPeriods + periodsPerExt;
512 }
513 }
514
SRTM_PdmSdmaAdapter_LocalBufFullProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)515 static void SRTM_PdmSdmaAdapter_LocalBufFullProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
516 {
517 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param1;
518 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
519 sdma_transfer_config_t transferConfig = {0U};
520 bool lastBd = true;
521 uint32_t periods = 0U;
522 uint8_t *src, *dst;
523 uint32_t size;
524
525 uint32_t periodsPerExt =
526 rtm->localBuf.periods - rtm->localBuf.threshold; /* local buffer periods number for each extra period */
527
528 periods = rtm->localBuf.periods - rtm->localRtm.bufRtm.leadIdx;
529 src = rtm->localBuf.buf + rtm->localRtm.bufRtm.leadIdx * rtm->localRtm.periodSize;
530 dst = rtm->extBuf.buf + rtm->extBufRtm.bufRtm.chaseIdx * rtm->extBufRtm.periodSize;
531
532 if (rtm->extBufPumpRunning)
533 {
534 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "Warn:Local buffer full during extra buffer pump.\r\n");
535 }
536
537 SDMA_CreateHandle(&handle->extBufDmaHandle.wDmaHandle, handle->dma, rtm->extBuf.bufWriteDmaChannel,
538 &handle->extBufDmaHandle.wDmaCtx);
539 SDMA_SetCallback(&handle->extBufDmaHandle.wDmaHandle, SRTM_PdmSdmaAdapter_LocalBufFullDMACb, handle);
540 SDMA_InstallBDMemory(&handle->extBufDmaHandle.wDmaHandle, handle->extBufDmaHandle.bd, 2U);
541
542 if (periods < periodsPerExt) /* The localbuf is a ringbuffer, there are more periods need to be copied. */
543 {
544 lastBd = false;
545 size = periods * rtm->localRtm.periodSize;
546
547 SDMA_ConfigBufferDescriptor(&handle->extBufDmaHandle.bd[0], (uint32_t)src, (uint32_t)dst,
548 kSDMA_TransferSize4Bytes, size, lastBd, lastBd, false, kSDMA_MemoryToMemory);
549 SDMA_PrepareTransfer(&transferConfig, (uint32_t)src, (uint32_t)dst, sizeof(uint32_t), sizeof(uint32_t),
550 sizeof(uint32_t), size, 0U, kSDMA_PeripheralTypeMemory, kSDMA_MemoryToMemory);
551
552 src = rtm->localBuf.buf; /* Return back to buffer start.*/
553 dst = dst + size;
554
555 size = (periodsPerExt - periods) * rtm->localRtm.periodSize;
556
557 SDMA_ConfigBufferDescriptor(&handle->extBufDmaHandle.bd[1], (uint32_t)src, (uint32_t)dst,
558 kSDMA_TransferSize4Bytes, size, true, true, false, kSDMA_MemoryToMemory);
559 }
560 else
561 {
562 lastBd = true;
563 size = periodsPerExt * rtm->localRtm.periodSize;
564
565 SDMA_ConfigBufferDescriptor(&handle->extBufDmaHandle.bd[0], (uint32_t)src, (uint32_t)dst,
566 kSDMA_TransferSize4Bytes, size, lastBd, lastBd, false, kSDMA_MemoryToMemory);
567 SDMA_PrepareTransfer(&transferConfig, (uint32_t)src, (uint32_t)dst, sizeof(uint32_t), sizeof(uint32_t),
568 sizeof(uint32_t), size, 0U, kSDMA_PeripheralTypeMemory, kSDMA_MemoryToMemory);
569 }
570
571 SDMA_SubmitTransfer(&handle->extBufDmaHandle.wDmaHandle, &transferConfig);
572 SDMA_SetChannelPriority(handle->dma, rtm->extBuf.bufWriteDmaChannel, rtm->extBuf.channelPriority);
573 SDMA_StartTransfer(&handle->extBufDmaHandle.wDmaHandle);
574 }
575 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER */
576
SRTM_PdmSdmaRxCallback(PDM_Type * sai,pdm_sdma_handle_t * sdmaHandle,status_t status,void * userData)577 static void SRTM_PdmSdmaRxCallback(PDM_Type *sai, pdm_sdma_handle_t *sdmaHandle, status_t status, void *userData)
578 {
579 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)userData;
580 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
581 srtm_sai_adapter_t adapter = &handle->adapter;
582 uint32_t chaseIdx = UINT32_MAX;
583 bool periodDone = false;
584 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
585 srtm_procedure_t extProc;
586 #endif
587
588 #if SRTM_PDM_SDMA_ADAPTER_FORCE_LOCAL_AND_EXTRA_BUFFERS
589 if (rtm->localBuf.buf == NULL)
590 {
591 /* Compiler can remove all code below supporting case where local buf isn't used. */
592 return;
593 }
594 #endif
595
596 /* When localBuf is used, the period size should not exceed the max size supported by one DMA tranfer. */
597 if (rtm->localBuf.buf != NULL)
598 {
599 rtm->localRtm.bufRtm.remainingPeriods--; /* One of the local period is filled */
600
601 chaseIdx = rtm->localRtm.bufRtm.chaseIdx; /* For callback */
602 rtm->localRtm.bufRtm.chaseIdx = (rtm->localRtm.bufRtm.chaseIdx + 1U) % rtm->localBuf.periods;
603
604 /* Rx is always freeRun, assume filled period is consumed immediately. */
605 periodDone = true;
606 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
607 /* If extra 2nd buffer is used. Copy the data from localbuffer to the extra buffer. During the extra buffer
608 * pump, the local buffer may full again. */
609 if (rtm->extBuf.buf != NULL)
610 {
611 if (((rtm->localRtm.bufRtm.chaseIdx + rtm->localBuf.threshold) % rtm->localBuf.periods) ==
612 rtm->localRtm.bufRtm.leadIdx) /* Local RX buffer is almost full, backup the audio data. */
613 {
614 extProc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_LocalBufFullProc, handle, NULL);
615 if ((adapter->service != NULL) && (extProc != NULL))
616 {
617 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, extProc);
618 }
619 }
620 }
621 else
622 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER */
623 {
624 if ((rtm->suspendState == SRTM_Suspended) && (rtm->dataCallback != NULL))
625 {
626 if (((rtm->localRtm.bufRtm.chaseIdx + rtm->localBuf.threshold) % rtm->localBuf.periods) ==
627 rtm->localRtm.bufRtm.leadIdx) /* Local RX buffer is full. Allow overwrite. */
628 {
629 rtm->localRtm.bufRtm.leadIdx = (rtm->localRtm.bufRtm.leadIdx + 1U) %
630 rtm->localBuf.periods; /* Overwrite will happen, move the leadIdx. */
631 rtm->localRtm.bufRtm.remainingLoadPeriods =
632 (rtm->localRtm.bufRtm.remainingLoadPeriods + 1U) % rtm->localBuf.periods;
633 rtm->localRtm.bufRtm.remainingPeriods =
634 (rtm->localRtm.bufRtm.remainingPeriods + 1U) % rtm->localBuf.periods;
635 }
636 }
637 }
638 }
639 else /* The localBuf is not used, the period size may exceed the max size supported by one DMA tranfer.*/
640 {
641 if (rtm->curXferIdx == rtm->countsPerPeriod) /* All the transfer in a period is done. */
642 {
643 rtm->curXferIdx = 1U;
644 periodDone = true;
645
646 rtm->bufRtm.remainingPeriods--;
647 chaseIdx = rtm->bufRtm.chaseIdx; /* For callback. */
648 rtm->bufRtm.chaseIdx = (rtm->bufRtm.chaseIdx + 1U) % rtm->periods;
649 rtm->finishedBufOffset = rtm->bufRtm.chaseIdx * rtm->periodSize;
650
651 /* Rx is always freeRun, we assume filled period is consumed immediately. */
652 SRTM_PdmSdmaAdapter_AddNewPeriods(rtm, rtm->bufRtm.chaseIdx);
653
654 if ((adapter->service != NULL) && (adapter->periodDone != NULL))
655 {
656 /* Rx is always freeRun */
657 if ((rtm->suspendState != SRTM_Suspended) || (rtm->dataCallback == NULL))
658 {
659 (void)adapter->periodDone(adapter->service, SRTM_AudioDirRx, handle->index, rtm->bufRtm.chaseIdx);
660 }
661 }
662 }
663 else
664 {
665 rtm->curXferIdx++;
666 SRTM_PdmSdmaAdapter_Transfer(handle);
667 }
668 }
669 if (periodDone)
670 {
671 if ((adapter->service != NULL) && (rtm->proc != NULL))
672 {
673 rtm->proc->procMsg.param2 = (void *)(uint8_t *)chaseIdx;
674 /* Add buffer to DMA scatter-gather list if there's remaining buffer to record. */
675 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, rtm->proc);
676 rtm->proc = NULL;
677 }
678 else if (rtm->proc == NULL)
679 {
680 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: proc busy!\r\n", __func__);
681 }
682 else
683 {
684 ; /* Intentional empty */
685 }
686 }
687 }
688
SRTM_PdmSdmaAdapter_InitPDM(srtm_pdm_sdma_adapter_t handle)689 static void SRTM_PdmSdmaAdapter_InitPDM(srtm_pdm_sdma_adapter_t handle)
690 {
691 PDM_Init(handle->pdm, (const pdm_config_t *)(&handle->rxConfig.config));
692
693 SDMA_CreateHandle(&handle->rxDmaHandle, handle->dma, handle->rxConfig.dmaChannel, &handle->rxConfig.rxContext);
694 handle->rxDmaHandle.priority =
695 handle->rxConfig.channelPriority; /* The priority will be set in SDMA_StartTransfer. */
696
697 PDM_TransferCreateHandleSDMA(handle->pdm, &handle->rxRtm.pdmHandle, SRTM_PdmSdmaRxCallback, (void *)handle,
698 &handle->rxDmaHandle, handle->rxConfig.eventSource);
699 }
700
SRTM_PdmSdmaAdapter_SetConfig(srtm_pdm_sdma_adapter_t handle)701 static void SRTM_PdmSdmaAdapter_SetConfig(srtm_pdm_sdma_adapter_t handle)
702 {
703 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
704 uint32_t ch = 0;
705
706 /* There must be a path with parameters configured before start. */
707 assert(handle->rxRtm.paramSet);
708
709 for (ch = 0; ch < rtm->pdmChannels; ch++)
710 {
711 PDM_SetChannelConfigSDMA(handle->pdm, &rtm->pdmHandle, ch, &handle->rxConfig.channelConfig);
712 }
713
714 (void)PDM_SetSampleRateConfig(handle->pdm, handle->rxConfig.pdmSrcClk, rtm->srate);
715
716 PDM_Reset(handle->pdm);
717
718 #if SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
719 if (handle->hwvadConfig.mode == kSRTM_PDM_Hwvad_EnvelopeBasedMode)
720 {
721 PDM_SetHwvadInEnvelopeBasedMode(handle->pdm, &handle->hwvadConfig.hwvadConfig,
722 &handle->hwvadConfig.noiseFilterConfig, &handle->hwvadConfig.zcdConfig,
723 handle->hwvadConfig.signalGain);
724 }
725
726 if (handle->hwvadConfig.mode == kSRTM_PDM_Hwvad_EnergyBasedMode)
727 {
728 PDM_SetHwvadInEnergyBasedMode(handle->pdm, &handle->hwvadConfig.hwvadConfig,
729 &handle->hwvadConfig.noiseFilterConfig, &handle->hwvadConfig.zcdConfig,
730 handle->hwvadConfig.signalGain);
731 }
732
733 if (handle->hwvadConfig.mode != kSRTM_PDM_Hwvad_Disabled) /* Enable the Hwvad IRQ. */
734 {
735 PDM_EnableHwvadInterruptCallback(handle->pdm, SRTM_PdmSdmaAdapter_HwvadCallback, (void *)handle, true);
736 }
737 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_HWVAD */
738 }
739
SRTM_PdmSdmaAdapter_DeinitPDM(srtm_pdm_sdma_adapter_t handle)740 static void SRTM_PdmSdmaAdapter_DeinitPDM(srtm_pdm_sdma_adapter_t handle)
741 {
742 assert(handle != NULL);
743 PDM_Reset(handle->pdm);
744 PDM_Deinit(handle->pdm);
745 }
746
747 /* Currently only 1 audio instance is adequate, so index is just ignored */
SRTM_PdmSdmaAdapter_Open(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)748 static srtm_status_t SRTM_PdmSdmaAdapter_Open(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
749 {
750 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
751 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
752
753 /* Only support RX. */
754 assert(dir == SRTM_AudioDirRx);
755 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
756
757 /* Record the index. */
758 handle->index = index;
759
760 if (rtm->state != SRTM_AudioStateClosed)
761 {
762 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
763 rtm->state);
764 return SRTM_Status_InvalidState;
765 }
766
767 rtm->state = SRTM_AudioStateOpened;
768 rtm->freeRun = true;
769 rtm->paramSet = false;
770
771 return SRTM_Status_Success;
772 }
773
SRTM_PdmSdmaAdapter_Start(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)774 static srtm_status_t SRTM_PdmSdmaAdapter_Start(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
775 {
776 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
777 srtm_pdm_sdma_runtime_t thisRtm = &handle->rxRtm;
778 srtm_pdm_sdma_config_t *thisCfg = &handle->rxConfig;
779
780 assert(dir == SRTM_AudioDirRx);
781
782 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
783
784 if (thisRtm->state != SRTM_AudioStateOpened)
785 {
786 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
787 thisRtm->state);
788 return SRTM_Status_InvalidState;
789 }
790
791 if (thisRtm->periods == 0U)
792 {
793 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s valid buffer not set!\r\n", __func__, saiDirection[dir]);
794 return SRTM_Status_InvalidState;
795 }
796
797 if (thisRtm->srate == 0U)
798 {
799 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s valid format param not set!\r\n", __func__,
800 saiDirection[dir]);
801 return SRTM_Status_InvalidState;
802 }
803
804 /* Init the audio device. */
805 if (thisRtm->state != SRTM_AudioStateStarted)
806 {
807 if (thisCfg->extendConfig.audioDevInit != NULL)
808 {
809 thisCfg->extendConfig.audioDevInit(true);
810 }
811 SRTM_PdmSdmaAdapter_InitPDM(handle);
812 /* Use our own format. */
813 SRTM_PdmSdmaAdapter_SetConfig(handle);
814 }
815
816 thisRtm->state = SRTM_AudioStateStarted;
817 /* Reset buffer index. */
818 thisRtm->bufRtm.loadIdx = thisRtm->bufRtm.chaseIdx;
819 thisRtm->bufRtm.offset = 0;
820 thisRtm->finishedBufOffset = thisRtm->bufRtm.chaseIdx * thisRtm->periodSize;
821 if (thisRtm->freeRun)
822 {
823 /* Assume buffer full in free run. */
824 thisRtm->readyIdx = thisRtm->bufRtm.leadIdx;
825 }
826 SRTM_PdmSdmaAdaptor_ResetLocalBuf(thisRtm);
827 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
828 SRTM_PdmSdmaAdaptor_ResetExtBuf(thisRtm);
829 #endif
830 SRTM_PdmSdmaAdapter_AddNewPeriods(thisRtm, thisRtm->readyIdx);
831 SRTM_PdmSdmaAdapter_Transfer(handle);
832
833 return SRTM_Status_Success;
834 }
835
SRTM_PdmSdmaAdapter_End(srtm_sai_adapter_t adapter,uint8_t index,bool stop)836 static srtm_status_t SRTM_PdmSdmaAdapter_End(srtm_sai_adapter_t adapter, uint8_t index, bool stop)
837 {
838 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
839 srtm_pdm_sdma_runtime_t thisRtm = &handle->rxRtm;
840 srtm_pdm_sdma_config_t *thisCfg = &handle->rxConfig;
841
842 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %d\r\n", __func__, index);
843
844 if (thisRtm->state == SRTM_AudioStateClosed)
845 {
846 /* Stop may called when audio service reset. */
847 return SRTM_Status_Success;
848 }
849
850 if (thisRtm->state == SRTM_AudioStateStarted)
851 {
852 PDM_TransferTerminateReceiveSDMA(handle->pdm, &thisRtm->pdmHandle);
853
854 SRTM_PdmSdmaAdapter_DeinitPDM(handle);
855
856 if (thisCfg->extendConfig.audioDevInit != NULL)
857 {
858 thisCfg->extendConfig.audioDevInit(false);
859 }
860 }
861
862 thisRtm->bufRtm.remainingPeriods = thisRtm->bufRtm.remainingLoadPeriods = 0U;
863 if (!thisRtm->freeRun)
864 {
865 thisRtm->readyIdx = thisRtm->bufRtm.leadIdx;
866 thisRtm->freeRun = stop; /* Reset to freeRun if stopped. */
867 }
868 thisRtm->bufRtm.leadIdx = thisRtm->bufRtm.chaseIdx;
869
870 thisRtm->state = SRTM_AudioStateOpened;
871
872 return SRTM_Status_Success;
873 }
874
SRTM_PdmSdmaAdapter_Stop(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)875 static srtm_status_t SRTM_PdmSdmaAdapter_Stop(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
876 {
877 assert(dir == SRTM_AudioDirRx);
878
879 return SRTM_PdmSdmaAdapter_End(adapter, index, true);
880 }
881
SRTM_PdmSdmaAdapter_Close(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)882 static srtm_status_t SRTM_PdmSdmaAdapter_Close(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
883 {
884 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
885 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
886
887 assert(dir == SRTM_AudioDirRx);
888
889 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
890
891 if (rtm->state == SRTM_AudioStateClosed)
892 {
893 /* Stop may called when audio service reset. */
894 return SRTM_Status_Success;
895 }
896
897 if (rtm->state != SRTM_AudioStateOpened)
898 {
899 (void)SRTM_PdmSdmaAdapter_End(adapter, index, true);
900 }
901
902 rtm->state = SRTM_AudioStateClosed;
903 rtm->paramSet = false;
904
905 return SRTM_Status_Success;
906 }
907
SRTM_PdmSdmaAdapter_Pause(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)908 static srtm_status_t SRTM_PdmSdmaAdapter_Pause(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
909 {
910 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
911
912 assert(dir == SRTM_AudioDirRx);
913
914 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
915 /* Disable request*/
916 PDM_EnableDMA(handle->pdm, false);
917 /* Disable PDM*/
918 PDM_Enable(handle->pdm, false);
919
920 return SRTM_Status_Success;
921 }
922
SRTM_PdmSdmaAdapter_Restart(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)923 static srtm_status_t SRTM_PdmSdmaAdapter_Restart(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
924 {
925 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
926
927 assert(dir == SRTM_AudioDirRx);
928
929 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
930
931 PDM_EnableDMA(handle->pdm, true);
932 PDM_Enable(handle->pdm, true);
933
934 return SRTM_Status_Success;
935 }
936
SRTM_PdmSdmaAdapter_SetParam(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,uint8_t format,uint8_t channels,uint32_t srate)937 static srtm_status_t SRTM_PdmSdmaAdapter_SetParam(
938 srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index, uint8_t format, uint8_t channels, uint32_t srate)
939 {
940 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
941 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
942 srtm_pdm_sdma_config_t *cfg = &handle->rxConfig;
943 uint32_t bytePerSample;
944
945 assert(dir == SRTM_AudioDirRx);
946
947 /* Currently, the format of the MICFIL/PDM IP is fixed. */
948 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d. fmt %d, ch %d, srate %d\r\n", __func__, saiDirection[dir],
949 index, format, channels, srate);
950
951 if (rtm->state != SRTM_AudioStateOpened)
952 {
953 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
954 rtm->state);
955 return SRTM_Status_InvalidState;
956 }
957
958 if (channels == 0U)
959 {
960 channels = 1U; /* To be compatible with SAI Mono channel definition. */
961 }
962 if (channels > (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM)
963 {
964 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s unsupported channels %d, %d!\r\n", __func__,
965 saiDirection[dir], channels);
966 return SRTM_Status_InvalidParameter;
967 }
968
969 if (((rtm->format != format) || (rtm->srate != srate)) && (cfg->extendConfig.audioDevConf != NULL))
970 {
971 handle->rxConfig.pdmSrcClk = cfg->extendConfig.audioDevConf((srtm_audio_format_type_t)format, srate);
972 }
973
974 if (format <= (uint8_t)SRTM_Audio_Stereo32Bits)
975 {
976 rtm->bitWidth = saiFormatMap[format].bitwidth;
977 }
978 else
979 {
980 return SRTM_Status_InvalidParameter;
981 }
982
983 /* Caluate the max bytes can be done by each SDMA transfer. */
984 bytePerSample = ((uint32_t)rtm->bitWidth >> 3U) * channels;
985 rtm->maxXferSize = (uint32_t)SRTM_SDMA_MAX_TRANSFER_SIZE / bytePerSample * bytePerSample;
986
987 rtm->srate = srate;
988 rtm->pdmChannels = channels;
989 rtm->format = format;
990
991 rtm->paramSet = true;
992
993 return SRTM_Status_Success;
994 }
995
SRTM_PdmSdmaAdapter_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)996 static srtm_status_t SRTM_PdmSdmaAdapter_SetBuf(srtm_sai_adapter_t adapter,
997 srtm_audio_dir_t dir,
998 uint8_t index,
999 uint8_t *bufAddr,
1000 uint32_t bufSize,
1001 uint32_t periodSize,
1002 uint32_t periodIdx)
1003 {
1004 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1005 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1006 srtm_pdm_sdma_buf_runtime_t bufRtm = &rtm->bufRtm;
1007
1008 assert(dir == SRTM_AudioDirRx);
1009
1010 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d. buf [0x%x, 0x%x]; prd size 0x%x, idx %d\r\n", __func__,
1011 saiDirection[dir], index, bufAddr, bufSize, periodSize, periodIdx);
1012
1013 if (rtm->state != SRTM_AudioStateOpened)
1014 {
1015 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: %s in wrong state %d!\r\n", __func__, saiDirection[dir],
1016 rtm->state);
1017 return SRTM_Status_InvalidState;
1018 }
1019
1020 /* Check the periodSize. */
1021 if (periodSize % (rtm->bitWidth / 8UL * rtm->pdmChannels) != 0U)
1022 {
1023 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: %s in wrong period size %d!\r\n", __func__, saiDirection[dir],
1024 periodSize);
1025 return SRTM_Status_InvalidParameter;
1026 }
1027
1028 rtm->bufAddr = bufAddr;
1029 rtm->periodSize = periodSize;
1030 rtm->periods = (periodSize != 0U) ? bufSize / periodSize : 0U;
1031 rtm->bufSize = periodSize * rtm->periods;
1032
1033 rtm->countsPerPeriod = (rtm->periodSize + rtm->maxXferSize - 1U) / rtm->maxXferSize;
1034 rtm->curXferIdx = 1U; /* The first transfer. */
1035
1036 assert(periodIdx < rtm->periods);
1037
1038 bufRtm->chaseIdx = periodIdx;
1039 bufRtm->leadIdx = periodIdx;
1040
1041 bufRtm->remainingPeriods = bufRtm->remainingLoadPeriods = 0U;
1042
1043 return SRTM_Status_Success;
1044 }
1045
SRTM_PdmSdmaAdapter_Suspend(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1046 static srtm_status_t SRTM_PdmSdmaAdapter_Suspend(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1047 {
1048 srtm_status_t status = SRTM_Status_Success;
1049 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1050 srtm_pdm_sdma_runtime_t thisRtm = &handle->rxRtm;
1051 srtm_pdm_sdma_config_t *thisCfg = &handle->rxConfig;
1052
1053 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1054
1055 if ((thisRtm->state == SRTM_AudioStateStarted) && thisCfg->stopOnSuspend)
1056 {
1057 thisRtm->stoppedOnSuspend = true;
1058 status = SRTM_PdmSdmaAdapter_End(adapter, index, false);
1059 }
1060
1061 thisRtm->suspendState = SRTM_Suspended;
1062
1063 return status;
1064 }
1065
SRTM_PdmSdmaAdapter_HostWakeProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)1066 static void SRTM_PdmSdmaAdapter_HostWakeProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
1067 {
1068 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param1;
1069 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1070 srtm_sai_adapter_t adapter = &handle->adapter;
1071
1072 /* Notify application if the host is waken by other reason. */
1073 if ((rtm->suspendState == SRTM_NotSuspended) && (rtm->dataCallback != NULL))
1074 {
1075 rtm->dataCallback(adapter, (void *)(0), 0U, rtm->dataCallbackParam);
1076 }
1077 }
1078
SRTM_PdmSdmaAdapter_Resume(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index)1079 static srtm_status_t SRTM_PdmSdmaAdapter_Resume(srtm_sai_adapter_t adapter, srtm_audio_dir_t dir, uint8_t index)
1080 {
1081 srtm_status_t status = SRTM_Status_Success;
1082 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1083 srtm_pdm_sdma_runtime_t thisRtm = &handle->rxRtm;
1084 srtm_procedure_t proc;
1085 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
1086 srtm_procedure_t extProc;
1087 #endif
1088
1089 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1090
1091 if (thisRtm->stoppedOnSuspend)
1092 {
1093 thisRtm->stoppedOnSuspend = false;
1094 status = SRTM_PdmSdmaAdapter_Start(adapter, SRTM_AudioDirRx, index);
1095 }
1096
1097 thisRtm->suspendState = SRTM_NotSuspended;
1098
1099 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
1100 /* In case the remote wake itself. Pump the extra buffer. */
1101 if ((thisRtm->extBuf.buf != NULL) && (!thisRtm->extBufPumpRunning))
1102 {
1103 if (thisRtm->extBufRtm.bufRtm.remainingPeriods < thisRtm->extBuf.periods)
1104 {
1105 /* Pump the audio data in extra buffer and then local buffer to remote. */
1106 extProc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_ExtPeriodCopyAndNotifyProc, handle, NULL);
1107 if ((adapter->service != NULL) && (extProc != NULL))
1108 {
1109 thisRtm->extBufPumpRunning = true;
1110 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, extProc);
1111 }
1112 }
1113 }
1114 #endif
1115
1116 if ((dir == SRTM_AudioDirRx) && (thisRtm->dataCallback != NULL))
1117 {
1118 /* Call the dataCallback to notify the host is wakeup. */
1119 proc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_HostWakeProc, handle, NULL);
1120 if ((adapter->service != NULL) && (proc != NULL))
1121 {
1122 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
1123 }
1124 else
1125 {
1126 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: : proc busy!\r\n", __func__);
1127 }
1128 }
1129
1130 return status;
1131 }
1132
SRTM_PdmSdmaAdapter_SetRxLocalBuf(srtm_sai_adapter_t adapter,srtm_pdm_sdma_local_buf_t * localBuf)1133 void SRTM_PdmSdmaAdapter_SetRxLocalBuf(srtm_sai_adapter_t adapter, srtm_pdm_sdma_local_buf_t *localBuf)
1134 {
1135 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1136 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1137
1138 assert(adapter != NULL);
1139
1140 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1141
1142 if (localBuf != NULL)
1143 {
1144 (void)memcpy(&rtm->localBuf, localBuf, sizeof(srtm_pdm_sdma_local_buf_t));
1145 }
1146 else
1147 {
1148 rtm->localBuf.buf = NULL;
1149 }
1150 }
1151
SRTM_PdmSdmaAdapter_GetBufOffset(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,uint32_t * pOffset)1152 static srtm_status_t SRTM_PdmSdmaAdapter_GetBufOffset(srtm_sai_adapter_t adapter,
1153 srtm_audio_dir_t dir,
1154 uint8_t index,
1155 uint32_t *pOffset)
1156 {
1157 assert(dir == SRTM_AudioDirRx);
1158
1159 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1160 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1161
1162 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d\r\n", __func__, saiDirection[dir], index);
1163
1164 *pOffset = rtm->finishedBufOffset;
1165
1166 return SRTM_Status_Success;
1167 }
1168
SRTM_PdmSdmaAdapter_PeriodReady(srtm_sai_adapter_t adapter,srtm_audio_dir_t dir,uint8_t index,uint32_t periodIdx)1169 static srtm_status_t SRTM_PdmSdmaAdapter_PeriodReady(srtm_sai_adapter_t adapter,
1170 srtm_audio_dir_t dir,
1171 uint8_t index,
1172 uint32_t periodIdx)
1173 {
1174 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1175 srtm_status_t status = SRTM_Status_Success;
1176 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1177
1178 assert(dir == SRTM_AudioDirRx);
1179
1180 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %s%d - period %d\r\n", __func__, saiDirection[dir], index,
1181 periodIdx);
1182
1183 if (rtm->state == SRTM_AudioStateStarted)
1184 {
1185 /* RX is always free run. */
1186 }
1187 else
1188 {
1189 /* RX is always free run. */
1190 rtm->readyIdx = periodIdx;
1191 }
1192
1193 return status;
1194 }
1195
SRTM_PdmSdmaAdapter_Create(PDM_Type * pdm,SDMAARM_Type * dma,srtm_pdm_sdma_config_t * rxConfig)1196 srtm_sai_adapter_t SRTM_PdmSdmaAdapter_Create(PDM_Type *pdm, SDMAARM_Type *dma, srtm_pdm_sdma_config_t *rxConfig)
1197 {
1198 srtm_pdm_sdma_adapter_t handle;
1199
1200 assert((pdm != NULL) && (dma != NULL));
1201
1202 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1203
1204 handle = (srtm_pdm_sdma_adapter_t)SRTM_Heap_Malloc(sizeof(struct _srtm_pdm_sdma_adapter));
1205 assert(handle != NULL);
1206 (void)memset(handle, 0, sizeof(struct _srtm_pdm_sdma_adapter));
1207
1208 handle->pdm = pdm;
1209 handle->dma = dma;
1210
1211 if (rxConfig != NULL)
1212 {
1213 (void)memcpy(&handle->rxConfig, rxConfig, sizeof(srtm_pdm_sdma_config_t));
1214 handle->rxRtm.proc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_RxTransferProc, handle, NULL);
1215 assert(handle->rxRtm.proc != NULL);
1216 SRTM_Message_SetFreeFunc(handle->rxRtm.proc, SRTM_PdmSdmaAdapter_RecycleRxMessage, handle);
1217 }
1218
1219 /* Adapter interfaces. */
1220 handle->adapter.open = SRTM_PdmSdmaAdapter_Open;
1221 handle->adapter.start = SRTM_PdmSdmaAdapter_Start;
1222 handle->adapter.pause = SRTM_PdmSdmaAdapter_Pause;
1223 handle->adapter.restart = SRTM_PdmSdmaAdapter_Restart;
1224 handle->adapter.stop = SRTM_PdmSdmaAdapter_Stop;
1225 handle->adapter.close = SRTM_PdmSdmaAdapter_Close;
1226 handle->adapter.setParam = SRTM_PdmSdmaAdapter_SetParam;
1227 handle->adapter.setBuf = SRTM_PdmSdmaAdapter_SetBuf;
1228 handle->adapter.suspend = SRTM_PdmSdmaAdapter_Suspend;
1229 handle->adapter.resume = SRTM_PdmSdmaAdapter_Resume;
1230 handle->adapter.getBufOffset = SRTM_PdmSdmaAdapter_GetBufOffset;
1231 handle->adapter.periodReady = SRTM_PdmSdmaAdapter_PeriodReady;
1232
1233 return &handle->adapter;
1234 }
1235
SRTM_PdmSdmaAdapter_Destroy(srtm_sai_adapter_t adapter)1236 void SRTM_PdmSdmaAdapter_Destroy(srtm_sai_adapter_t adapter)
1237 {
1238 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1239
1240 assert(adapter != NULL);
1241
1242 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1243
1244 if (handle->rxRtm.proc != NULL)
1245 {
1246 SRTM_Message_SetFreeFunc(handle->rxRtm.proc, NULL, NULL);
1247 SRTM_Procedure_Destroy(handle->rxRtm.proc);
1248 }
1249
1250 SRTM_Heap_Free(handle);
1251 }
1252
SRTM_PdmSdmaAdapter_SetDataHandlerOnHostSuspend(srtm_sai_adapter_t adapter,srtm_pdm_sdma_data_callback_t cb,void * param)1253 void SRTM_PdmSdmaAdapter_SetDataHandlerOnHostSuspend(srtm_sai_adapter_t adapter,
1254 srtm_pdm_sdma_data_callback_t cb,
1255 void *param)
1256 {
1257 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1258
1259 assert(adapter != NULL);
1260
1261 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1262
1263 handle->rxRtm.dataCallback = cb;
1264 handle->rxRtm.dataCallbackParam = param;
1265 }
1266
SRTM_PdmSdmaAdapter_ResumeHostProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)1267 static void SRTM_PdmSdmaAdapter_ResumeHostProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
1268 {
1269 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param1;
1270 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1271
1272 if (handle->rxRtm.suspendState == SRTM_Suspended)
1273 {
1274 handle->rxRtm.suspendState = SRTM_WakingUp;
1275
1276 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
1277 if (rtm->extBuf.buf != NULL)
1278 {
1279 if (rtm->extBufRtm.bufRtm.remainingPeriods < rtm->extBuf.periods)
1280 {
1281 rtm->extBufPumpRunning = true;
1282 /* Pump the audio data in extra buffer and then local buffer to remote. */
1283 SRTM_PdmSdmaAdapter_PumpExtraBuf(handle);
1284 }
1285 }
1286 /* ExtBuf not used, local buffer is used, only copy local buffer. */
1287 else if (rtm->localBuf.buf != NULL)
1288 #else
1289 if (rtm->localBuf.buf != NULL)
1290 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER */
1291 {
1292 if (rtm->localRtm.bufRtm.remainingPeriods < rtm->localBuf.periods)
1293 {
1294 /* Copy the audio data from the local buffer to the remote in case the local buffer is overwritten
1295 * during host wakeup. */
1296 SRTM_PdmSdmaAdapter_CopyData(handle);
1297 }
1298 }
1299 else
1300 {
1301 /* Intentional empty. */
1302 }
1303 }
1304 }
1305
1306 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
SRTM_PdmSdmaAdapter_SetRxExtBuf(srtm_sai_adapter_t adapter,srtm_pdm_sdma_ext_buf_t * extBuf)1307 void SRTM_PdmSdmaAdapter_SetRxExtBuf(srtm_sai_adapter_t adapter, srtm_pdm_sdma_ext_buf_t *extBuf)
1308 {
1309 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1310 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1311
1312 assert(adapter != NULL);
1313 assert(rtm->localBuf.buf != NULL);
1314
1315 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s:[0x%x:0x%x]\r\n", __func__, rtm->extBuf.buf, rtm->extBuf.bufSize);
1316
1317 if (extBuf != NULL)
1318 {
1319 (void)memcpy(&rtm->extBuf, extBuf, sizeof(srtm_pdm_sdma_ext_buf_t));
1320 }
1321 else
1322 {
1323 rtm->extBuf.buf = NULL;
1324 }
1325 }
1326
SRTM_PdmSdmaAdapter_DmaM2MCallback(sdma_handle_t * sdma_handle,void * param,bool transferDone,uint32_t bds)1327 static void SRTM_PdmSdmaAdapter_DmaM2MCallback(sdma_handle_t *sdma_handle, void *param, bool transferDone, uint32_t bds)
1328 {
1329 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param;
1330
1331 srtm_sai_adapter_t adapter = &handle->adapter;
1332 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1333 srtm_pdm_sdma_buf_runtime_t srcRtm, dstRtm;
1334
1335 srtm_procedure_t proc;
1336
1337 srcRtm = &rtm->extBufRtm.bufRtm;
1338 dstRtm = &rtm->bufRtm;
1339
1340 if (transferDone)
1341 {
1342 if (srcRtm->offset == rtm->extBufRtm.periodSize) /* A extra buffer period is copied. */
1343 {
1344 srcRtm->leadIdx = (srcRtm->leadIdx + 1U) % rtm->extBuf.periods;
1345 srcRtm->offset = 0U;
1346 srcRtm->remainingPeriods++;
1347 }
1348
1349 if (dstRtm->offset == rtm->periodSize)
1350 {
1351 /* One period is filled. */
1352 dstRtm->chaseIdx = (dstRtm->chaseIdx + 1U) % rtm->periods;
1353 dstRtm->remainingPeriods--; /* Now one of the remote buffer has been consumed. Assume the ready period is
1354 consumed by host immediately. */
1355 dstRtm->remainingLoadPeriods--; /* Unused. */
1356 rtm->finishedBufOffset = dstRtm->chaseIdx * rtm->periodSize;
1357 dstRtm->offset = 0U;
1358
1359 /* Rx is always freeRun, we assume filled period is consumed immediately. */
1360 SRTM_PdmSdmaAdapter_AddNewPeriods(rtm, dstRtm->chaseIdx);
1361
1362 if ((adapter->service != NULL) && (adapter->periodDone != NULL))
1363 {
1364 (void)adapter->periodDone(adapter->service, SRTM_AudioDirRx, handle->index, rtm->bufRtm.chaseIdx);
1365 }
1366 }
1367
1368 /* Pump more data. */
1369 proc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_ExtPeriodCopyAndNotifyProc, handle, NULL);
1370 if ((adapter->service != NULL) && (proc != NULL))
1371 {
1372 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
1373 }
1374 }
1375 }
1376
SRTM_PdmSdmaAdapter_DmaMemcpy(srtm_pdm_sdma_adapter_t handle,uint32_t * dest,uint32_t * src,uint32_t count)1377 static void SRTM_PdmSdmaAdapter_DmaMemcpy(srtm_pdm_sdma_adapter_t handle, uint32_t *dest, uint32_t *src, uint32_t count)
1378 {
1379 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1380 sdma_transfer_config_t transferConfig = {0U};
1381
1382 SDMA_CreateHandle(&handle->extBufDmaHandle.rDmaHandle, handle->dma, rtm->extBuf.bufReadDmaChannel,
1383 &handle->extBufDmaHandle.rDmaCtx);
1384 SDMA_SetCallback(&handle->extBufDmaHandle.rDmaHandle, SRTM_PdmSdmaAdapter_DmaM2MCallback, handle);
1385
1386 SDMA_PrepareTransfer(&transferConfig, (uint32_t)src, (uint32_t)dest, sizeof(dest[0]), sizeof(dest[0]),
1387 sizeof(src[0]), count, 0, kSDMA_PeripheralTypeMemory, kSDMA_MemoryToMemory);
1388 SDMA_SubmitTransfer(&handle->extBufDmaHandle.rDmaHandle, &transferConfig);
1389 SDMA_SetChannelPriority(handle->dma, rtm->extBuf.bufReadDmaChannel, rtm->extBuf.channelPriority);
1390 SDMA_StartTransfer(&handle->extBufDmaHandle.rDmaHandle);
1391 }
1392
SRTM_PdmSdmaAdapter_ExtPeriodCopyAndNotifyProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)1393 static void SRTM_PdmSdmaAdapter_ExtPeriodCopyAndNotifyProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
1394 {
1395 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param1;
1396 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1397 uint32_t srcSize, dstSize, size;
1398 srtm_pdm_sdma_buf_runtime_t srcRtm, dstRtm;
1399
1400 uint8_t *src, *dst;
1401
1402 srcRtm = &rtm->extBufRtm.bufRtm;
1403 dstRtm = &rtm->bufRtm;
1404
1405 if (rtm->state == SRTM_AudioStateStarted)
1406 {
1407 if ((srcRtm->remainingPeriods != rtm->extBuf.periods) && (dstRtm->remainingPeriods != 0U))
1408 {
1409 src = rtm->extBuf.buf + srcRtm->leadIdx * rtm->extBufRtm.periodSize;
1410 dst = rtm->bufAddr + dstRtm->chaseIdx * rtm->periodSize;
1411 srcSize = rtm->extBufRtm.periodSize - srcRtm->offset;
1412 dstSize = rtm->periodSize - dstRtm->offset;
1413 size = MIN(srcSize, dstSize);
1414
1415 SRTM_PdmSdmaAdapter_DmaMemcpy(handle, (uint32_t *)(void *)(dst + dstRtm->offset),
1416 (uint32_t *)(void *)(src + srcRtm->offset), size);
1417
1418 srcRtm->offset += size;
1419 dstRtm->offset += size;
1420 }
1421 else
1422 {
1423 rtm->extBufPumpRunning = false;
1424 /* Pump local buffer ASAP. */
1425 if (rtm->localBuf.buf != NULL)
1426 {
1427 if (rtm->localRtm.bufRtm.remainingPeriods < rtm->localBuf.periods)
1428 {
1429 SRTM_PdmSdmaAdapter_CopyData(handle);
1430 }
1431 }
1432 }
1433 }
1434 else
1435 {
1436 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s:in wrong state %d during data pump!\r\n", __func__,
1437 rtm->state);
1438 }
1439 }
1440
1441 /* Pump Extra buffer, if no audio data in extra buffer it will start local buffer pump. */
SRTM_PdmSdmaAdapter_PumpExtraBuf(srtm_pdm_sdma_adapter_t handle)1442 static void SRTM_PdmSdmaAdapter_PumpExtraBuf(srtm_pdm_sdma_adapter_t handle)
1443 {
1444 srtm_sai_adapter_t adapter = &handle->adapter;
1445
1446 SRTM_PdmSdmaAdapter_ExtPeriodCopyAndNotifyProc(adapter->service->dispatcher, handle, NULL);
1447 }
1448 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER */
1449
SRTM_PdmSdmaAdapter_ResumeHost(srtm_sai_adapter_t adapter)1450 void SRTM_PdmSdmaAdapter_ResumeHost(srtm_sai_adapter_t adapter)
1451 {
1452 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1453 srtm_procedure_t proc;
1454
1455 assert(adapter != NULL);
1456
1457 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1458
1459 proc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_ResumeHostProc, handle, NULL);
1460 if ((adapter->service != NULL) && (proc != NULL))
1461 {
1462 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
1463 }
1464 }
1465
SRTM_PdmSdmaAdapter_GetDataFormat(srtm_sai_adapter_t adapter)1466 srtm_audio_format_type_t SRTM_PdmSdmaAdapter_GetDataFormat(srtm_sai_adapter_t adapter)
1467 {
1468 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1469 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1470
1471 return (srtm_audio_format_type_t)rtm->format;
1472 }
1473
1474 #if SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
SRTM_PdmSdmaAdapter_HwvadProc(srtm_dispatcher_t dispatcher,void * param1,void * param2)1475 static void SRTM_PdmSdmaAdapter_HwvadProc(srtm_dispatcher_t dispatcher, void *param1, void *param2)
1476 {
1477 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)param1;
1478 srtm_pdm_sdma_runtime_t rtm = &handle->rxRtm;
1479 srtm_sai_adapter_t adapter = &handle->adapter;
1480
1481 if ((rtm->hwvadCallback != NULL) && (rtm->state == SRTM_AudioStateStarted))
1482 {
1483 rtm->hwvadCallback(adapter, rtm->hwvadCallbackParam);
1484 }
1485 }
1486
SRTM_PdmSdmaAdapter_HwvadCallback(status_t status,void * userData)1487 static void SRTM_PdmSdmaAdapter_HwvadCallback(status_t status, void *userData)
1488 {
1489 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)userData;
1490 srtm_sai_adapter_t adapter = &handle->adapter;
1491 srtm_procedure_t proc;
1492
1493 if (status == kStatus_PDM_HWVAD_VoiceDetected)
1494 {
1495 proc = SRTM_Procedure_Create(SRTM_PdmSdmaAdapter_HwvadProc, handle, NULL);
1496 if ((adapter->service != NULL) && (proc != NULL))
1497 {
1498 (void)SRTM_Dispatcher_PostProc(adapter->service->dispatcher, proc);
1499 }
1500 }
1501 }
1502
SRTM_PdmSdmaAdapter_ConfigHwvad(srtm_sai_adapter_t adapter,const srtm_pdm_hwvad_config_t * hwvadConfig,srtm_pdm_sdma_hwvad_callback_t cb,void * param)1503 srtm_status_t SRTM_PdmSdmaAdapter_ConfigHwvad(srtm_sai_adapter_t adapter,
1504 const srtm_pdm_hwvad_config_t *hwvadConfig,
1505 srtm_pdm_sdma_hwvad_callback_t cb,
1506 void *param)
1507 {
1508 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1509 srtm_status_t status = SRTM_Status_Success;
1510
1511 assert(adapter != NULL);
1512 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1513
1514 if (handle->rxRtm.state == SRTM_AudioStateStarted) /* The HWVAD should be configured before start. */
1515 {
1516 status = SRTM_Status_InvalidState;
1517 }
1518 else
1519 {
1520 handle->rxRtm.hwvadCallback = cb;
1521 handle->rxRtm.hwvadCallbackParam = param;
1522
1523 (void)memcpy(&handle->hwvadConfig, hwvadConfig, sizeof(srtm_pdm_hwvad_config_t));
1524 }
1525
1526 return status;
1527 }
1528
SRTM_PdmSdmaAdapter_EnableHwvad(srtm_sai_adapter_t adapter,bool enable)1529 void SRTM_PdmSdmaAdapter_EnableHwvad(srtm_sai_adapter_t adapter, bool enable)
1530 {
1531 srtm_pdm_sdma_adapter_t handle = (srtm_pdm_sdma_adapter_t)(void *)adapter;
1532
1533 assert(adapter != NULL);
1534 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
1535
1536 if (enable)
1537 {
1538 if (handle->rxRtm.state == SRTM_AudioStateStarted)
1539 {
1540 PDM_EnableHwvadInterruptCallback(handle->pdm, SRTM_PdmSdmaAdapter_HwvadCallback, (void *)adapter, true);
1541 }
1542 }
1543 else
1544 {
1545 if (handle->rxRtm.state == SRTM_AudioStateStarted)
1546 {
1547 PDM_EnableHwvadInterruptCallback(handle->pdm, NULL, NULL, false);
1548 }
1549 }
1550 }
1551 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_HWVAD */
1552