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_edma.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_edma_private_handle_t. The structure is private. */
66 typedef struct _uart_edma_private_handle
67 {
68 UART_Type *base;
69 uart_edma_handle_t *handle;
70 } uart_edma_private_handle_t;
71
72 /* UART EDMA transfer handle. */
73 enum _uart_edma_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 * Definitions
83 ******************************************************************************/
84
85 /*<! Private handle only used for internally. */
86 static uart_edma_private_handle_t s_edmaPrivateHandle[UART_HANDLE_ARRAY_SIZE];
87
88 /*******************************************************************************
89 * Prototypes
90 ******************************************************************************/
91
92 /*!
93 * @brief UART EDMA send finished callback function.
94 *
95 * This function is called when UART EDMA send finished. It disables the UART
96 * TX EDMA request and sends @ref kStatus_UART_TxIdle to UART callback.
97 *
98 * @param handle The EDMA handle.
99 * @param param Callback function parameter.
100 */
101 static void UART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
102
103 /*!
104 * @brief UART EDMA receive finished callback function.
105 *
106 * This function is called when UART EDMA receive finished. It disables the UART
107 * RX EDMA request and sends @ref kStatus_UART_RxIdle to UART callback.
108 *
109 * @param handle The EDMA handle.
110 * @param param Callback function parameter.
111 */
112 static void UART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
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_SendEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)126 static void UART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
127 {
128 assert(param);
129
130 uart_edma_private_handle_t *uartPrivateHandle = (uart_edma_private_handle_t *)param;
131
132 /* Avoid the warning for unused variables. */
133 handle = handle;
134 tcds = tcds;
135
136 if (transferDone)
137 {
138 UART_TransferAbortSendEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
139
140 if (uartPrivateHandle->handle->callback)
141 {
142 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle, kStatus_UART_TxIdle,
143 uartPrivateHandle->handle->userData);
144 }
145 }
146 }
147
UART_ReceiveEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)148 static void UART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
149 {
150 assert(param);
151
152 uart_edma_private_handle_t *uartPrivateHandle = (uart_edma_private_handle_t *)param;
153
154 /* Avoid warning for unused parameters. */
155 handle = handle;
156 tcds = tcds;
157
158 if (transferDone)
159 {
160 /* Disable transfer. */
161 UART_TransferAbortReceiveEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
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 }
170
UART_TransferCreateHandleEDMA(UART_Type * base,uart_edma_handle_t * handle,uart_edma_transfer_callback_t callback,void * userData,edma_handle_t * txEdmaHandle,edma_handle_t * rxEdmaHandle)171 void UART_TransferCreateHandleEDMA(UART_Type *base,
172 uart_edma_handle_t *handle,
173 uart_edma_transfer_callback_t callback,
174 void *userData,
175 edma_handle_t *txEdmaHandle,
176 edma_handle_t *rxEdmaHandle)
177 {
178 assert(handle);
179
180 uint32_t instance = UART_GetInstance(base);
181
182 s_edmaPrivateHandle[instance].base = base;
183 s_edmaPrivateHandle[instance].handle = handle;
184
185 memset(handle, 0, sizeof(*handle));
186
187 handle->rxState = kUART_RxIdle;
188 handle->txState = kUART_TxIdle;
189
190 handle->rxEdmaHandle = rxEdmaHandle;
191 handle->txEdmaHandle = txEdmaHandle;
192
193 handle->callback = callback;
194 handle->userData = userData;
195
196 #if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
197 /* Note:
198 Take care of the RX FIFO, EDMA request only assert when received bytes
199 equal or more than RX water mark, there is potential issue if RX water
200 mark larger than 1.
201 For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
202 5 bytes are received. the last byte will be saved in FIFO but not trigger
203 EDMA transfer because the water mark is 2.
204 */
205 if (rxEdmaHandle)
206 {
207 base->RWFIFO = 1U;
208 }
209 #endif
210
211 /* Configure TX. */
212 if (txEdmaHandle)
213 {
214 EDMA_SetCallback(handle->txEdmaHandle, UART_SendEDMACallback, &s_edmaPrivateHandle[instance]);
215 }
216
217 /* Configure RX. */
218 if (rxEdmaHandle)
219 {
220 EDMA_SetCallback(handle->rxEdmaHandle, UART_ReceiveEDMACallback, &s_edmaPrivateHandle[instance]);
221 }
222 }
223
UART_SendEDMA(UART_Type * base,uart_edma_handle_t * handle,uart_transfer_t * xfer)224 status_t UART_SendEDMA(UART_Type *base, uart_edma_handle_t *handle, uart_transfer_t *xfer)
225 {
226 assert(handle);
227 assert(handle->txEdmaHandle);
228 assert(xfer);
229 assert(xfer->data);
230 assert(xfer->dataSize);
231
232 edma_transfer_config_t xferConfig;
233 status_t status;
234
235 /* If previous TX not finished. */
236 if (kUART_TxBusy == handle->txState)
237 {
238 status = kStatus_UART_TxBusy;
239 }
240 else
241 {
242 handle->txState = kUART_TxBusy;
243 handle->txDataSizeAll = xfer->dataSize;
244
245 /* Prepare transfer. */
246 EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t), (void *)UART_GetDataRegisterAddress(base),
247 sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_MemoryToPeripheral);
248
249 /* Store the initially configured eDMA minor byte transfer count into the UART handle */
250 handle->nbytes = sizeof(uint8_t);
251
252 /* Submit transfer. */
253 EDMA_SubmitTransfer(handle->txEdmaHandle, &xferConfig);
254 EDMA_StartTransfer(handle->txEdmaHandle);
255
256 /* Enable UART TX EDMA. */
257 UART_EnableTxDMA(base, true);
258
259 status = kStatus_Success;
260 }
261
262 return status;
263 }
264
UART_ReceiveEDMA(UART_Type * base,uart_edma_handle_t * handle,uart_transfer_t * xfer)265 status_t UART_ReceiveEDMA(UART_Type *base, uart_edma_handle_t *handle, uart_transfer_t *xfer)
266 {
267 assert(handle);
268 assert(handle->rxEdmaHandle);
269 assert(xfer);
270 assert(xfer->data);
271 assert(xfer->dataSize);
272
273 edma_transfer_config_t xferConfig;
274 status_t status;
275
276 /* If previous RX not finished. */
277 if (kUART_RxBusy == handle->rxState)
278 {
279 status = kStatus_UART_RxBusy;
280 }
281 else
282 {
283 handle->rxState = kUART_RxBusy;
284 handle->rxDataSizeAll = xfer->dataSize;
285
286 /* Prepare transfer. */
287 EDMA_PrepareTransfer(&xferConfig, (void *)UART_GetDataRegisterAddress(base), sizeof(uint8_t), xfer->data,
288 sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
289
290 /* Store the initially configured eDMA minor byte transfer count into the UART handle */
291 handle->nbytes = sizeof(uint8_t);
292
293 /* Submit transfer. */
294 EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
295 EDMA_StartTransfer(handle->rxEdmaHandle);
296
297 /* Enable UART RX EDMA. */
298 UART_EnableRxDMA(base, true);
299
300 status = kStatus_Success;
301 }
302
303 return status;
304 }
305
UART_TransferAbortSendEDMA(UART_Type * base,uart_edma_handle_t * handle)306 void UART_TransferAbortSendEDMA(UART_Type *base, uart_edma_handle_t *handle)
307 {
308 assert(handle);
309 assert(handle->txEdmaHandle);
310
311 /* Disable UART TX EDMA. */
312 UART_EnableTxDMA(base, false);
313
314 /* Stop transfer. */
315 EDMA_AbortTransfer(handle->txEdmaHandle);
316
317 handle->txState = kUART_TxIdle;
318 }
319
UART_TransferAbortReceiveEDMA(UART_Type * base,uart_edma_handle_t * handle)320 void UART_TransferAbortReceiveEDMA(UART_Type *base, uart_edma_handle_t *handle)
321 {
322 assert(handle);
323 assert(handle->rxEdmaHandle);
324
325 /* Disable UART RX EDMA. */
326 UART_EnableRxDMA(base, false);
327
328 /* Stop transfer. */
329 EDMA_AbortTransfer(handle->rxEdmaHandle);
330
331 handle->rxState = kUART_RxIdle;
332 }
333
UART_TransferGetReceiveCountEDMA(UART_Type * base,uart_edma_handle_t * handle,uint32_t * count)334 status_t UART_TransferGetReceiveCountEDMA(UART_Type *base, uart_edma_handle_t *handle, uint32_t *count)
335 {
336 assert(handle);
337 assert(handle->rxEdmaHandle);
338 assert(count);
339
340 if (kUART_RxIdle == handle->rxState)
341 {
342 return kStatus_NoTransferInProgress;
343 }
344
345 *count = handle->rxDataSizeAll -
346 (uint32_t)handle->nbytes *
347 EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel);
348
349 return kStatus_Success;
350 }
351
UART_TransferGetSendCountEDMA(UART_Type * base,uart_edma_handle_t * handle,uint32_t * count)352 status_t UART_TransferGetSendCountEDMA(UART_Type *base, uart_edma_handle_t *handle, uint32_t *count)
353 {
354 assert(handle);
355 assert(handle->txEdmaHandle);
356 assert(count);
357
358 if (kUART_TxIdle == handle->txState)
359 {
360 return kStatus_NoTransferInProgress;
361 }
362
363 *count = handle->txDataSizeAll -
364 (uint32_t)handle->nbytes *
365 EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel);
366
367 return kStatus_Success;
368 }
369