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