1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_flexio_uart_edma.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
16 typedef struct _flexio_uart_edma_private_handle
17 {
18     FLEXIO_UART_Type *base;
19     flexio_uart_edma_handle_t *handle;
20 } flexio_uart_edma_private_handle_t;
21 
22 /* UART EDMA transfer handle. */
23 enum _flexio_uart_edma_tansfer_states
24 {
25     kFLEXIO_UART_TxIdle, /* TX idle. */
26     kFLEXIO_UART_TxBusy, /* TX busy. */
27     kFLEXIO_UART_RxIdle, /* RX idle. */
28     kFLEXIO_UART_RxBusy  /* RX busy. */
29 };
30 
31 /*******************************************************************************
32  * Definitions
33  ******************************************************************************/
34 /*< @brief user configurable flexio uart handle count. */
35 #define FLEXIO_UART_HANDLE_COUNT 2
36 
37 /*<! Private handle only used for internally. */
38 static flexio_uart_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_UART_HANDLE_COUNT];
39 
40 /*******************************************************************************
41  * Prototypes
42  ******************************************************************************/
43 
44 /*!
45  * @brief FLEXIO UART EDMA send finished callback function.
46  *
47  * This function is called when FLEXIO UART EDMA send finished. It disables the UART
48  * TX EDMA request and sends @ref kStatus_FLEXIO_UART_TxIdle to FLEXIO UART callback.
49  *
50  * @param handle The EDMA handle.
51  * @param param Callback function parameter.
52  */
53 static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
54 
55 /*!
56  * @brief FLEXIO UART EDMA receive finished callback function.
57  *
58  * This function is called when FLEXIO UART EDMA receive finished. It disables the UART
59  * RX EDMA request and sends @ref kStatus_FLEXIO_UART_RxIdle to UART callback.
60  *
61  * @param handle The EDMA handle.
62  * @param param Callback function parameter.
63  */
64 static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
65                                                     void *param,
66                                                     bool transferDone,
67                                                     uint32_t tcds);
68 
69 /*******************************************************************************
70  * Code
71  ******************************************************************************/
72 
FLEXIO_UART_TransferSendEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)73 static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
74 {
75     flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
76 
77     assert(uartPrivateHandle->handle);
78 
79     /* Avoid the warning for unused variables. */
80     handle = handle;
81     tcds = tcds;
82 
83     if (transferDone)
84     {
85         FLEXIO_UART_TransferAbortSendEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
86 
87         if (uartPrivateHandle->handle->callback)
88         {
89             uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
90                                                 kStatus_FLEXIO_UART_TxIdle, uartPrivateHandle->handle->userData);
91         }
92     }
93 }
94 
FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)95 static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
96                                                     void *param,
97                                                     bool transferDone,
98                                                     uint32_t tcds)
99 {
100     flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
101 
102     assert(uartPrivateHandle->handle);
103 
104     /* Avoid the warning for unused variables. */
105     handle = handle;
106     tcds = tcds;
107 
108     if (transferDone)
109     {
110         /* Disable transfer. */
111         FLEXIO_UART_TransferAbortReceiveEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
112 
113         if (uartPrivateHandle->handle->callback)
114         {
115             uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
116                                                 kStatus_FLEXIO_UART_RxIdle, uartPrivateHandle->handle->userData);
117         }
118     }
119 }
120 
FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_edma_transfer_callback_t callback,void * userData,edma_handle_t * txEdmaHandle,edma_handle_t * rxEdmaHandle)121 status_t FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type *base,
122                                               flexio_uart_edma_handle_t *handle,
123                                               flexio_uart_edma_transfer_callback_t callback,
124                                               void *userData,
125                                               edma_handle_t *txEdmaHandle,
126                                               edma_handle_t *rxEdmaHandle)
127 {
128     assert(handle);
129 
130     uint8_t index = 0;
131 
132     /* Find the an empty handle pointer to store the handle. */
133     for (index = 0; index < FLEXIO_UART_HANDLE_COUNT; index++)
134     {
135         if (s_edmaPrivateHandle[index].base == NULL)
136         {
137             s_edmaPrivateHandle[index].base = base;
138             s_edmaPrivateHandle[index].handle = handle;
139             break;
140         }
141     }
142 
143     if (index == FLEXIO_UART_HANDLE_COUNT)
144     {
145         return kStatus_OutOfRange;
146     }
147 
148     memset(handle, 0, sizeof(*handle));
149 
150     handle->rxState = kFLEXIO_UART_RxIdle;
151     handle->txState = kFLEXIO_UART_TxIdle;
152 
153     handle->rxEdmaHandle = rxEdmaHandle;
154     handle->txEdmaHandle = txEdmaHandle;
155 
156     handle->callback = callback;
157     handle->userData = userData;
158 
159     /* Configure TX. */
160     if (txEdmaHandle)
161     {
162         EDMA_SetCallback(handle->txEdmaHandle, FLEXIO_UART_TransferSendEDMACallback, &s_edmaPrivateHandle);
163     }
164 
165     /* Configure RX. */
166     if (rxEdmaHandle)
167     {
168         EDMA_SetCallback(handle->rxEdmaHandle, FLEXIO_UART_TransferReceiveEDMACallback, &s_edmaPrivateHandle);
169     }
170 
171     return kStatus_Success;
172 }
173 
FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_transfer_t * xfer)174 status_t FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type *base,
175                                       flexio_uart_edma_handle_t *handle,
176                                       flexio_uart_transfer_t *xfer)
177 {
178     assert(handle->txEdmaHandle);
179 
180     edma_transfer_config_t xferConfig;
181     status_t status;
182 
183     /* Return error if xfer invalid. */
184     if ((0U == xfer->dataSize) || (NULL == xfer->data))
185     {
186         return kStatus_InvalidArgument;
187     }
188 
189     /* If previous TX not finished. */
190     if (kFLEXIO_UART_TxBusy == handle->txState)
191     {
192         status = kStatus_FLEXIO_UART_TxBusy;
193     }
194     else
195     {
196         handle->txState = kFLEXIO_UART_TxBusy;
197         handle->txDataSizeAll = xfer->dataSize;
198 
199         /* Prepare transfer. */
200         EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
201                              (void *)FLEXIO_UART_GetTxDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
202                              xfer->dataSize, kEDMA_MemoryToPeripheral);
203 
204         /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
205         handle->nbytes = sizeof(uint8_t);
206 
207         /* Submit transfer. */
208         EDMA_SubmitTransfer(handle->txEdmaHandle, &xferConfig);
209         EDMA_StartTransfer(handle->txEdmaHandle);
210 
211         /* Enable UART TX EDMA. */
212         FLEXIO_UART_EnableTxDMA(base, true);
213 
214         status = kStatus_Success;
215     }
216 
217     return status;
218 }
219 
FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_transfer_t * xfer)220 status_t FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type *base,
221                                          flexio_uart_edma_handle_t *handle,
222                                          flexio_uart_transfer_t *xfer)
223 {
224     assert(handle->rxEdmaHandle);
225 
226     edma_transfer_config_t xferConfig;
227     status_t status;
228 
229     /* Return error if xfer invalid. */
230     if ((0U == xfer->dataSize) || (NULL == xfer->data))
231     {
232         return kStatus_InvalidArgument;
233     }
234 
235     /* If previous RX not finished. */
236     if (kFLEXIO_UART_RxBusy == handle->rxState)
237     {
238         status = kStatus_FLEXIO_UART_RxBusy;
239     }
240     else
241     {
242         handle->rxState = kFLEXIO_UART_RxBusy;
243         handle->rxDataSizeAll = xfer->dataSize;
244 
245         /* Prepare transfer. */
246         EDMA_PrepareTransfer(&xferConfig, (void *)FLEXIO_UART_GetRxDataRegisterAddress(base), sizeof(uint8_t),
247                              xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
248 
249         /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
250         handle->nbytes = sizeof(uint8_t);
251 
252         /* Submit transfer. */
253         EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
254         EDMA_StartTransfer(handle->rxEdmaHandle);
255 
256         /* Enable UART RX EDMA. */
257         FLEXIO_UART_EnableRxDMA(base, true);
258 
259         status = kStatus_Success;
260     }
261 
262     return status;
263 }
264 
FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle)265 void FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
266 {
267     assert(handle->txEdmaHandle);
268 
269     /* Disable UART TX EDMA. */
270     FLEXIO_UART_EnableTxDMA(base, false);
271 
272     /* Stop transfer. */
273     EDMA_StopTransfer(handle->txEdmaHandle);
274 
275     handle->txState = kFLEXIO_UART_TxIdle;
276 }
277 
FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle)278 void FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
279 {
280     assert(handle->rxEdmaHandle);
281 
282     /* Disable UART RX EDMA. */
283     FLEXIO_UART_EnableRxDMA(base, false);
284 
285     /* Stop transfer. */
286     EDMA_StopTransfer(handle->rxEdmaHandle);
287 
288     handle->rxState = kFLEXIO_UART_RxIdle;
289 }
290 
FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,size_t * count)291 status_t FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type *base,
292                                                  flexio_uart_edma_handle_t *handle,
293                                                  size_t *count)
294 {
295     assert(handle);
296     assert(handle->rxEdmaHandle);
297     assert(count);
298 
299     if (kFLEXIO_UART_RxIdle == handle->rxState)
300     {
301         return kStatus_NoTransferInProgress;
302     }
303 
304     *count = handle->rxDataSizeAll -
305              (uint32_t)handle->nbytes *
306                  EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel);
307 
308     return kStatus_Success;
309 }
310 
FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,size_t * count)311 status_t FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle, size_t *count)
312 {
313     assert(handle);
314     assert(handle->txEdmaHandle);
315     assert(count);
316 
317     if (kFLEXIO_UART_TxIdle == handle->txState)
318     {
319         return kStatus_NoTransferInProgress;
320     }
321 
322     *count = handle->txDataSizeAll -
323              (uint32_t)handle->nbytes *
324                  EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel);
325 
326     return kStatus_Success;
327 }
328