1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  *   of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  *   list of conditions and the following disclaimer in the documentation and/or
13  *   other materials provided with the distribution.
14  *
15  * o Neither the name of the copyright holder nor the names of its
16  *   contributors may be used to endorse or promote products derived from this
17  *   software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "fsl_uart_dma.h"
32 #include "fsl_dmamux.h"
33 
34 /*******************************************************************************
35  * Definitions
36  ******************************************************************************/
37 
38 /* Array of UART handle. */
39 #if (defined(UART5))
40 #define UART_HANDLE_ARRAY_SIZE 6
41 #else /* UART5 */
42 #if (defined(UART4))
43 #define UART_HANDLE_ARRAY_SIZE 5
44 #else /* UART4 */
45 #if (defined(UART3))
46 #define UART_HANDLE_ARRAY_SIZE 4
47 #else /* UART3 */
48 #if (defined(UART2))
49 #define UART_HANDLE_ARRAY_SIZE 3
50 #else /* UART2 */
51 #if (defined(UART1))
52 #define UART_HANDLE_ARRAY_SIZE 2
53 #else /* UART1 */
54 #if (defined(UART0))
55 #define UART_HANDLE_ARRAY_SIZE 1
56 #else /* UART0 */
57 #error No UART instance.
58 #endif /* UART 0 */
59 #endif /* UART 1 */
60 #endif /* UART 2 */
61 #endif /* UART 3 */
62 #endif /* UART 4 */
63 #endif /* UART 5 */
64 
65 /*<! Structure definition for uart_dma_handle_t. The structure is private. */
66 typedef struct _uart_dma_private_handle
67 {
68     UART_Type *base;
69     uart_dma_handle_t *handle;
70 } uart_dma_private_handle_t;
71 
72 /* UART DMA transfer handle. */
73 enum _uart_dma_tansfer_states
74 {
75     kUART_TxIdle, /* TX idle. */
76     kUART_TxBusy, /* TX busy. */
77     kUART_RxIdle, /* RX idle. */
78     kUART_RxBusy  /* RX busy. */
79 };
80 
81 /*******************************************************************************
82  * Variables
83  ******************************************************************************/
84 
85 /*<! Private handle only used for internally. */
86 static uart_dma_private_handle_t s_dmaPrivateHandle[UART_HANDLE_ARRAY_SIZE];
87 
88 /*******************************************************************************
89  * Prototypes
90  ******************************************************************************/
91 
92 /*!
93  * @brief UART DMA send finished callback function.
94  *
95  * This function is called when UART DMA send finished. It disables the UART
96  * TX DMA request and sends @ref kStatus_UART_TxIdle to UART callback.
97  *
98  * @param handle The DMA handle.
99  * @param param Callback function parameter.
100  */
101 static void UART_TransferSendDMACallback(dma_handle_t *handle, void *param);
102 
103 /*!
104  * @brief UART DMA receive finished callback function.
105  *
106  * This function is called when UART DMA receive finished. It disables the UART
107  * RX DMA request and sends @ref kStatus_UART_RxIdle to UART callback.
108  *
109  * @param handle The DMA handle.
110  * @param param Callback function parameter.
111  */
112 static void UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param);
113 
114 /*!
115  * @brief Get the UART instance from peripheral base address.
116  *
117  * @param base UART peripheral base address.
118  * @return UART instance.
119  */
120 extern uint32_t UART_GetInstance(UART_Type *base);
121 
122 /*******************************************************************************
123  * Code
124  ******************************************************************************/
125 
UART_TransferSendDMACallback(dma_handle_t * handle,void * param)126 static void UART_TransferSendDMACallback(dma_handle_t *handle, void *param)
127 {
128     assert(handle);
129     assert(param);
130 
131     uart_dma_private_handle_t *uartPrivateHandle = (uart_dma_private_handle_t *)param;
132 
133     /* Disable UART TX DMA. */
134     UART_EnableTxDMA(uartPrivateHandle->base, false);
135 
136     /* Disable interrupt. */
137     DMA_DisableInterrupts(handle->base, handle->channel);
138 
139     uartPrivateHandle->handle->txState = kUART_TxIdle;
140 
141     if (uartPrivateHandle->handle->callback)
142     {
143         uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle, kStatus_UART_TxIdle,
144                                             uartPrivateHandle->handle->userData);
145     }
146 }
147 
UART_TransferReceiveDMACallback(dma_handle_t * handle,void * param)148 static void UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param)
149 {
150     assert(handle);
151     assert(param);
152 
153     uart_dma_private_handle_t *uartPrivateHandle = (uart_dma_private_handle_t *)param;
154 
155     /* Disable UART RX DMA. */
156     UART_EnableRxDMA(uartPrivateHandle->base, false);
157 
158     /* Disable interrupt. */
159     DMA_DisableInterrupts(handle->base, handle->channel);
160 
161     uartPrivateHandle->handle->rxState = kUART_RxIdle;
162 
163     if (uartPrivateHandle->handle->callback)
164     {
165         uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle, kStatus_UART_RxIdle,
166                                             uartPrivateHandle->handle->userData);
167     }
168 }
169 
UART_TransferCreateHandleDMA(UART_Type * base,uart_dma_handle_t * handle,uart_dma_transfer_callback_t callback,void * userData,dma_handle_t * txDmaHandle,dma_handle_t * rxDmaHandle)170 void UART_TransferCreateHandleDMA(UART_Type *base,
171                                   uart_dma_handle_t *handle,
172                                   uart_dma_transfer_callback_t callback,
173                                   void *userData,
174                                   dma_handle_t *txDmaHandle,
175                                   dma_handle_t *rxDmaHandle)
176 {
177     assert(handle);
178 
179     uint32_t instance = UART_GetInstance(base);
180 
181     memset(handle, 0, sizeof(*handle));
182 
183     s_dmaPrivateHandle[instance].base = base;
184     s_dmaPrivateHandle[instance].handle = handle;
185 
186     handle->rxState = kUART_RxIdle;
187     handle->txState = kUART_TxIdle;
188 
189     handle->callback = callback;
190     handle->userData = userData;
191 
192 #if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
193     /* Note:
194        Take care of the RX FIFO, DMA request only assert when received bytes
195        equal or more than RX water mark, there is potential issue if RX water
196        mark larger than 1.
197        For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
198        5 bytes are received. the last byte will be saved in FIFO but not trigger
199        DMA transfer because the water mark is 2.
200      */
201     if (rxDmaHandle)
202     {
203         base->RWFIFO = 1U;
204     }
205 #endif
206 
207     handle->rxDmaHandle = rxDmaHandle;
208     handle->txDmaHandle = txDmaHandle;
209 
210     /* Configure TX. */
211     if (txDmaHandle)
212     {
213         DMA_SetCallback(txDmaHandle, UART_TransferSendDMACallback, &s_dmaPrivateHandle[instance]);
214     }
215 
216     /* Configure RX. */
217     if (rxDmaHandle)
218     {
219         DMA_SetCallback(rxDmaHandle, UART_TransferReceiveDMACallback, &s_dmaPrivateHandle[instance]);
220     }
221 }
222 
UART_TransferSendDMA(UART_Type * base,uart_dma_handle_t * handle,uart_transfer_t * xfer)223 status_t UART_TransferSendDMA(UART_Type *base, uart_dma_handle_t *handle, uart_transfer_t *xfer)
224 {
225     assert(handle);
226     assert(handle->txDmaHandle);
227     assert(xfer);
228     assert(xfer->data);
229     assert(xfer->dataSize);
230 
231     dma_transfer_config_t xferConfig;
232     status_t status;
233 
234     /* If previous TX not finished. */
235     if (kUART_TxBusy == handle->txState)
236     {
237         status = kStatus_UART_TxBusy;
238     }
239     else
240     {
241         handle->txState = kUART_TxBusy;
242         handle->txDataSizeAll = xfer->dataSize;
243 
244         /* Prepare transfer. */
245         DMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t), (void *)UART_GetDataRegisterAddress(base),
246                             sizeof(uint8_t), xfer->dataSize, kDMA_MemoryToPeripheral);
247 
248         /* Submit transfer. */
249         DMA_SubmitTransfer(handle->txDmaHandle, &xferConfig, kDMA_EnableInterrupt);
250         DMA_StartTransfer(handle->txDmaHandle);
251 
252         /* Enable UART TX DMA. */
253         UART_EnableTxDMA(base, true);
254 
255         status = kStatus_Success;
256     }
257 
258     return status;
259 }
260 
UART_TransferReceiveDMA(UART_Type * base,uart_dma_handle_t * handle,uart_transfer_t * xfer)261 status_t UART_TransferReceiveDMA(UART_Type *base, uart_dma_handle_t *handle, uart_transfer_t *xfer)
262 {
263     assert(handle);
264     assert(handle->rxDmaHandle);
265     assert(xfer);
266     assert(xfer->data);
267     assert(xfer->dataSize);
268 
269     dma_transfer_config_t xferConfig;
270     status_t status;
271 
272     /* If previous RX not finished. */
273     if (kUART_RxBusy == handle->rxState)
274     {
275         status = kStatus_UART_RxBusy;
276     }
277     else
278     {
279         handle->rxState = kUART_RxBusy;
280         handle->rxDataSizeAll = xfer->dataSize;
281 
282         /* Prepare transfer. */
283         DMA_PrepareTransfer(&xferConfig, (void *)UART_GetDataRegisterAddress(base), sizeof(uint8_t), xfer->data,
284                             sizeof(uint8_t), xfer->dataSize, kDMA_PeripheralToMemory);
285 
286         /* Submit transfer. */
287         DMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig, kDMA_EnableInterrupt);
288         DMA_StartTransfer(handle->rxDmaHandle);
289 
290         /* Enable UART RX DMA. */
291         UART_EnableRxDMA(base, true);
292 
293         status = kStatus_Success;
294     }
295 
296     return status;
297 }
298 
UART_TransferAbortSendDMA(UART_Type * base,uart_dma_handle_t * handle)299 void UART_TransferAbortSendDMA(UART_Type *base, uart_dma_handle_t *handle)
300 {
301     assert(handle);
302     assert(handle->txDmaHandle);
303 
304     /* Disable UART TX DMA. */
305     UART_EnableTxDMA(base, false);
306 
307     /* Stop transfer. */
308     DMA_AbortTransfer(handle->txDmaHandle);
309 
310     /* Write DMA->DSR[DONE] to abort transfer and clear status. */
311     DMA_ClearChannelStatusFlags(handle->txDmaHandle->base, handle->txDmaHandle->channel, kDMA_TransactionsDoneFlag);
312 
313     handle->txState = kUART_TxIdle;
314 }
315 
UART_TransferAbortReceiveDMA(UART_Type * base,uart_dma_handle_t * handle)316 void UART_TransferAbortReceiveDMA(UART_Type *base, uart_dma_handle_t *handle)
317 {
318     assert(handle);
319     assert(handle->rxDmaHandle);
320 
321     /* Disable UART RX DMA. */
322     UART_EnableRxDMA(base, false);
323 
324     /* Stop transfer. */
325     DMA_AbortTransfer(handle->rxDmaHandle);
326 
327     /* Write DMA->DSR[DONE] to abort transfer and clear status. */
328     DMA_ClearChannelStatusFlags(handle->rxDmaHandle->base, handle->rxDmaHandle->channel, kDMA_TransactionsDoneFlag);
329 
330     handle->rxState = kUART_RxIdle;
331 }
332 
UART_TransferGetSendCountDMA(UART_Type * base,uart_dma_handle_t * handle,uint32_t * count)333 status_t UART_TransferGetSendCountDMA(UART_Type *base, uart_dma_handle_t *handle, uint32_t *count)
334 {
335     assert(handle);
336     assert(handle->txDmaHandle);
337     assert(count);
338 
339     if (kUART_TxIdle == handle->txState)
340     {
341         return kStatus_NoTransferInProgress;
342     }
343 
344     *count = handle->txDataSizeAll - DMA_GetRemainingBytes(handle->txDmaHandle->base, handle->txDmaHandle->channel);
345 
346     return kStatus_Success;
347 }
348 
UART_TransferGetReceiveCountDMA(UART_Type * base,uart_dma_handle_t * handle,uint32_t * count)349 status_t UART_TransferGetReceiveCountDMA(UART_Type *base, uart_dma_handle_t *handle, uint32_t *count)
350 {
351     assert(handle);
352     assert(handle->rxDmaHandle);
353     assert(count);
354 
355     if (kUART_RxIdle == handle->rxState)
356     {
357         return kStatus_NoTransferInProgress;
358     }
359 
360     *count = handle->rxDataSizeAll - DMA_GetRemainingBytes(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
361 
362     return kStatus_Success;
363 }
364