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