1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2019 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_spifi_dma.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.spifi_dma"
18 #endif
19
20 /*<! Structure definition for spifi_dma_private_handle_t. The structure is private. */
21 typedef struct _spifi_dma_private_handle
22 {
23 SPIFI_Type *base;
24 spifi_dma_handle_t *handle;
25 } spifi_dma_private_handle_t;
26
27 /* SPIFI DMA transfer handle. */
28 enum
29 {
30 kSPIFI_Idle, /* TX idle. */
31 kSPIFI_BusBusy /* RX busy. */
32 };
33
34 /*******************************************************************************
35 * Variables
36 ******************************************************************************/
37
38 /*<! Private handle only used for internally. */
39 static spifi_dma_private_handle_t s_dmaPrivateHandle[FSL_FEATURE_SOC_SPIFI_COUNT][2];
40
41 /*******************************************************************************
42 * Prototypes
43 ******************************************************************************/
44
45 /*!
46 * @brief SPIFI DMA send finished callback function.
47 *
48 * This function is called when SPIFI DMA send finished. It disables the SPIFI
49 * TX DMA request and sends @ref kStatus_SPIFI_TxIdle to SPIFI callback.
50 *
51 * @param handle The DMA handle.
52 * @param param Callback function parameter.
53 */
54 static void SPIFI_SendDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t intmode);
55
56 /*!
57 * @brief SPIFI DMA receive finished callback function.
58 *
59 * This function is called when SPIFI DMA receive finished. It disables the SPIFI
60 * RX DMA request and sends @ref kStatus_SPIFI_RxIdle to SPIFI callback.
61 *
62 * @param handle The DMA handle.
63 * @param param Callback function parameter.
64 */
65 static void SPIFI_ReceiveDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t intmode);
66
67 /*******************************************************************************
68 * Code
69 ******************************************************************************/
70
SPIFI_SendDMACallback(dma_handle_t * handle,void * param,bool transferDone,uint32_t intmode)71 static void SPIFI_SendDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t intmode)
72 {
73 spifi_dma_private_handle_t *spifiPrivateHandle = (spifi_dma_private_handle_t *)param;
74
75 /* Avoid the warning for unused variables. */
76 handle = handle;
77 intmode = intmode;
78
79 if (transferDone)
80 {
81 SPIFI_TransferAbortSendDMA(spifiPrivateHandle->base, spifiPrivateHandle->handle);
82
83 if (spifiPrivateHandle->handle->callback != NULL)
84 {
85 spifiPrivateHandle->handle->callback(spifiPrivateHandle->base, spifiPrivateHandle->handle,
86 kStatus_SPIFI_Idle, spifiPrivateHandle->handle->userData);
87 }
88 }
89 }
90
SPIFI_ReceiveDMACallback(dma_handle_t * handle,void * param,bool transferDone,uint32_t intmode)91 static void SPIFI_ReceiveDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t intmode)
92 {
93 spifi_dma_private_handle_t *spifiPrivateHandle = (spifi_dma_private_handle_t *)param;
94
95 /* Avoid warning for unused parameters. */
96 handle = handle;
97 intmode = intmode;
98
99 if (transferDone)
100 {
101 /* Disable transfer. */
102 SPIFI_TransferAbortReceiveDMA(spifiPrivateHandle->base, spifiPrivateHandle->handle);
103
104 if (spifiPrivateHandle->handle->callback != NULL)
105 {
106 spifiPrivateHandle->handle->callback(spifiPrivateHandle->base, spifiPrivateHandle->handle,
107 kStatus_SPIFI_Idle, spifiPrivateHandle->handle->userData);
108 }
109 }
110 }
111
112 /*!
113 * brief Initializes the SPIFI handle for send which is used in transactional functions and set the callback.
114 *
115 * param base SPIFI peripheral base address
116 * param handle Pointer to spifi_dma_handle_t structure
117 * param callback SPIFI callback, NULL means no callback.
118 * param userData User callback function data.
119 * param rxDmaHandle User requested DMA handle for DMA transfer
120 */
SPIFI_TransferTxCreateHandleDMA(SPIFI_Type * base,spifi_dma_handle_t * handle,spifi_dma_callback_t callback,void * userData,dma_handle_t * dmaHandle)121 void SPIFI_TransferTxCreateHandleDMA(SPIFI_Type *base,
122 spifi_dma_handle_t *handle,
123 spifi_dma_callback_t callback,
124 void *userData,
125 dma_handle_t *dmaHandle)
126 {
127 assert(handle != NULL);
128
129 uint32_t instance = SPIFI_GetInstance(base);
130
131 s_dmaPrivateHandle[instance][0].base = base;
132 s_dmaPrivateHandle[instance][0].handle = handle;
133
134 (void)memset(handle, 0, sizeof(*handle));
135
136 handle->state = kSPIFI_Idle;
137 handle->dmaHandle = dmaHandle;
138
139 handle->callback = callback;
140 handle->userData = userData;
141
142 /* Configure TX dma callback */
143 DMA_SetCallback(handle->dmaHandle, SPIFI_SendDMACallback, &s_dmaPrivateHandle[instance][0]);
144 }
145
146 /*!
147 * brief Initializes the SPIFI handle for receive which is used in transactional functions and set the callback.
148 *
149 * param base SPIFI peripheral base address
150 * param handle Pointer to spifi_dma_handle_t structure
151 * param callback SPIFI callback, NULL means no callback.
152 * param userData User callback function data.
153 * param rxDmaHandle User requested DMA handle for DMA transfer
154 */
SPIFI_TransferRxCreateHandleDMA(SPIFI_Type * base,spifi_dma_handle_t * handle,spifi_dma_callback_t callback,void * userData,dma_handle_t * dmaHandle)155 void SPIFI_TransferRxCreateHandleDMA(SPIFI_Type *base,
156 spifi_dma_handle_t *handle,
157 spifi_dma_callback_t callback,
158 void *userData,
159 dma_handle_t *dmaHandle)
160 {
161 assert(handle != NULL);
162
163 uint32_t instance = SPIFI_GetInstance(base);
164
165 s_dmaPrivateHandle[instance][1].base = base;
166 s_dmaPrivateHandle[instance][1].handle = handle;
167
168 (void)memset(handle, 0, sizeof(*handle));
169
170 handle->state = kSPIFI_Idle;
171 handle->dmaHandle = dmaHandle;
172
173 handle->callback = callback;
174 handle->userData = userData;
175
176 /* Configure RX dma callback */
177 DMA_SetCallback(handle->dmaHandle, SPIFI_ReceiveDMACallback, &s_dmaPrivateHandle[instance][1]);
178 }
179
180 /*!
181 * brief Transfers SPIFI data using an DMA non-blocking method.
182 *
183 * This function writes data to the SPIFI transmit FIFO. This function is non-blocking.
184 * param base Pointer to QuadSPI Type.
185 * param handle Pointer to spifi_dma_handle_t structure
186 * param xfer SPIFI transfer structure.
187 */
SPIFI_TransferSendDMA(SPIFI_Type * base,spifi_dma_handle_t * handle,spifi_transfer_t * xfer)188 status_t SPIFI_TransferSendDMA(SPIFI_Type *base, spifi_dma_handle_t *handle, spifi_transfer_t *xfer)
189 {
190 assert(handle != NULL);
191 assert(handle->dmaHandle != NULL);
192
193 dma_transfer_config_t xferConfig;
194 status_t status;
195
196 /* If previous TX not finished. */
197 if ((uint32_t)kSPIFI_BusBusy == handle->state)
198 {
199 status = kStatus_SPIFI_Busy;
200 }
201 else
202 {
203 handle->state = kSPIFI_BusBusy;
204
205 /* Prepare transfer. */
206 DMA_PrepareTransfer(&xferConfig, xfer->data, (uint32_t *)SPIFI_GetDataRegisterAddress(base), sizeof(uint32_t),
207 xfer->dataSize, kDMA_MemoryToPeripheral, NULL);
208
209 /* Submit transfer. */
210 (void)DMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
211 DMA_StartTransfer(handle->dmaHandle);
212
213 /* Enable SPIFI TX DMA. */
214 SPIFI_EnableDMA(base, true);
215
216 status = kStatus_Success;
217 }
218
219 return status;
220 }
221
222 /*!
223 * brief Receives data using an DMA non-blocking method.
224 *
225 * This function receive data from the SPIFI receive buffer/FIFO. This function is non-blocking.
226 * param base Pointer to QuadSPI Type.
227 * param handle Pointer to spifi_dma_handle_t structure
228 * param xfer SPIFI transfer structure.
229 */
SPIFI_TransferReceiveDMA(SPIFI_Type * base,spifi_dma_handle_t * handle,spifi_transfer_t * xfer)230 status_t SPIFI_TransferReceiveDMA(SPIFI_Type *base, spifi_dma_handle_t *handle, spifi_transfer_t *xfer)
231 {
232 assert(handle != NULL);
233 assert(handle->dmaHandle != NULL);
234
235 dma_transfer_config_t xferConfig;
236 status_t status;
237
238 /* If previous TX not finished. */
239 if ((uint32_t)kSPIFI_BusBusy == handle->state)
240 {
241 status = kStatus_SPIFI_Busy;
242 }
243 else
244 {
245 handle->state = kSPIFI_BusBusy;
246
247 /* Prepare transfer. */
248 DMA_PrepareTransfer(&xferConfig, (uint32_t *)SPIFI_GetDataRegisterAddress(base), xfer->data, sizeof(uint32_t),
249 xfer->dataSize, kDMA_PeripheralToMemory, NULL);
250
251 /* Submit transfer. */
252 (void)DMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
253 DMA_StartTransfer(handle->dmaHandle);
254
255 /* Enable SPIFI TX DMA. */
256 SPIFI_EnableDMA(base, true);
257
258 status = kStatus_Success;
259 }
260
261 return status;
262 }
263
264 /*!
265 * brief Aborts the sent data using DMA.
266 *
267 * This function aborts the sent data using DMA.
268 *
269 * param base SPIFI peripheral base address.
270 * param handle Pointer to spifi_dma_handle_t structure
271 */
SPIFI_TransferAbortSendDMA(SPIFI_Type * base,spifi_dma_handle_t * handle)272 void SPIFI_TransferAbortSendDMA(SPIFI_Type *base, spifi_dma_handle_t *handle)
273 {
274 assert(handle != NULL);
275 assert(handle->dmaHandle != NULL);
276
277 /* Disable SPIFI TX DMA. */
278 SPIFI_EnableDMA(base, false);
279
280 /* Stop transfer. */
281 DMA_AbortTransfer(handle->dmaHandle);
282
283 handle->state = kSPIFI_Idle;
284 }
285
286 /*!
287 * brief Aborts the receive data using DMA.
288 *
289 * This function abort receive data which using DMA.
290 *
291 * param base SPIFI peripheral base address.
292 * param handle Pointer to spifi_dma_handle_t structure
293 */
SPIFI_TransferAbortReceiveDMA(SPIFI_Type * base,spifi_dma_handle_t * handle)294 void SPIFI_TransferAbortReceiveDMA(SPIFI_Type *base, spifi_dma_handle_t *handle)
295 {
296 assert(handle != NULL);
297 assert(handle->dmaHandle != NULL);
298
299 /* Disable SPIFI RX DMA. */
300 SPIFI_EnableDMA(base, false);
301
302 /* Stop transfer. */
303 DMA_AbortTransfer(handle->dmaHandle);
304
305 handle->state = kSPIFI_Idle;
306 }
307
308 /*!
309 * brief Gets the transferred counts of send.
310 *
311 * param base Pointer to QuadSPI Type.
312 * param handle Pointer to spifi_dma_handle_t structure.
313 * param count Bytes sent.
314 * retval kStatus_Success Succeed get the transfer count.
315 * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
316 */
SPIFI_TransferGetSendCountDMA(SPIFI_Type * base,spifi_dma_handle_t * handle,size_t * count)317 status_t SPIFI_TransferGetSendCountDMA(SPIFI_Type *base, spifi_dma_handle_t *handle, size_t *count)
318 {
319 assert(handle != NULL);
320 assert(handle->dmaHandle != NULL);
321
322 status_t status = kStatus_Success;
323
324 if (handle->state != (uint32_t)kSPIFI_BusBusy)
325 {
326 status = kStatus_NoTransferInProgress;
327 }
328 else
329 {
330 *count = handle->transferSize - DMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel);
331 }
332
333 return status;
334 }
335
336 /*!
337 * brief Gets the status of the receive transfer.
338 *
339 * param base Pointer to QuadSPI Type.
340 * param handle Pointer to spifi_dma_handle_t structure
341 * param count Bytes received.
342 * retval kStatus_Success Succeed get the transfer count.
343 * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
344 */
SPIFI_TransferGetReceiveCountDMA(SPIFI_Type * base,spifi_dma_handle_t * handle,size_t * count)345 status_t SPIFI_TransferGetReceiveCountDMA(SPIFI_Type *base, spifi_dma_handle_t *handle, size_t *count)
346 {
347 assert(handle != NULL);
348 assert(handle->dmaHandle != NULL);
349
350 status_t status = kStatus_Success;
351
352 if (handle->state != (uint32_t)kSPIFI_BusBusy)
353 {
354 status = kStatus_NoTransferInProgress;
355 }
356 else
357 {
358 *count = handle->transferSize - DMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel);
359 }
360
361 return status;
362 }
363