1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_qspi_edma.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.qspi_edma"
18 #endif
19
20 /*<! Structure definition for qspi_edma_private_handle_t. The structure is private. */
21 typedef struct _qspi_edma_private_handle
22 {
23 QuadSPI_Type *base;
24 qspi_edma_handle_t *handle;
25 } qspi_edma_private_handle_t;
26
27 /* QSPI EDMA transfer handle. */
28 enum _qspi_edma_tansfer_states
29 {
30 kQSPI_Idle, /* TX idle. */
31 kQSPI_BusBusy /* RX busy. */
32 };
33
34 /*!
35 * @brief Used for conversion between `void*` and `uint32_t`.
36 */
37 typedef union pvoid_to_u32
38 {
39 void *pvoid;
40 uint32_t u32;
41 } pvoid_to_u32_t;
42
43 /*******************************************************************************
44 * Variables
45 ******************************************************************************/
46
47 /*<! Private handle only used for internally. */
48 static qspi_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_QuadSPI_COUNT][2];
49
50 /*******************************************************************************
51 * Prototypes
52 ******************************************************************************/
53
54 /*!
55 * @brief QSPI EDMA send finished callback function.
56 *
57 * This function is called when QSPI EDMA send finished. It disables the QSPI
58 * TX EDMA request and sends @ref kStatus_QSPI_TxIdle to QSPI callback.
59 *
60 * @param handle The EDMA handle.
61 * @param param Callback function parameter.
62 */
63 static void QSPI_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
64
65 /*!
66 * @brief QSPI EDMA receive finished callback function.
67 *
68 * This function is called when QSPI EDMA receive finished. It disables the QSPI
69 * RX EDMA request and sends @ref kStatus_QSPI_RxIdle to QSPI callback.
70 *
71 * @param handle The EDMA handle.
72 * @param param Callback function parameter.
73 */
74 static void QSPI_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
75
76 /*******************************************************************************
77 * Code
78 ******************************************************************************/
79
QSPI_SendEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)80 static void QSPI_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
81 {
82 qspi_edma_private_handle_t *qspiPrivateHandle = (qspi_edma_private_handle_t *)param;
83
84 /* Avoid the warning for unused variables. */
85 handle = handle;
86 tcds = tcds;
87
88 if (transferDone)
89 {
90 QSPI_TransferAbortSendEDMA(qspiPrivateHandle->base, qspiPrivateHandle->handle);
91
92 if (NULL != qspiPrivateHandle->handle->callback)
93 {
94 qspiPrivateHandle->handle->callback(qspiPrivateHandle->base, qspiPrivateHandle->handle, kStatus_QSPI_Idle,
95 qspiPrivateHandle->handle->userData);
96 }
97 }
98 }
99
QSPI_ReceiveEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)100 static void QSPI_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
101 {
102 qspi_edma_private_handle_t *qspiPrivateHandle = (qspi_edma_private_handle_t *)param;
103
104 /* Avoid warning for unused parameters. */
105 handle = handle;
106 tcds = tcds;
107
108 if (transferDone)
109 {
110 /* Disable transfer. */
111 QSPI_TransferAbortReceiveEDMA(qspiPrivateHandle->base, qspiPrivateHandle->handle);
112
113 if (NULL != qspiPrivateHandle->handle->callback)
114 {
115 qspiPrivateHandle->handle->callback(qspiPrivateHandle->base, qspiPrivateHandle->handle, kStatus_QSPI_Idle,
116 qspiPrivateHandle->handle->userData);
117 }
118 }
119 }
120
121 /*!
122 * brief Initializes the QSPI handle for send which is used in transactional functions and set the callback.
123 *
124 * param base QSPI peripheral base address
125 * param handle Pointer to qspi_edma_handle_t structure
126 * param callback QSPI callback, NULL means no callback.
127 * param userData User callback function data.
128 * param rxDmaHandle User requested eDMA handle for eDMA transfer
129 */
QSPI_TransferTxCreateHandleEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle,qspi_edma_callback_t callback,void * userData,edma_handle_t * dmaHandle)130 void QSPI_TransferTxCreateHandleEDMA(QuadSPI_Type *base,
131 qspi_edma_handle_t *handle,
132 qspi_edma_callback_t callback,
133 void *userData,
134 edma_handle_t *dmaHandle)
135 {
136 assert(handle);
137
138 uint32_t instance = QSPI_GetInstance(base);
139
140 s_edmaPrivateHandle[instance][0].base = base;
141 s_edmaPrivateHandle[instance][0].handle = handle;
142
143 (void)memset(handle, 0, sizeof(*handle));
144
145 handle->state = (uint32_t)kQSPI_Idle;
146 handle->dmaHandle = dmaHandle;
147
148 handle->callback = callback;
149 handle->userData = userData;
150
151 /* Get the watermark value */
152 handle->count = (uint8_t)base->TBCT + 1U;
153
154 /* Configure TX edma callback */
155 EDMA_SetCallback(handle->dmaHandle, QSPI_SendEDMACallback, &s_edmaPrivateHandle[instance][0]);
156 }
157
158 /*!
159 * brief Initializes the QSPI handle for receive which is used in transactional functions and set the callback.
160 *
161 * param base QSPI peripheral base address
162 * param handle Pointer to qspi_edma_handle_t structure
163 * param callback QSPI callback, NULL means no callback.
164 * param userData User callback function data.
165 * param rxDmaHandle User requested eDMA handle for eDMA transfer
166 */
QSPI_TransferRxCreateHandleEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle,qspi_edma_callback_t callback,void * userData,edma_handle_t * dmaHandle)167 void QSPI_TransferRxCreateHandleEDMA(QuadSPI_Type *base,
168 qspi_edma_handle_t *handle,
169 qspi_edma_callback_t callback,
170 void *userData,
171 edma_handle_t *dmaHandle)
172 {
173 assert(handle);
174
175 uint32_t instance = QSPI_GetInstance(base);
176
177 s_edmaPrivateHandle[instance][1].base = base;
178 s_edmaPrivateHandle[instance][1].handle = handle;
179
180 (void)memset(handle, 0, sizeof(*handle));
181
182 handle->state = (uint32_t)kQSPI_Idle;
183 handle->dmaHandle = dmaHandle;
184
185 handle->callback = callback;
186 handle->userData = userData;
187
188 /* Get the watermark value */
189 handle->count = ((uint8_t)base->RBCT & QuadSPI_RBCT_WMRK_MASK) + 1U;
190
191 /* Configure RX edma callback */
192 EDMA_SetCallback(handle->dmaHandle, QSPI_ReceiveEDMACallback, &s_edmaPrivateHandle[instance][1]);
193 }
194
195 /*!
196 * brief Transfers QSPI data using an eDMA non-blocking method.
197 *
198 * This function writes data to the QSPI transmit FIFO. This function is non-blocking.
199 * param base Pointer to QuadSPI Type.
200 * param handle Pointer to qspi_edma_handle_t structure
201 * param xfer QSPI transfer structure.
202 */
QSPI_TransferSendEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle,qspi_transfer_t * xfer)203 status_t QSPI_TransferSendEDMA(QuadSPI_Type *base, qspi_edma_handle_t *handle, qspi_transfer_t *xfer)
204 {
205 assert(handle && (handle->dmaHandle));
206
207 edma_transfer_config_t xferConfig;
208 status_t status;
209 pvoid_to_u32_t destAddr;
210
211 /* If previous TX not finished. */
212 if ((uint8_t)kQSPI_BusBusy == handle->state)
213 {
214 status = kStatus_QSPI_Busy;
215 }
216 else
217 {
218 handle->state = (uint32_t)kQSPI_BusBusy;
219
220 destAddr.u32 = QSPI_GetTxDataRegisterAddress(base);
221 /* Prepare transfer. */
222 EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint32_t), destAddr.pvoid, sizeof(uint32_t),
223 (sizeof(uint32_t) * (uint32_t)handle->count), xfer->dataSize, kEDMA_MemoryToPeripheral);
224
225 /* Store the initially configured eDMA minor byte transfer count into the QSPI handle */
226 handle->nbytes = (sizeof(uint32_t) * handle->count);
227
228 /* Submit transfer. */
229 do
230 {
231 status = EDMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
232 } while (status != kStatus_Success);
233
234 EDMA_StartTransfer(handle->dmaHandle);
235
236 /* Enable QSPI TX EDMA. */
237 QSPI_EnableDMA(base, (uint32_t)kQSPI_TxBufferFillDMAEnable, true);
238
239 status = kStatus_Success;
240 }
241
242 return status;
243 }
244
245 /*!
246 * brief Receives data using an eDMA non-blocking method.
247 *
248 * This function receive data from the QSPI receive buffer/FIFO. This function is non-blocking. Users shall notice that
249 * this receive size shall not bigger than 64 bytes. As this interface is used to read flash status registers.
250 * For flash contents read, please use AHB bus read, this is much more efficiency.
251 *
252 * param base Pointer to QuadSPI Type.
253 * param handle Pointer to qspi_edma_handle_t structure
254 * param xfer QSPI transfer structure.
255 */
QSPI_TransferReceiveEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle,qspi_transfer_t * xfer)256 status_t QSPI_TransferReceiveEDMA(QuadSPI_Type *base, qspi_edma_handle_t *handle, qspi_transfer_t *xfer)
257 {
258 assert(handle && (handle->dmaHandle));
259
260 edma_transfer_config_t xferConfig;
261 status_t status;
262 pvoid_to_u32_t srcAddr;
263
264 /* If previous TX not finished. */
265 if ((uint32_t)kQSPI_BusBusy == handle->state)
266 {
267 status = kStatus_QSPI_Busy;
268 }
269 else
270 {
271 handle->state = (uint32_t)kQSPI_BusBusy;
272
273 srcAddr.u32 = QSPI_GetRxDataRegisterAddress(base);
274 /* Prepare transfer. */
275 EDMA_PrepareTransfer(&xferConfig, srcAddr.pvoid, sizeof(uint32_t), xfer->data, sizeof(uint32_t),
276 (sizeof(uint32_t) * (uint32_t)handle->count), xfer->dataSize, kEDMA_MemoryToMemory);
277
278 /* Store the initially configured eDMA minor byte transfer count into the QSPI handle */
279 handle->nbytes = (sizeof(uint32_t) * handle->count);
280 /* Submit transfer. */
281 do
282 {
283 status = EDMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
284 } while (status != kStatus_Success);
285
286 handle->dmaHandle->base->TCD[handle->dmaHandle->channel].ATTR |= DMA_ATTR_SMOD(0x5U);
287 EDMA_StartTransfer(handle->dmaHandle);
288
289 /* Enable QSPI TX EDMA. */
290 QSPI_EnableDMA(base, (uint32_t)kQSPI_RxBufferDrainDMAEnable, true);
291
292 status = kStatus_Success;
293 }
294
295 return status;
296 }
297
298 /*!
299 * brief Aborts the sent data using eDMA.
300 *
301 * This function aborts the sent data using eDMA.
302 *
303 * param base QSPI peripheral base address.
304 * param handle Pointer to qspi_edma_handle_t structure
305 */
QSPI_TransferAbortSendEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle)306 void QSPI_TransferAbortSendEDMA(QuadSPI_Type *base, qspi_edma_handle_t *handle)
307 {
308 assert(handle && (handle->dmaHandle));
309
310 /* Disable QSPI TX EDMA. */
311 QSPI_EnableDMA(base, (uint32_t)kQSPI_TxBufferFillDMAEnable, false);
312
313 /* Stop transfer. */
314 EDMA_AbortTransfer(handle->dmaHandle);
315
316 handle->state = (uint32_t)kQSPI_Idle;
317 }
318
319 /*!
320 * brief Aborts the receive data using eDMA.
321 *
322 * This function abort receive data which using eDMA.
323 *
324 * param base QSPI peripheral base address.
325 * param handle Pointer to qspi_edma_handle_t structure
326 */
QSPI_TransferAbortReceiveEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle)327 void QSPI_TransferAbortReceiveEDMA(QuadSPI_Type *base, qspi_edma_handle_t *handle)
328 {
329 assert(handle && (handle->dmaHandle));
330
331 /* Disable QSPI RX EDMA. */
332 QSPI_EnableDMA(base, (uint32_t)kQSPI_RxBufferDrainDMAEnable, false);
333
334 /* Stop transfer. */
335 EDMA_AbortTransfer(handle->dmaHandle);
336
337 handle->state = (uint32_t)kQSPI_Idle;
338 }
339
340 /*!
341 * brief Gets the transferred counts of send.
342 *
343 * param base Pointer to QuadSPI Type.
344 * param handle Pointer to qspi_edma_handle_t structure.
345 * param count Bytes sent.
346 * retval kStatus_Success Succeed get the transfer count.
347 * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
348 */
QSPI_TransferGetSendCountEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle,size_t * count)349 status_t QSPI_TransferGetSendCountEDMA(QuadSPI_Type *base, qspi_edma_handle_t *handle, size_t *count)
350 {
351 assert(handle);
352
353 status_t status = kStatus_Success;
354
355 if (handle->state != (uint32_t)kQSPI_BusBusy)
356 {
357 status = kStatus_NoTransferInProgress;
358 }
359 else
360 {
361 *count = (handle->transferSize -
362 (uint32_t)handle->nbytes *
363 EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
364 }
365
366 return status;
367 }
368
369 /*!
370 * brief Gets the status of the receive transfer.
371 *
372 * param base Pointer to QuadSPI Type.
373 * param handle Pointer to qspi_edma_handle_t structure
374 * param count Bytes received.
375 * retval kStatus_Success Succeed get the transfer count.
376 * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
377 */
QSPI_TransferGetReceiveCountEDMA(QuadSPI_Type * base,qspi_edma_handle_t * handle,size_t * count)378 status_t QSPI_TransferGetReceiveCountEDMA(QuadSPI_Type *base, qspi_edma_handle_t *handle, size_t *count)
379 {
380 assert(handle);
381
382 status_t status = kStatus_Success;
383
384 if (handle->state != (uint32_t)kQSPI_BusBusy)
385 {
386 status = kStatus_NoTransferInProgress;
387 }
388 else
389 {
390 *count = (handle->transferSize -
391 (uint32_t)handle->nbytes *
392 EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
393 }
394
395 return status;
396 }
397