1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 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 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.flexio_uart_edma"
18 #endif
19
20 /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
21 typedef struct _flexio_uart_edma_private_handle
22 {
23 FLEXIO_UART_Type *base;
24 flexio_uart_edma_handle_t *handle;
25 } flexio_uart_edma_private_handle_t;
26
27 /* UART EDMA transfer handle. */
28 enum _flexio_uart_edma_tansfer_states
29 {
30 kFLEXIO_UART_TxIdle, /* TX idle. */
31 kFLEXIO_UART_TxBusy, /* TX busy. */
32 kFLEXIO_UART_RxIdle, /* RX idle. */
33 kFLEXIO_UART_RxBusy /* RX busy. */
34 };
35
36 /*******************************************************************************
37 * Variables
38 ******************************************************************************/
39
40 /*< @brief user configurable flexio uart handle count. */
41 #define FLEXIO_UART_HANDLE_COUNT 2
42
43 /*<! Private handle only used for internally. */
44 static flexio_uart_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_UART_HANDLE_COUNT];
45
46 /*******************************************************************************
47 * Prototypes
48 ******************************************************************************/
49
50 /*!
51 * @brief FLEXIO UART EDMA send finished callback function.
52 *
53 * This function is called when FLEXIO UART EDMA send finished. It disables the UART
54 * TX EDMA request and sends @ref kStatus_FLEXIO_UART_TxIdle to FLEXIO UART callback.
55 *
56 * @param handle The EDMA handle.
57 * @param param Callback function parameter.
58 */
59 static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
60
61 /*!
62 * @brief FLEXIO UART EDMA receive finished callback function.
63 *
64 * This function is called when FLEXIO UART EDMA receive finished. It disables the UART
65 * RX EDMA request and sends @ref kStatus_FLEXIO_UART_RxIdle to UART callback.
66 *
67 * @param handle The EDMA handle.
68 * @param param Callback function parameter.
69 */
70 static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
71 void *param,
72 bool transferDone,
73 uint32_t tcds);
74
75 /*******************************************************************************
76 * Code
77 ******************************************************************************/
78
FLEXIO_UART_TransferSendEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)79 static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
80 {
81 flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
82
83 assert(uartPrivateHandle->handle != NULL);
84
85 /* Avoid the warning for unused variables. */
86 handle = handle;
87 tcds = tcds;
88
89 if (transferDone)
90 {
91 FLEXIO_UART_TransferAbortSendEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
92
93 if (uartPrivateHandle->handle->callback != NULL)
94 {
95 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
96 kStatus_FLEXIO_UART_TxIdle, uartPrivateHandle->handle->userData);
97 }
98 }
99 }
100
FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)101 static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
102 void *param,
103 bool transferDone,
104 uint32_t tcds)
105 {
106 flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
107
108 assert(uartPrivateHandle->handle != NULL);
109
110 /* Avoid the warning for unused variables. */
111 handle = handle;
112 tcds = tcds;
113
114 if (transferDone)
115 {
116 /* Disable transfer. */
117 FLEXIO_UART_TransferAbortReceiveEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
118
119 if (uartPrivateHandle->handle->callback != NULL)
120 {
121 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
122 kStatus_FLEXIO_UART_RxIdle, uartPrivateHandle->handle->userData);
123 }
124 }
125 }
126
127 /*!
128 * brief Initializes the UART handle which is used in transactional functions.
129 *
130 * param base Pointer to FLEXIO_UART_Type.
131 * param handle Pointer to flexio_uart_edma_handle_t structure.
132 * param callback The callback function.
133 * param userData The parameter of the callback function.
134 * param rxEdmaHandle User requested DMA handle for RX DMA transfer.
135 * param txEdmaHandle User requested DMA handle for TX DMA transfer.
136 * retval kStatus_Success Successfully create the handle.
137 * retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
138 */
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)139 status_t FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type *base,
140 flexio_uart_edma_handle_t *handle,
141 flexio_uart_edma_transfer_callback_t callback,
142 void *userData,
143 edma_handle_t *txEdmaHandle,
144 edma_handle_t *rxEdmaHandle)
145 {
146 assert(handle != NULL);
147
148 uint8_t index = 0U;
149
150 /* Find the an empty handle pointer to store the handle. */
151 for (index = 0U; index < (uint8_t)FLEXIO_UART_HANDLE_COUNT; index++)
152 {
153 if (s_edmaPrivateHandle[index].base == NULL)
154 {
155 s_edmaPrivateHandle[index].base = base;
156 s_edmaPrivateHandle[index].handle = handle;
157 break;
158 }
159 }
160
161 if (index == (uint8_t)FLEXIO_UART_HANDLE_COUNT)
162 {
163 return kStatus_OutOfRange;
164 }
165
166 (void)memset(handle, 0, sizeof(*handle));
167
168 handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
169 handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
170
171 handle->rxEdmaHandle = rxEdmaHandle;
172 handle->txEdmaHandle = txEdmaHandle;
173
174 handle->callback = callback;
175 handle->userData = userData;
176
177 /* Configure TX. */
178 if (txEdmaHandle != NULL)
179 {
180 EDMA_SetCallback(handle->txEdmaHandle, FLEXIO_UART_TransferSendEDMACallback, &s_edmaPrivateHandle);
181 }
182
183 /* Configure RX. */
184 if (rxEdmaHandle != NULL)
185 {
186 EDMA_SetCallback(handle->rxEdmaHandle, FLEXIO_UART_TransferReceiveEDMACallback, &s_edmaPrivateHandle);
187 }
188
189 return kStatus_Success;
190 }
191
192 /*!
193 * brief Sends data using eDMA.
194 *
195 * This function sends data using eDMA. This is a non-blocking function, which returns
196 * right away. When all data is sent out, the send callback function is called.
197 *
198 * param base Pointer to FLEXIO_UART_Type
199 * param handle UART handle pointer.
200 * param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
201 * retval kStatus_Success if succeed, others failed.
202 * retval kStatus_FLEXIO_UART_TxBusy Previous transfer on going.
203 */
FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_transfer_t * xfer)204 status_t FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type *base,
205 flexio_uart_edma_handle_t *handle,
206 flexio_uart_transfer_t *xfer)
207 {
208 assert(handle->txEdmaHandle != NULL);
209
210 edma_transfer_config_t xferConfig;
211 status_t status;
212
213 /* Return error if xfer invalid. */
214 if ((0U == xfer->dataSize) || (NULL == xfer->data))
215 {
216 return kStatus_InvalidArgument;
217 }
218
219 /* If previous TX not finished. */
220 if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
221 {
222 status = kStatus_FLEXIO_UART_TxBusy;
223 }
224 else
225 {
226 handle->txState = (uint8_t)kFLEXIO_UART_TxBusy;
227 handle->txDataSizeAll = xfer->dataSize;
228
229 /* Prepare transfer. */
230 EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
231 (uint32_t *)FLEXIO_UART_GetTxDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
232 xfer->dataSize, kEDMA_MemoryToPeripheral);
233
234 /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
235 handle->nbytes = sizeof(uint8_t);
236
237 /* Submit transfer. */
238 (void)EDMA_SubmitTransfer(handle->txEdmaHandle, &xferConfig);
239 EDMA_StartTransfer(handle->txEdmaHandle);
240
241 /* Enable UART TX EDMA. */
242 FLEXIO_UART_EnableTxDMA(base, true);
243
244 status = kStatus_Success;
245 }
246
247 return status;
248 }
249
250 /*!
251 * brief Receives data using eDMA.
252 *
253 * This function receives data using eDMA. This is a non-blocking function, which returns
254 * right away. When all data is received, the receive callback function is called.
255 *
256 * param base Pointer to FLEXIO_UART_Type
257 * param handle Pointer to flexio_uart_edma_handle_t structure
258 * param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
259 * retval kStatus_Success if succeed, others failed.
260 * retval kStatus_UART_RxBusy Previous transfer on going.
261 */
FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_transfer_t * xfer)262 status_t FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type *base,
263 flexio_uart_edma_handle_t *handle,
264 flexio_uart_transfer_t *xfer)
265 {
266 assert(handle->rxEdmaHandle != NULL);
267
268 edma_transfer_config_t xferConfig;
269 status_t status;
270
271 /* Return error if xfer invalid. */
272 if ((0U == xfer->dataSize) || (NULL == xfer->data))
273 {
274 return kStatus_InvalidArgument;
275 }
276
277 /* If previous RX not finished. */
278 if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
279 {
280 status = kStatus_FLEXIO_UART_RxBusy;
281 }
282 else
283 {
284 handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
285 handle->rxDataSizeAll = xfer->dataSize;
286
287 /* Prepare transfer. */
288 EDMA_PrepareTransfer(&xferConfig, (uint32_t *)FLEXIO_UART_GetRxDataRegisterAddress(base), sizeof(uint8_t),
289 xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
290
291 /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
292 handle->nbytes = sizeof(uint8_t);
293
294 /* Submit transfer. */
295 (void)EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
296 EDMA_StartTransfer(handle->rxEdmaHandle);
297
298 /* Enable UART RX EDMA. */
299 FLEXIO_UART_EnableRxDMA(base, true);
300
301 status = kStatus_Success;
302 }
303
304 return status;
305 }
306
307 /*!
308 * brief Aborts the sent data which using eDMA.
309 *
310 * This function aborts sent data which using eDMA.
311 *
312 * param base Pointer to FLEXIO_UART_Type
313 * param handle Pointer to flexio_uart_edma_handle_t structure
314 */
FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle)315 void FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
316 {
317 assert(handle->txEdmaHandle != NULL);
318
319 /* Disable UART TX EDMA. */
320 FLEXIO_UART_EnableTxDMA(base, false);
321
322 /* Stop transfer. */
323 EDMA_StopTransfer(handle->txEdmaHandle);
324
325 handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
326 }
327
328 /*!
329 * brief Aborts the receive data which using eDMA.
330 *
331 * This function aborts the receive data which using eDMA.
332 *
333 * param base Pointer to FLEXIO_UART_Type
334 * param handle Pointer to flexio_uart_edma_handle_t structure
335 */
FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle)336 void FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
337 {
338 assert(handle->rxEdmaHandle != NULL);
339
340 /* Disable UART RX EDMA. */
341 FLEXIO_UART_EnableRxDMA(base, false);
342
343 /* Stop transfer. */
344 EDMA_StopTransfer(handle->rxEdmaHandle);
345
346 handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
347 }
348
349 /*!
350 * brief Gets the number of bytes received.
351 *
352 * This function gets the number of bytes received.
353 *
354 * param base Pointer to FLEXIO_UART_Type
355 * param handle Pointer to flexio_uart_edma_handle_t structure
356 * param count Number of bytes received so far by the non-blocking transaction.
357 * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
358 * retval kStatus_Success Successfully return the count.
359 */
FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,size_t * count)360 status_t FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type *base,
361 flexio_uart_edma_handle_t *handle,
362 size_t *count)
363 {
364 assert(handle != NULL);
365 assert(handle->rxEdmaHandle != NULL);
366 assert(count != NULL);
367
368 if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
369 {
370 return kStatus_NoTransferInProgress;
371 }
372
373 *count = handle->rxDataSizeAll -
374 (uint32_t)handle->nbytes *
375 EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel);
376
377 return kStatus_Success;
378 }
379
380 /*!
381 * brief Gets the number of bytes sent out.
382 *
383 * This function gets the number of bytes sent out.
384 *
385 * param base Pointer to FLEXIO_UART_Type
386 * param handle Pointer to flexio_uart_edma_handle_t structure
387 * param count Number of bytes sent so far by the non-blocking transaction.
388 * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
389 * retval kStatus_Success Successfully return the count.
390 */
FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,size_t * count)391 status_t FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle, size_t *count)
392 {
393 assert(handle != NULL);
394 assert(handle->txEdmaHandle != NULL);
395 assert(count != NULL);
396
397 if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
398 {
399 return kStatus_NoTransferInProgress;
400 }
401
402 *count = handle->txDataSizeAll -
403 (uint32_t)handle->nbytes *
404 EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel);
405
406 return kStatus_Success;
407 }
408