1 /*
2 * Copyright 2016-2020 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_uart_sdma.h"
8
9 /*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.iuart_sdma"
16 #endif
17
18 /*<! Structure definition for uart_sdma_private_handle_t. The structure is private. */
19 typedef struct _uart_sdma_private_handle
20 {
21 UART_Type *base;
22 uart_sdma_handle_t *handle;
23 } uart_sdma_private_handle_t;
24
25 /* UART SDMA transfer handle. */
26 enum _uart_sdma_tansfer_states
27 {
28 kUART_TxIdle, /* TX idle. */
29 kUART_TxBusy, /* TX busy. */
30 kUART_RxIdle, /* RX idle. */
31 kUART_RxBusy /* RX busy. */
32 };
33
34 /*******************************************************************************
35 * Variables
36 ******************************************************************************/
37
38 /*<! Private handle only used for internally. */
39 static UART_Type *const s_uartSdmaBases[] = UART_BASE_PTRS;
40 static uart_sdma_private_handle_t s_sdmaPrivateHandle[ARRAY_SIZE(s_uartSdmaBases)];
41
42 /*******************************************************************************
43 * Prototypes
44 ******************************************************************************/
45
46 /*!
47 * @brief UART SDMA send finished callback function.
48 *
49 * This function is called when UART SDMA send finished. It disables the UART
50 * TX SDMA request and sends @ref kStatus_UART_TxIdle to UART callback.
51 *
52 * @param handle The SDMA handle.
53 * @param param Callback function parameter.
54 */
55 static void UART_SendSDMACallback(sdma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
56
57 /*!
58 * @brief UART SDMA receive finished callback function.
59 *
60 * This function is called when UART SDMA receive finished. It disables the UART
61 * RX SDMA request and sends @ref kStatus_UART_RxIdle to UART callback.
62 *
63 * @param handle The SDMA handle.
64 * @param param Callback function parameter.
65 */
66 static void UART_ReceiveSDMACallback(sdma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
67
68 /*******************************************************************************
69 * Code
70 ******************************************************************************/
71
UART_SendSDMACallback(sdma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)72 static void UART_SendSDMACallback(sdma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
73 {
74 assert(param != NULL);
75
76 uart_sdma_private_handle_t *uartPrivateHandle = (uart_sdma_private_handle_t *)param;
77
78 if (transferDone)
79 {
80 /* Disable UART TX SDMA. */
81 UART_EnableTxDMA(uartPrivateHandle->base, false);
82
83 /* Stop transfer. */
84 SDMA_AbortTransfer(handle);
85
86 /* Enable tx empty interrupt */
87 UART_EnableInterrupts(uartPrivateHandle->base, (uint32_t)kUART_TxEmptyEnable);
88 }
89 }
90
UART_ReceiveSDMACallback(sdma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)91 static void UART_ReceiveSDMACallback(sdma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
92 {
93 assert(param != NULL);
94
95 uart_sdma_private_handle_t *uartPrivateHandle = (uart_sdma_private_handle_t *)param;
96
97 if (transferDone)
98 {
99 /* Disable transfer. */
100 UART_TransferAbortReceiveSDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
101
102 if (uartPrivateHandle->handle->callback != NULL)
103 {
104 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle, kStatus_UART_RxIdle,
105 uartPrivateHandle->handle->userData);
106 }
107 }
108 }
109
110 /*!
111 * brief Initializes the UART handle which is used in transactional functions.
112 * param base UART peripheral base address.
113 * param handle Pointer to the uart_sdma_handle_t structure.
114 * param callback UART callback, NULL means no callback.
115 * param userData User callback function data.
116 * param rxSdmaHandle User-requested DMA handle for RX DMA transfer.
117 * param txSdmaHandle User-requested DMA handle for TX DMA transfer.
118 * param eventSourceTx Eventsource for TX DMA transfer.
119 * param eventSourceRx Eventsource for RX DMA transfer.
120 */
UART_TransferCreateHandleSDMA(UART_Type * base,uart_sdma_handle_t * handle,uart_sdma_transfer_callback_t callback,void * userData,sdma_handle_t * txSdmaHandle,sdma_handle_t * rxSdmaHandle,uint32_t eventSourceTx,uint32_t eventSourceRx)121 void UART_TransferCreateHandleSDMA(UART_Type *base,
122 uart_sdma_handle_t *handle,
123 uart_sdma_transfer_callback_t callback,
124 void *userData,
125 sdma_handle_t *txSdmaHandle,
126 sdma_handle_t *rxSdmaHandle,
127 uint32_t eventSourceTx,
128 uint32_t eventSourceRx)
129 {
130 assert(handle != NULL);
131
132 uint32_t instance = UART_GetInstance(base);
133
134 (void)memset(handle, 0, sizeof(*handle));
135
136 handle->rxState = (uint8_t)kUART_RxIdle;
137 handle->txState = (uint8_t)kUART_TxIdle;
138
139 if (rxSdmaHandle != NULL)
140 {
141 rxSdmaHandle->eventSource = eventSourceRx;
142 }
143
144 if (txSdmaHandle != NULL)
145 {
146 txSdmaHandle->eventSource = eventSourceTx;
147 }
148
149 handle->rxSdmaHandle = rxSdmaHandle;
150 handle->txSdmaHandle = txSdmaHandle;
151
152 handle->callback = callback;
153 handle->userData = userData;
154
155 s_sdmaPrivateHandle[instance].base = base;
156 s_sdmaPrivateHandle[instance].handle = handle;
157
158 /* Save the handle in global variables to support the double weak mechanism. */
159 s_uartHandle[instance] = handle;
160
161 s_uartIsr = UART_TransferSdmaHandleIRQ;
162
163 /* Enable interrupt in NVIC. */
164 (void)EnableIRQ(s_uartIRQ[instance]);
165
166 /* Configure TX. */
167 if (txSdmaHandle != NULL)
168 {
169 SDMA_SetCallback(handle->txSdmaHandle, UART_SendSDMACallback, &s_sdmaPrivateHandle[instance]);
170 }
171
172 /* Configure RX. */
173 if (rxSdmaHandle != NULL)
174 {
175 SDMA_SetCallback(handle->rxSdmaHandle, UART_ReceiveSDMACallback, &s_sdmaPrivateHandle[instance]);
176 }
177 }
178
179 /*!
180 * brief Sends data using sDMA.
181 *
182 * This function sends data using sDMA. This is a non-blocking function, which returns
183 * right away. When all data is sent, the send callback function is called.
184 *
185 * param base UART peripheral base address.
186 * param handle UART handle pointer.
187 * param xfer UART sDMA transfer structure. See #uart_transfer_t.
188 * retval kStatus_Success if succeeded; otherwise failed.
189 * retval kStatus_UART_TxBusy Previous transfer ongoing.
190 * retval kStatus_InvalidArgument Invalid argument.
191 */
UART_SendSDMA(UART_Type * base,uart_sdma_handle_t * handle,uart_transfer_t * xfer)192 status_t UART_SendSDMA(UART_Type *base, uart_sdma_handle_t *handle, uart_transfer_t *xfer)
193 {
194 assert(handle != NULL);
195 assert(handle->txSdmaHandle != NULL);
196 assert(xfer != NULL);
197 assert(xfer->data != NULL);
198 assert(xfer->dataSize != 0U);
199
200 sdma_transfer_config_t xferConfig = {0U};
201 status_t status;
202 sdma_peripheral_t perType = kSDMA_PeripheralTypeUART;
203
204 /* If previous TX not finished. */
205 if ((uint8_t)kUART_TxBusy == handle->txState)
206 {
207 status = kStatus_UART_TxBusy;
208 }
209 else
210 {
211 handle->txState = (uint8_t)kUART_TxBusy;
212 handle->txDataSizeAll = xfer->dataSize;
213
214 #if defined(FSL_FEATURE_SOC_SPBA_COUNT) && (FSL_FEATURE_SOC_SPBA_COUNT > 0)
215 bool isSpba = SDMA_IsPeripheralInSPBA((uint32_t)base);
216 /* Judge if the instance is located in SPBA */
217 if (isSpba)
218 {
219 perType = kSDMA_PeripheralTypeUART_SP;
220 }
221 #endif /* FSL_FEATURE_SOC_SPBA_COUNT */
222
223 /* Prepare transfer. */
224 SDMA_PrepareTransfer(&xferConfig, (uint32_t)xfer->data, (uint32_t) & (base->UTXD), sizeof(uint8_t),
225 sizeof(uint8_t), sizeof(uint8_t), (uint32_t)xfer->dataSize,
226 handle->txSdmaHandle->eventSource, perType, kSDMA_MemoryToPeripheral);
227
228 /* Submit transfer. */
229 SDMA_SubmitTransfer(handle->txSdmaHandle, &xferConfig);
230
231 SDMA_StartTransfer(handle->txSdmaHandle);
232
233 /* Enable UART TX SDMA. */
234 UART_EnableTxDMA(base, true);
235 status = kStatus_Success;
236 }
237
238 return status;
239 }
240
241 /*!
242 * brief Receives data using sDMA.
243 *
244 * This function receives data using sDMA. This is a non-blocking function, which returns
245 * right away. When all data is received, the receive callback function is called.
246 *
247 * param base UART peripheral base address.
248 * param handle Pointer to the uart_sdma_handle_t structure.
249 * param xfer UART sDMA transfer structure. See #uart_transfer_t.
250 * retval kStatus_Success if succeeded; otherwise failed.
251 * retval kStatus_UART_RxBusy Previous transfer ongoing.
252 * retval kStatus_InvalidArgument Invalid argument.
253 */
UART_ReceiveSDMA(UART_Type * base,uart_sdma_handle_t * handle,uart_transfer_t * xfer)254 status_t UART_ReceiveSDMA(UART_Type *base, uart_sdma_handle_t *handle, uart_transfer_t *xfer)
255 {
256 assert(handle != NULL);
257 assert(handle->rxSdmaHandle != NULL);
258 assert(xfer != NULL);
259 assert(xfer->data != NULL);
260 assert(xfer->dataSize != 0U);
261
262 sdma_transfer_config_t xferConfig = {0U};
263 status_t status;
264 sdma_peripheral_t perType = kSDMA_PeripheralTypeUART;
265
266 /* If previous RX not finished. */
267 if ((uint8_t)kUART_RxBusy == handle->rxState)
268 {
269 status = kStatus_UART_RxBusy;
270 }
271 else
272 {
273 handle->rxState = (uint8_t)kUART_RxBusy;
274 handle->rxDataSizeAll = xfer->dataSize;
275
276 #if defined(FSL_FEATURE_SOC_SPBA_COUNT) && (FSL_FEATURE_SOC_SPBA_COUNT > 0)
277 bool isSpba = SDMA_IsPeripheralInSPBA((uint32_t)base);
278 /* Judge if the instance is located in SPBA */
279 if (isSpba)
280 {
281 perType = kSDMA_PeripheralTypeUART_SP;
282 }
283 #endif /* FSL_FEATURE_SOC_SPBA_COUNT */
284
285 /* Prepare transfer. */
286 SDMA_PrepareTransfer(&xferConfig, (uint32_t) & (base->URXD), (uint32_t)xfer->data, sizeof(uint8_t),
287 sizeof(uint8_t), sizeof(uint8_t), (uint32_t)xfer->dataSize,
288 handle->rxSdmaHandle->eventSource, perType, kSDMA_PeripheralToMemory);
289
290 /* Submit transfer. */
291 SDMA_SubmitTransfer(handle->rxSdmaHandle, &xferConfig);
292
293 SDMA_StartTransfer(handle->rxSdmaHandle);
294
295 /* Enable UART RX SDMA. */
296 UART_EnableRxDMA(base, true);
297
298 status = kStatus_Success;
299 }
300
301 return status;
302 }
303
304 /*!
305 * brief Aborts the sent data using sDMA.
306 *
307 * This function aborts sent data using sDMA.
308 *
309 * param base UART peripheral base address.
310 * param handle Pointer to the uart_sdma_handle_t structure.
311 */
UART_TransferAbortSendSDMA(UART_Type * base,uart_sdma_handle_t * handle)312 void UART_TransferAbortSendSDMA(UART_Type *base, uart_sdma_handle_t *handle)
313 {
314 assert(handle != NULL);
315 assert(handle->txSdmaHandle != NULL);
316
317 /* Disable UART TX SDMA. */
318 UART_EnableTxDMA(base, false);
319
320 /* Stop transfer. */
321 SDMA_AbortTransfer(handle->txSdmaHandle);
322
323 handle->txState = (uint8_t)kUART_TxIdle;
324 }
325
326 /*!
327 * brief Aborts the receive data using sDMA.
328 *
329 * This function aborts receive data using sDMA.
330 *
331 * param base UART peripheral base address.
332 * param handle Pointer to the uart_sdma_handle_t structure.
333 */
UART_TransferAbortReceiveSDMA(UART_Type * base,uart_sdma_handle_t * handle)334 void UART_TransferAbortReceiveSDMA(UART_Type *base, uart_sdma_handle_t *handle)
335 {
336 assert(handle != NULL);
337 assert(handle->rxSdmaHandle != NULL);
338
339 /* Disable UART RX SDMA. */
340 UART_EnableRxDMA(base, false);
341
342 /* Stop transfer. */
343 SDMA_AbortTransfer(handle->rxSdmaHandle);
344
345 handle->rxState = (uint8_t)kUART_RxIdle;
346 }
347
348 /*!
349 * brief UART IRQ handle function.
350 *
351 * This function handles the UART transmit complete IRQ request and invoke user callback.
352 *
353 * param base UART peripheral base address.
354 * param uartSdmaHandle UART handle pointer.
355 */
UART_TransferSdmaHandleIRQ(UART_Type * base,void * uartSdmaHandle)356 void UART_TransferSdmaHandleIRQ(UART_Type *base, void *uartSdmaHandle)
357 {
358 assert(uartSdmaHandle != NULL);
359
360 uart_sdma_handle_t *handle = (uart_sdma_handle_t *)uartSdmaHandle;
361 handle->txState = (uint8_t)kUART_TxIdle;
362
363 /* Disable tx empty interrupt */
364 UART_DisableInterrupts(base, (uint32_t)kUART_TxEmptyEnable);
365
366 if (handle->callback != NULL)
367 {
368 handle->callback(base, handle, kStatus_UART_TxIdle, handle->userData);
369 }
370 }
371