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_dma.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_dma"
18 #endif
19 
20 /*<! @brief Structure definition for DMA callback param pass in. */
21 typedef struct _flexio_uart_dma_private_handle
22 {
23     FLEXIO_UART_Type *base;
24     flexio_uart_dma_handle_t *handle;
25 } flexio_uart_dma_private_handle_t;
26 
27 /*<! @brief uart transfer state. */
28 enum _flexio_uart_dma_transfer_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_dma_private_handle_t s_dmaPrivateHandle[FLEXIO_UART_HANDLE_COUNT];
45 
46 /*******************************************************************************
47  * Prototypes
48  ******************************************************************************/
49 
50 /*!
51  * @brief FLEXIO UART DMA send finished callback function.
52  *
53  * This function is called when FLEXIO UART DMA send finished. It disables the UART
54  * TX DMA request and sends @ref kStatus_FLEXIO_UART_TxIdle to FLEXIO UART callback.
55  *
56  * @param handle The DMA handle.
57  * @param param Callback function parameter.
58  */
59 static void FLEXIO_UART_TransferSendDMACallback(dma_handle_t *handle, void *param);
60 
61 /*!
62  * @brief FLEXIO UART DMA receive finished callback function.
63  *
64  * This function is called when FLEXIO UART DMA receive finished. It disables the FLEXIO
65  * UART RX DMA request and sends @ref kStatus_FLEXIO_UART_RxIdle to UART callback.
66  *
67  * @param handle The DMA handle.
68  * @param param Callback function parameter.
69  */
70 static void FLEXIO_UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param);
71 
72 /*******************************************************************************
73  * Code
74  ******************************************************************************/
75 
FLEXIO_UART_TransferSendDMACallback(dma_handle_t * handle,void * param)76 static void FLEXIO_UART_TransferSendDMACallback(dma_handle_t *handle, void *param)
77 {
78     flexio_uart_dma_private_handle_t *uartPrivateHandle = (flexio_uart_dma_private_handle_t *)param;
79 
80     /* Disable UART TX DMA. */
81     FLEXIO_UART_EnableTxDMA(uartPrivateHandle->base, false);
82 
83     /* Disable interrupt. */
84     DMA_DisableInterrupts(handle->base, handle->channel);
85 
86     uartPrivateHandle->handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
87 
88     if (uartPrivateHandle->handle->callback != NULL)
89     {
90         uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
91                                             kStatus_FLEXIO_UART_TxIdle, uartPrivateHandle->handle->userData);
92     }
93 }
94 
FLEXIO_UART_TransferReceiveDMACallback(dma_handle_t * handle,void * param)95 static void FLEXIO_UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param)
96 {
97     flexio_uart_dma_private_handle_t *uartPrivateHandle = (flexio_uart_dma_private_handle_t *)param;
98 
99     /* Disable UART RX DMA. */
100     FLEXIO_UART_EnableRxDMA(uartPrivateHandle->base, false);
101 
102     /* Disable interrupt. */
103     DMA_DisableInterrupts(handle->base, handle->channel);
104 
105     uartPrivateHandle->handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
106 
107     if (uartPrivateHandle->handle->callback != NULL)
108     {
109         uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
110                                             kStatus_FLEXIO_UART_RxIdle, uartPrivateHandle->handle->userData);
111     }
112 }
113 
114 /*!
115  * brief Initializes the FLEXIO_UART handle which is used in transactional functions.
116  *
117  * param base Pointer to FLEXIO_UART_Type structure.
118  * param handle Pointer to flexio_uart_dma_handle_t structure.
119  * param callback FlexIO UART callback, NULL means no callback.
120  * param userData User callback function data.
121  * param txDmaHandle User requested DMA handle for TX DMA transfer.
122  * param rxDmaHandle User requested DMA handle for RX DMA transfer.
123  * retval kStatus_Success Successfully create the handle.
124  * retval kStatus_OutOfRange The FlexIO UART DMA type/handle table out of range.
125  */
FLEXIO_UART_TransferCreateHandleDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,flexio_uart_dma_transfer_callback_t callback,void * userData,dma_handle_t * txDmaHandle,dma_handle_t * rxDmaHandle)126 status_t FLEXIO_UART_TransferCreateHandleDMA(FLEXIO_UART_Type *base,
127                                              flexio_uart_dma_handle_t *handle,
128                                              flexio_uart_dma_transfer_callback_t callback,
129                                              void *userData,
130                                              dma_handle_t *txDmaHandle,
131                                              dma_handle_t *rxDmaHandle)
132 {
133     assert(handle != NULL);
134 
135     dma_transfer_config_t dmaXferConfig;
136     uint8_t index = 0;
137 
138     /* Find the an empty handle pointer to store the handle. */
139     for (index = 0U; index < (uint8_t)FLEXIO_UART_HANDLE_COUNT; index++)
140     {
141         if (s_dmaPrivateHandle[index].base == NULL)
142         {
143             s_dmaPrivateHandle[index].base   = base;
144             s_dmaPrivateHandle[index].handle = handle;
145             break;
146         }
147     }
148 
149     if (index == (uint8_t)FLEXIO_UART_HANDLE_COUNT)
150     {
151         return kStatus_OutOfRange;
152     }
153 
154     (void)memset(handle, 0, sizeof(*handle));
155 
156     handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
157     handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
158 
159     handle->callback = callback;
160     handle->userData = userData;
161 
162     handle->rxDmaHandle = rxDmaHandle;
163     handle->txDmaHandle = txDmaHandle;
164 
165     /* Set DMA channel configuration. */
166     (void)memset(&dmaXferConfig, 0, sizeof(dmaXferConfig));
167     dmaXferConfig.srcSize  = kDMA_Transfersize8bits;
168     dmaXferConfig.destSize = kDMA_Transfersize8bits;
169 
170     /* Configure TX. */
171     if (txDmaHandle != NULL)
172     {
173         DMA_SetCallback(txDmaHandle, FLEXIO_UART_TransferSendDMACallback, &s_dmaPrivateHandle[index]);
174 
175         DMA_ResetChannel(txDmaHandle->base, txDmaHandle->channel);
176 
177         dmaXferConfig.destAddr            = FLEXIO_UART_GetTxDataRegisterAddress(base);
178         dmaXferConfig.enableSrcIncrement  = true;
179         dmaXferConfig.enableDestIncrement = false;
180         DMA_SetTransferConfig(txDmaHandle->base, txDmaHandle->channel, &dmaXferConfig);
181     }
182 
183     /* Configure RX. */
184     if (rxDmaHandle != NULL)
185     {
186         DMA_SetCallback(rxDmaHandle, FLEXIO_UART_TransferReceiveDMACallback, &s_dmaPrivateHandle[index]);
187 
188         DMA_ResetChannel(rxDmaHandle->base, rxDmaHandle->channel);
189 
190         dmaXferConfig.destAddr            = 0U;
191         dmaXferConfig.srcAddr             = FLEXIO_UART_GetRxDataRegisterAddress(base);
192         dmaXferConfig.enableSrcIncrement  = false;
193         dmaXferConfig.enableDestIncrement = true;
194         DMA_SetTransferConfig(rxDmaHandle->base, rxDmaHandle->channel, &dmaXferConfig);
195     }
196 
197     return kStatus_Success;
198 }
199 
200 /*!
201  * brief Sends data using DMA.
202  *
203  * This function send data using DMA. This is non-blocking function, which returns
204  * right away. When all data is sent out, the send callback function is called.
205  *
206  * param base Pointer to FLEXIO_UART_Type structure
207  * param handle Pointer to flexio_uart_dma_handle_t structure
208  * param xfer FLEXIO_UART DMA transfer structure, see #flexio_uart_transfer_t.
209  * retval kStatus_Success if succeed, others failed.
210  * retval kStatus_FLEXIO_UART_TxBusy Previous transfer on going.
211  */
FLEXIO_UART_TransferSendDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,flexio_uart_transfer_t * xfer)212 status_t FLEXIO_UART_TransferSendDMA(FLEXIO_UART_Type *base,
213                                      flexio_uart_dma_handle_t *handle,
214                                      flexio_uart_transfer_t *xfer)
215 {
216     assert(handle->txDmaHandle != NULL);
217 
218     status_t status;
219 
220     /* Return error if xfer invalid. */
221     if ((0U == xfer->dataSize) || (NULL == xfer->data))
222     {
223         return kStatus_InvalidArgument;
224     }
225 
226     /* If previous TX not finished. */
227     if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
228     {
229         status = kStatus_FLEXIO_UART_TxBusy;
230     }
231     else
232     {
233         handle->txState       = (uint8_t)kFLEXIO_UART_TxBusy;
234         handle->txDataSizeAll = xfer->dataSize;
235 
236         /* Set transfer data address and data size. */
237         DMA_SetSourceAddress(handle->txDmaHandle->base, handle->txDmaHandle->channel, (uint32_t)xfer->data);
238         DMA_SetTransferSize(handle->txDmaHandle->base, handle->txDmaHandle->channel, xfer->dataSize);
239 
240         /* Enable FLEXIO UART TX DMA. */
241         FLEXIO_UART_EnableTxDMA(base, true);
242 
243         /* Enable DMA transfer complete interrupt and start transfer. */
244         DMA_EnableInterrupts(handle->txDmaHandle->base, handle->txDmaHandle->channel);
245         DMA_EnableChannelRequest(handle->txDmaHandle->base, handle->txDmaHandle->channel);
246 
247         status = kStatus_Success;
248     }
249 
250     return status;
251 }
252 
253 /*!
254  * brief Receives data using DMA.
255  *
256  * This function receives data using DMA. This is non-blocking function, which returns
257  * right away. When all data is received, the receive callback function is called.
258  *
259  * param base Pointer to FLEXIO_UART_Type structure
260  * param handle Pointer to flexio_uart_dma_handle_t structure
261  * param xfer FLEXIO_UART DMA transfer structure, see #flexio_uart_transfer_t.
262  * retval kStatus_Success if succeed, others failed.
263  * retval kStatus_FLEXIO_UART_RxBusy Previous transfer on going.
264  */
FLEXIO_UART_TransferReceiveDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,flexio_uart_transfer_t * xfer)265 status_t FLEXIO_UART_TransferReceiveDMA(FLEXIO_UART_Type *base,
266                                         flexio_uart_dma_handle_t *handle,
267                                         flexio_uart_transfer_t *xfer)
268 {
269     assert(handle->rxDmaHandle != NULL);
270 
271     status_t status;
272 
273     /* Return error if xfer invalid. */
274     if ((0U == xfer->dataSize) || (NULL == xfer->data))
275     {
276         return kStatus_InvalidArgument;
277     }
278 
279     /* If previous RX not finished. */
280     if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
281     {
282         status = kStatus_FLEXIO_UART_RxBusy;
283     }
284     else
285     {
286         handle->rxState       = (uint8_t)kFLEXIO_UART_RxBusy;
287         handle->rxDataSizeAll = xfer->dataSize;
288 
289         /* Set transfer data address and data size. */
290         DMA_SetDestinationAddress(handle->rxDmaHandle->base, handle->rxDmaHandle->channel, (uint32_t)xfer->data);
291         DMA_SetTransferSize(handle->rxDmaHandle->base, handle->rxDmaHandle->channel, xfer->dataSize);
292 
293         /* Enable FLEXIO UART RX DMA. */
294         FLEXIO_UART_EnableRxDMA(base, true);
295 
296         /* Enable DMA transfer complete interrupt and start transfer. */
297         DMA_EnableInterrupts(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
298         DMA_EnableChannelRequest(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
299 
300         status = kStatus_Success;
301     }
302 
303     return status;
304 }
305 
306 /*!
307  * brief Aborts the sent data which using DMA.
308  *
309  * This function aborts the sent data which using DMA.
310  *
311  * param base Pointer to FLEXIO_UART_Type structure
312  * param handle Pointer to flexio_uart_dma_handle_t structure
313  */
FLEXIO_UART_TransferAbortSendDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle)314 void FLEXIO_UART_TransferAbortSendDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle)
315 {
316     assert(handle->txDmaHandle != NULL);
317 
318     /* Disable FLEXIO UART TX DMA. */
319     FLEXIO_UART_EnableTxDMA(base, false);
320 
321     /* Stop transfer. */
322     DMA_StopTransfer(handle->txDmaHandle);
323 
324     /* Write DMA->DSR[DONE] to abort transfer and clear status. */
325     DMA_ClearChannelStatusFlags(handle->txDmaHandle->base, handle->txDmaHandle->channel,
326                                 (uint32_t)kDMA_TransactionsDoneFlag);
327 
328     handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
329 }
330 
331 /*!
332  * brief Aborts the receive data which using DMA.
333  *
334  * This function aborts the receive data which using DMA.
335  *
336  * param base Pointer to FLEXIO_UART_Type structure
337  * param handle Pointer to flexio_uart_dma_handle_t structure
338  */
FLEXIO_UART_TransferAbortReceiveDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle)339 void FLEXIO_UART_TransferAbortReceiveDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle)
340 {
341     assert(handle->rxDmaHandle != NULL);
342 
343     /* Disable FLEXIO UART RX DMA. */
344     FLEXIO_UART_EnableRxDMA(base, false);
345 
346     /* Stop transfer. */
347     DMA_StopTransfer(handle->rxDmaHandle);
348 
349     /* Write DMA->DSR[DONE] to abort transfer and clear status. */
350     DMA_ClearChannelStatusFlags(handle->rxDmaHandle->base, handle->rxDmaHandle->channel,
351                                 (uint32_t)kDMA_TransactionsDoneFlag);
352 
353     handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
354 }
355 
356 /*!
357  * brief Gets the number of bytes sent out.
358  *
359  * This function gets the number of bytes sent out.
360  *
361  * param base Pointer to FLEXIO_UART_Type structure
362  * param handle Pointer to flexio_uart_dma_handle_t structure
363  * param count Number of bytes sent so far by the non-blocking transaction.
364  * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
365  * retval kStatus_Success Successfully return the count.
366  */
FLEXIO_UART_TransferGetSendCountDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,size_t * count)367 status_t FLEXIO_UART_TransferGetSendCountDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle, size_t *count)
368 {
369     assert(handle != NULL);
370     assert(handle->txDmaHandle != NULL);
371     assert(count != NULL);
372 
373     if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
374     {
375         return kStatus_NoTransferInProgress;
376     }
377 
378     *count = handle->txDataSizeAll - DMA_GetRemainingBytes(handle->txDmaHandle->base, handle->txDmaHandle->channel);
379 
380     return kStatus_Success;
381 }
382 
383 /*!
384  * brief Gets the number of bytes received.
385  *
386  * This function gets the number of bytes received.
387  *
388  * param base Pointer to FLEXIO_UART_Type structure
389  * param handle Pointer to flexio_uart_dma_handle_t structure
390  * param count Number of bytes received so far by the non-blocking transaction.
391  * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
392  * retval kStatus_Success Successfully return the count.
393  */
FLEXIO_UART_TransferGetReceiveCountDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,size_t * count)394 status_t FLEXIO_UART_TransferGetReceiveCountDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle, size_t *count)
395 {
396     assert(handle != NULL);
397     assert(handle->rxDmaHandle != NULL);
398     assert(count != NULL);
399 
400     if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
401     {
402         return kStatus_NoTransferInProgress;
403     }
404 
405     *count = handle->rxDataSizeAll - DMA_GetRemainingBytes(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
406 
407     return kStatus_Success;
408 }
409