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