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