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