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