1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2017-2020 NXP
4 * All rights reserved.
5 *
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 */
9
10 #include "fsl_spdif_edma.h"
11 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
12 #include "fsl_memory.h"
13 #endif
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.spdif_edma"
18 #endif
19
20 /*******************************************************************************
21 * Definitations
22 ******************************************************************************/
23 /* Used for edma_tcd_t size aligned */
24 #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + sizeof(edma_tcd_t)) & ~(sizeof(edma_tcd_t) - 1U))
25
26 /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
27 typedef struct _spdif_edma_private_handle
28 {
29 SPDIF_Type *base;
30 spdif_edma_handle_t *handle;
31 } spdif_edma_private_handle_t;
32
33 /*!
34 * @brief Used for conversion between `void*` and `uint32_t`.
35 */
36 typedef union pvoid_to_u32
37 {
38 void *pvoid;
39 uint32_t u32;
40 } pvoid_to_u32_t;
41
42 /*! @brief spdif edma transfer state. */
43 enum
44 {
45 kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
46 kSPDIF_Idle, /*!< Transfer is done. */
47 };
48
49 /*<! Private handle only used for internally. */
50 static spdif_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_SPDIF_COUNT][2];
51 static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
52 static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
53
54 /*******************************************************************************
55 * Prototypes
56 ******************************************************************************/
57 /*!
58 * @brief Submit SPDIF tcds to EDMA.
59 *
60 * @param base SPDIF base pointer.
61 */
62 static status_t SPDIF_SubmitTransfer(edma_handle_t *handle,
63 const edma_transfer_config_t *config,
64 uint32_t rightChannel);
65
66 /*!
67 * @brief SPDIF EDMA callback for send.
68 *
69 * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
70 * @param userData Parameter for user callback.
71 * @param done If the DMA transfer finished.
72 * @param tcds The TCD index.
73 */
74 static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
75
76 /*!
77 * @brief SPDIF EDMA callback for receive.
78 *
79 * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
80 * @param userData Parameter for user callback.
81 * @param done If the DMA transfer finished.
82 * @param tcds The TCD index.
83 */
84 static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
85
86 /*******************************************************************************
87 * Code
88 ******************************************************************************/
SPDIF_TxEDMACallback(edma_handle_t * handle,void * userData,bool done,uint32_t tcds)89 static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
90 {
91 spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
92 spdif_edma_handle_t *spdifHandle = privHandle->handle;
93
94 /* If finished a block, call the callback function */
95 (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
96 spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
97 if (spdifHandle->callback != NULL)
98 {
99 (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_TxIdle, spdifHandle->userData);
100 }
101
102 /* If all data finished, just stop the transfer */
103 if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
104 {
105 SPDIF_TransferAbortSendEDMA(privHandle->base, spdifHandle);
106 }
107 }
108
SPDIF_RxEDMACallback(edma_handle_t * handle,void * userData,bool done,uint32_t tcds)109 static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
110 {
111 spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
112 spdif_edma_handle_t *spdifHandle = privHandle->handle;
113
114 /* If finished a block, call the callback function */
115 (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
116 spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
117 if (spdifHandle->callback != NULL)
118 {
119 (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_RxIdle, spdifHandle->userData);
120 }
121
122 /* If all data finished, just stop the transfer */
123 if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
124 {
125 SPDIF_TransferAbortReceiveEDMA(privHandle->base, spdifHandle);
126 }
127 }
128
SPDIF_SubmitTransfer(edma_handle_t * handle,const edma_transfer_config_t * config,uint32_t rightChannel)129 static status_t SPDIF_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config, uint32_t rightChannel)
130 {
131 #if defined(FSL_EDMA_DRIVER_EDMA4) && FSL_EDMA_DRIVER_EDMA4
132 edma_tcd_t *tcdRegs = handle->tcdBase;
133 #else
134 edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
135 #endif
136 uint32_t primask;
137 uint16_t csr;
138 int8_t currentTcd;
139 int8_t previousTcd;
140 int8_t nextTcd;
141 int8_t tcdUsed = handle->tcdUsed;
142 int8_t tcdSize = handle->tcdSize;
143
144 /* Check if tcd pool is full. */
145 primask = DisableGlobalIRQ();
146 if (tcdUsed >= tcdSize)
147 {
148 EnableGlobalIRQ(primask);
149
150 return kStatus_EDMA_QueueFull;
151 }
152 currentTcd = handle->tail;
153 handle->tcdUsed++;
154 /* Calculate index of next TCD */
155 nextTcd = currentTcd + 0x01;
156 if (nextTcd == handle->tcdSize)
157 {
158 nextTcd = 0x00;
159 }
160 /* Advance queue tail index */
161 handle->tail = nextTcd;
162 EnableGlobalIRQ(primask);
163 /* Calculate index of previous TCD */
164 previousTcd = (currentTcd != 0x00) ? (currentTcd - 0x01) : (handle->tcdSize - 0x01);
165 /* Configure current TCD block. */
166 #if defined FSL_EDMA_DRIVER_EDMA4 && FSL_EDMA_DRIVER_EDMA4
167 EDMA_TcdResetExt(handle->base, &handle->tcdPool[currentTcd]);
168 EDMA_TcdSetTransferConfigExt(handle->base, &handle->tcdPool[currentTcd], config, NULL);
169 /* Set channel link */
170 EDMA_TcdSetChannelLinkExt(handle->base, &handle->tcdPool[currentTcd], kEDMA_MinorLink, rightChannel);
171 EDMA_TcdSetChannelLinkExt(handle->base, &handle->tcdPool[currentTcd], kEDMA_MajorLink, rightChannel);
172 #else
173 EDMA_TcdReset(&handle->tcdPool[currentTcd]);
174 EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
175 /* Set channel link */
176 EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MinorLink, rightChannel);
177 EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MajorLink, rightChannel);
178 #endif
179 #if defined FSL_EDMA_DRIVER_EDMA4 && FSL_EDMA_DRIVER_EDMA4
180 /* Enable major interrupt */
181 EDMA_TCD_CSR((&handle->tcdPool[currentTcd]), EDMA_TCD_TYPE(handle->base)) |= DMA_CSR_INTMAJOR_MASK;
182 /* Link current TCD with next TCD for identification of current TCD */
183 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
184 EDMA_TCD_DLAST_SGA((&handle->tcdPool[currentTcd]), EDMA_TCD_TYPE(handle->base)) =
185 MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA);
186 #else
187 EDMA_TCD_DLAST_SGA((&handle->tcdPool[currentTcd]), EDMA_TCD_TYPE(handle->base)) = (uint32_t)&handle->tcdPool[nextTcd];
188 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
189 /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
190 if (currentTcd != previousTcd)
191 {
192 /* Enable scatter/gather feature in the previous TCD block. */
193 csr = (EDMA_TCD_CSR((&handle->tcdPool[previousTcd]), EDMA_TCD_TYPE(handle->base)) | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
194 EDMA_TCD_CSR((&handle->tcdPool[previousTcd]), EDMA_TCD_TYPE(handle->base)) = csr;
195 /*
196 Check if the TCD block in the registers is the previous one (points to current TCD block). It
197 is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
198 link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
199 before link the previous TCD block.
200 */
201 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
202 if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) ==
203 MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[currentTcd], kMEMORY_Local2DMA))
204 #else
205 if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) == (uint32_t)&handle->tcdPool[currentTcd])
206 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
207 {
208 /* Enable scatter/gather also in the TCD registers. */
209 csr = (EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
210 /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
211 EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) = csr;
212 /*
213 It is very important to check the ESG bit!
214 Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
215 be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
216 and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
217 the current TCD block has been loaded into TCD registers), it means transfer finished
218 and TCD link operation fail, so must install TCD content into TCD registers and enable
219 transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
220 link succeed.
221 */
222 if ((EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(handle->base)) & DMA_CSR_ESG_MASK) != 0x00U)
223 {
224 return kStatus_Success;
225 }
226 /*
227 Check whether the current TCD block is already loaded in the TCD registers. It is another
228 condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
229 TCD block has been loaded into TCD registers.
230 */
231 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
232 if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) ==
233 MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA))
234 #else
235 if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) == (uint32_t)&handle->tcdPool[nextTcd])
236 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
237 {
238 return kStatus_Success;
239 }
240 /*
241 If go to this, means the previous transfer finished, and the DONE bit is set.
242 So shall configure TCD registers.
243 */
244 }
245 else if (EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(handle->base)) != 0x00U)
246 {
247 /* The current TCD block has been linked successfully. */
248 return kStatus_Success;
249 }
250 else
251 {
252 /*
253 DLAST_SGA is 0 and it means the first submit transfer, so shall configure
254 TCD registers.
255 */
256 }
257 }
258 #else
259 /* Enable major interrupt */
260 handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
261 /* Link current TCD with next TCD for identification of current TCD */
262 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
263 handle->tcdPool[currentTcd].DLAST_SGA =
264 MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA);
265 #else
266 handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
267 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
268 /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
269 if (currentTcd != previousTcd)
270 {
271 /* Enable scatter/gather feature in the previous TCD block. */
272 csr = (handle->tcdPool[previousTcd].CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
273 handle->tcdPool[previousTcd].CSR = csr;
274 /*
275 Check if the TCD block in the registers is the previous one (points to current TCD block). It
276 is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
277 link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
278 before link the previous TCD block.
279 */
280 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
281 if (tcdRegs->DLAST_SGA ==
282 MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[currentTcd], kMEMORY_Local2DMA))
283 #else
284 if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
285 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
286 {
287 /* Enable scatter/gather also in the TCD registers. */
288 csr = (tcdRegs->CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
289 /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
290 tcdRegs->CSR = csr;
291 /*
292 It is very important to check the ESG bit!
293 Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
294 be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
295 and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
296 the current TCD block has been loaded into TCD registers), it means transfer finished
297 and TCD link operation fail, so must install TCD content into TCD registers and enable
298 transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
299 link succeed.
300 */
301 if ((tcdRegs->CSR & DMA_CSR_ESG_MASK) != 0x00U)
302 {
303 return kStatus_Success;
304 }
305 /*
306 Check whether the current TCD block is already loaded in the TCD registers. It is another
307 condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
308 TCD block has been loaded into TCD registers.
309 */
310 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
311 if (tcdRegs->DLAST_SGA ==
312 MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA))
313 #else
314 if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
315 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
316 {
317 return kStatus_Success;
318 }
319 /*
320 If go to this, means the previous transfer finished, and the DONE bit is set.
321 So shall configure TCD registers.
322 */
323 }
324 else if (tcdRegs->DLAST_SGA != 0x00U)
325 {
326 /* The current TCD block has been linked successfully. */
327 return kStatus_Success;
328 }
329 else
330 {
331 /*
332 DLAST_SGA is 0 and it means the first submit transfer, so shall configure
333 TCD registers.
334 */
335 }
336 }
337 #endif /* FSL_EDMA_DRIVER_EDMA4 */
338 /* There is no live chain, TCD block need to be installed in TCD registers. */
339 EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
340 /* Enable channel request again. */
341 #if defined EDMA_TRANSFER_ENABLED_MASK && EDMA_TRANSFER_ENABLED_MASK
342 if ((handle->flags & EDMA_TRANSFER_ENABLED_MASK) != 0x00U)
343
344 {
345 EDMA_EnableChannelRequest(handle->base, handle->channel);
346 }
347 else
348 {
349 ; /* Intentional empty */
350 }
351 #endif
352
353 return kStatus_Success;
354 }
355
356 /*!
357 * brief Initializes the SPDIF eDMA handle.
358 *
359 * This function initializes the SPDIF master DMA handle, which can be used for other SPDIF master transactional APIs.
360 * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
361 *
362 * param base SPDIF base pointer.
363 * param handle SPDIF eDMA handle pointer.
364 * param base SPDIF peripheral base address.
365 * param callback Pointer to user callback function.
366 * param userData User parameter passed to the callback function.
367 * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
368 * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
369 */
SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,spdif_edma_callback_t callback,void * userData,edma_handle_t * dmaLeftHandle,edma_handle_t * dmaRightHandle)370 void SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type *base,
371 spdif_edma_handle_t *handle,
372 spdif_edma_callback_t callback,
373 void *userData,
374 edma_handle_t *dmaLeftHandle,
375 edma_handle_t *dmaRightHandle)
376 {
377 assert(handle != NULL);
378 assert(dmaLeftHandle != NULL);
379 assert(dmaRightHandle != NULL);
380
381 uint32_t instance = SPDIF_GetInstance(base);
382
383 /* Zero the handle */
384 (void)memset(handle, 0, sizeof(*handle));
385
386 /* Set spdif base to handle */
387 handle->dmaLeftHandle = dmaLeftHandle;
388 handle->dmaRightHandle = dmaRightHandle;
389 handle->callback = callback;
390 handle->userData = userData;
391 handle->count =
392 s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
393
394 /* Set SPDIF state to idle */
395 handle->state = kSPDIF_Idle;
396
397 s_edmaPrivateHandle[instance][0].base = base;
398 s_edmaPrivateHandle[instance][0].handle = handle;
399
400 /* Need to use scatter gather */
401 EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
402 EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
403
404 /* Install callback for Tx dma channel, only right channel finished, a transfer finished */
405 EDMA_SetCallback(dmaRightHandle, SPDIF_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
406 }
407
408 /*!
409 * brief Initializes the SPDIF Rx eDMA handle.
410 *
411 * This function initializes the SPDIF slave DMA handle, which can be used for other SPDIF master transactional APIs.
412 * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
413 *
414 * param base SPDIF base pointer.
415 * param handle SPDIF eDMA handle pointer.
416 * param base SPDIF peripheral base address.
417 * param callback Pointer to user callback function.
418 * param userData User parameter passed to the callback function.
419 * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
420 * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
421 */
SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,spdif_edma_callback_t callback,void * userData,edma_handle_t * dmaLeftHandle,edma_handle_t * dmaRightHandle)422 void SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type *base,
423 spdif_edma_handle_t *handle,
424 spdif_edma_callback_t callback,
425 void *userData,
426 edma_handle_t *dmaLeftHandle,
427 edma_handle_t *dmaRightHandle)
428 {
429 assert(handle != NULL);
430 assert(dmaLeftHandle != NULL);
431 assert(dmaRightHandle != NULL);
432
433 uint32_t instance = SPDIF_GetInstance(base);
434
435 /* Zero the handle */
436 (void)memset(handle, 0, sizeof(*handle));
437
438 /* Set spdif base to handle */
439 handle->dmaLeftHandle = dmaLeftHandle;
440 handle->dmaRightHandle = dmaRightHandle;
441 handle->callback = callback;
442 handle->userData = userData;
443 handle->count = s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
444
445 /* Set SPDIF state to idle */
446 handle->state = kSPDIF_Idle;
447
448 s_edmaPrivateHandle[instance][1].base = base;
449 s_edmaPrivateHandle[instance][1].handle = handle;
450
451 /* Need to use scatter gather */
452 EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
453 EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
454
455 /* Install callback for Tx dma channel */
456 EDMA_SetCallback(dmaRightHandle, SPDIF_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
457 }
458
459 /*!
460 * brief Performs a non-blocking SPDIF transfer using DMA.
461 *
462 * note This interface returns immediately after the transfer initiates. Call
463 * SPDIF_GetTransferStatus to poll the transfer status and check whether the SPDIF transfer is finished.
464 *
465 * param base SPDIF base pointer.
466 * param handle SPDIF eDMA handle pointer.
467 * param xfer Pointer to the DMA transfer structure.
468 * retval kStatus_Success Start a SPDIF eDMA send successfully.
469 * retval kStatus_InvalidArgument The input argument is invalid.
470 * retval kStatus_TxBusy SPDIF is busy sending data.
471 */
SPDIF_TransferSendEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,spdif_edma_transfer_t * xfer)472 status_t SPDIF_TransferSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
473 {
474 assert(handle != NULL);
475 assert(xfer != NULL);
476
477 pvoid_to_u32_t destAddr;
478 edma_transfer_config_t config = {0};
479 destAddr.u32 = SPDIF_TxGetLeftDataRegisterAddress(base);
480
481 /* Check if input parameter invalid */
482 if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
483 {
484 return kStatus_InvalidArgument;
485 }
486
487 if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
488 (handle->spdifQueue[handle->queueUser].rightData != NULL))
489 {
490 return kStatus_SPDIF_QueueFull;
491 }
492
493 /* Change the state of handle */
494 handle->state = kSPDIF_Busy;
495
496 /* Update the queue state */
497 handle->transferSize[handle->queueUser] = xfer->dataSize;
498 handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
499 handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
500 handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
501 handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
502
503 /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
504 handle->nbytes = handle->count * 8U;
505
506 /* Prepare edma configure */
507 EDMA_PrepareTransfer(&config, xfer->leftData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
508 kEDMA_MemoryToPeripheral);
509 (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
510
511 /* Prepare right channel */
512 destAddr.u32 = SPDIF_TxGetRightDataRegisterAddress(base);
513 EDMA_PrepareTransfer(&config, xfer->rightData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
514 kEDMA_MemoryToPeripheral);
515 (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
516
517 /* Start DMA transfer */
518 EDMA_StartTransfer(handle->dmaLeftHandle);
519
520 /* Enable DMA enable bit */
521 SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, true);
522
523 /* Enable SPDIF Tx clock */
524 SPDIF_TxEnable(base, true);
525
526 return kStatus_Success;
527 }
528
529 /*!
530 * brief Performs a non-blocking SPDIF receive using eDMA.
531 *
532 * note This interface returns immediately after the transfer initiates. Call
533 * the SPDIF_GetReceiveRemainingBytes to poll the transfer status and check whether the SPDIF transfer is finished.
534 *
535 * param base SPDIF base pointer
536 * param handle SPDIF eDMA handle pointer.
537 * param xfer Pointer to DMA transfer structure.
538 * retval kStatus_Success Start a SPDIF eDMA receive successfully.
539 * retval kStatus_InvalidArgument The input argument is invalid.
540 * retval kStatus_RxBusy SPDIF is busy receiving data.
541 */
SPDIF_TransferReceiveEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,spdif_edma_transfer_t * xfer)542 status_t SPDIF_TransferReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
543 {
544 assert(handle != NULL);
545 assert(xfer != NULL);
546
547 pvoid_to_u32_t srcAddr;
548 edma_transfer_config_t config = {0};
549 srcAddr.u32 = SPDIF_RxGetLeftDataRegisterAddress(base);
550
551 /* Check if input parameter invalid */
552 if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
553 {
554 return kStatus_InvalidArgument;
555 }
556
557 if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
558 (handle->spdifQueue[handle->queueUser].rightData != NULL))
559 {
560 return kStatus_SPDIF_QueueFull;
561 }
562
563 /* Change the state of handle */
564 handle->state = kSPDIF_Busy;
565
566 /* Update the queue state */
567 handle->transferSize[handle->queueUser] = xfer->dataSize;
568 handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
569 handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
570 handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
571 handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
572
573 /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
574 handle->nbytes = handle->count * 8U;
575
576 /* Prepare edma configure */
577 EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->leftData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
578 kEDMA_PeripheralToMemory);
579 /* Use specific submit function to enable channel link */
580 (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
581
582 /* Prepare right channel */
583 srcAddr.u32 = SPDIF_RxGetRightDataRegisterAddress(base);
584 EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->rightData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
585 kEDMA_PeripheralToMemory);
586 (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
587
588 /* Start DMA transfer */
589 EDMA_StartTransfer(handle->dmaLeftHandle);
590
591 /* Enable DMA enable bit */
592 SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, true);
593
594 /* Enable SPDIF Rx clock */
595 SPDIF_RxEnable(base, true);
596
597 return kStatus_Success;
598 }
599
600 /*!
601 * brief Aborts a SPDIF transfer using eDMA.
602 *
603 * param base SPDIF base pointer.
604 * param handle SPDIF eDMA handle pointer.
605 */
SPDIF_TransferAbortSendEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle)606 void SPDIF_TransferAbortSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
607 {
608 assert(handle != NULL);
609
610 /* Disable dma */
611 EDMA_AbortTransfer(handle->dmaLeftHandle);
612 EDMA_AbortTransfer(handle->dmaRightHandle);
613
614 /* Disable DMA enable bit */
615 SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, false);
616
617 /* Set internal state */
618 (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
619 (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
620 handle->queueUser = 0U;
621 handle->queueDriver = 0U;
622
623 /* Set the handle state */
624 handle->state = kSPDIF_Idle;
625 }
626
627 /*!
628 * brief Aborts a SPDIF receive using eDMA.
629 *
630 * param base SPDIF base pointer
631 * param handle SPDIF eDMA handle pointer.
632 */
SPDIF_TransferAbortReceiveEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle)633 void SPDIF_TransferAbortReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
634 {
635 assert(handle != NULL);
636
637 /* Disable dma */
638 EDMA_AbortTransfer(handle->dmaLeftHandle);
639 EDMA_AbortTransfer(handle->dmaRightHandle);
640
641 /* Disable DMA enable bit */
642 SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, false);
643
644 /* Set internal state */
645 (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
646 (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
647 handle->queueUser = 0U;
648 handle->queueDriver = 0U;
649
650 /* Set the handle state */
651 handle->state = kSPDIF_Idle;
652 }
653
654 /*!
655 * brief Gets byte count sent by SPDIF.
656 *
657 * param base SPDIF base pointer.
658 * param handle SPDIF eDMA handle pointer.
659 * param count Bytes count sent by SPDIF.
660 * retval kStatus_Success Succeed get the transfer count.
661 * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
662 */
SPDIF_TransferGetSendCountEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,size_t * count)663 status_t SPDIF_TransferGetSendCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
664 {
665 assert(handle != NULL);
666
667 status_t status = kStatus_Success;
668
669 if (handle->state != (uint32_t)kSPDIF_Busy)
670 {
671 status = kStatus_NoTransferInProgress;
672 }
673 else
674 {
675 *count = (handle->transferSize[handle->queueDriver] -
676 (uint32_t)handle->nbytes *
677 EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
678 }
679
680 return status;
681 }
682
683 /*!
684 * brief Gets byte count received by SPDIF.
685 *
686 * param base SPDIF base pointer
687 * param handle SPDIF eDMA handle pointer.
688 * param count Bytes count received by SPDIF.
689 * retval kStatus_Success Succeed get the transfer count.
690 * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
691 */
SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,size_t * count)692 status_t SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
693 {
694 assert(handle != NULL);
695
696 status_t status = kStatus_Success;
697
698 if (handle->state != (uint32_t)kSPDIF_Busy)
699 {
700 status = kStatus_NoTransferInProgress;
701 }
702 else
703 {
704 *count = (handle->transferSize[handle->queueDriver] -
705 (uint32_t)handle->nbytes *
706 EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
707 }
708
709 return status;
710 }
711