1 /*
2 * Copyright (c) 2016, 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_flexspi_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.flexspi_edma"
18 #endif
19
20 /*<! Structure definition for flexspi_edma_private_handle_t. The structure is private. */
21 typedef struct _flexspi_edma_private_handle
22 {
23 FLEXSPI_Type *base;
24 flexspi_edma_handle_t *handle;
25 } flexspi_edma_private_handle_t;
26
27 /* FLEXSPI EDMA transfer handle, _flexspi_edma_tansfer_states. */
28 enum
29 {
30 kFLEXSPI_Idle, /* FLEXSPI Bus idle. */
31 kFLEXSPI_Busy /* FLEXSPI Bus busy. */
32 };
33
34 /*******************************************************************************
35 * Variables
36 ******************************************************************************/
37
38 /*! @brief Pointers to flexspi bases for each instance. */
39 static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;
40
41 /*<! Private handle only used for internally. */
42 static flexspi_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_flexspiBases)];
43
44 /*******************************************************************************
45 * Prototypes
46 ******************************************************************************/
47
48 /*!
49 * @brief FLEXSPI EDMA transfer finished callback function.
50 *
51 * This function is called when FLEXSPI EDMA transfer finished. It disables the FLEXSPI
52 * TX/RX EDMA request and sends status to FLEXSPI callback.
53 *
54 * @param handle The EDMA handle.
55 * @param param Callback function parameter.
56 */
57 static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
58
59 /*******************************************************************************
60 * Code
61 ******************************************************************************/
FLEXSPI_CalculatePower(uint8_t value)62 static uint8_t FLEXSPI_CalculatePower(uint8_t value)
63 {
64 uint8_t power = 0;
65 while (value >> 1 != 0U)
66 {
67 power++;
68 value = value >> 1;
69 }
70
71 return power;
72 }
FLEXSPI_TransferEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)73 static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
74 {
75 flexspi_edma_private_handle_t *flexspiPrivateHandle = (flexspi_edma_private_handle_t *)param;
76
77 /* Avoid warning for unused parameters. */
78 handle = handle;
79 tcds = tcds;
80
81 if (transferDone)
82 {
83 /* Wait for bus idle. */
84 while (!FLEXSPI_GetBusIdleStatus(flexspiPrivateHandle->base))
85 {
86 }
87 /* Disable transfer. */
88 FLEXSPI_TransferAbortEDMA(flexspiPrivateHandle->base, flexspiPrivateHandle->handle);
89
90 if (flexspiPrivateHandle->handle->completionCallback != NULL)
91 {
92 flexspiPrivateHandle->handle->completionCallback(flexspiPrivateHandle->base, flexspiPrivateHandle->handle,
93 kStatus_Success, flexspiPrivateHandle->handle->userData);
94 }
95 }
96 }
97
98 /*!
99 * brief Initializes the FLEXSPI handle for transfer which is used in transactional functions and set the callback.
100 *
101 * param base FLEXSPI peripheral base address
102 * param handle Pointer to flexspi_edma_handle_t structure
103 * param callback FLEXSPI callback, NULL means no callback.
104 * param userData User callback function data.
105 * param txDmaHandle User requested DMA handle for TX DMA transfer.
106 * param rxDmaHandle User requested DMA handle for RX DMA transfer.
107 */
FLEXSPI_TransferCreateHandleEDMA(FLEXSPI_Type * base,flexspi_edma_handle_t * handle,flexspi_edma_callback_t callback,void * userData,edma_handle_t * txDmaHandle,edma_handle_t * rxDmaHandle)108 void FLEXSPI_TransferCreateHandleEDMA(FLEXSPI_Type *base,
109 flexspi_edma_handle_t *handle,
110 flexspi_edma_callback_t callback,
111 void *userData,
112 edma_handle_t *txDmaHandle,
113 edma_handle_t *rxDmaHandle)
114 {
115 assert(handle);
116
117 uint32_t instance = FLEXSPI_GetInstance(base);
118
119 s_edmaPrivateHandle[instance].base = base;
120 s_edmaPrivateHandle[instance].handle = handle;
121
122 (void)memset(handle, 0, sizeof(*handle));
123
124 handle->state = kFLEXSPI_Idle;
125 handle->txDmaHandle = txDmaHandle;
126 handle->rxDmaHandle = rxDmaHandle;
127 handle->nsize = kFLEXPSI_EDMAnSize1Bytes;
128
129 handle->completionCallback = callback;
130 handle->userData = userData;
131 }
132
133 /*!
134 * brief Update FLEXSPI EDMA transfer source data transfer size(SSIZE) and destination data transfer size(DSIZE).
135 *
136 * param base FLEXSPI peripheral base address
137 * param handle Pointer to flexspi_edma_handle_t structure
138 * param nsize FLEXSPI DMA transfer data transfer size(SSIZE/DSIZE), by default the size is
139 * kFLEXPSI_EDMAnSize1Bytes(one byte).
140 * see flexspi_edma_transfer_nsize_t .
141 */
FLEXSPI_TransferUpdateSizeEDMA(FLEXSPI_Type * base,flexspi_edma_handle_t * handle,flexspi_edma_transfer_nsize_t nsize)142 void FLEXSPI_TransferUpdateSizeEDMA(FLEXSPI_Type *base,
143 flexspi_edma_handle_t *handle,
144 flexspi_edma_transfer_nsize_t nsize)
145 {
146 handle->nsize = nsize;
147 }
148
149 /*!
150 * brief Transfers FLEXSPI data using an eDMA non-blocking method.
151 *
152 * This function writes/receives data to/from the FLEXSPI transmit/receive FIFO. This function is non-blocking.
153 * param base FLEXSPI peripheral base address.
154 * param handle Pointer to flexspi_edma_handle_t structure
155 * param xfer FLEXSPI transfer structure.
156 * retval kStatus_FLEXSPI_Busy FLEXSPI is busy transfer.
157 * retval kStatus_InvalidArgument The watermark configuration is invalid, the watermark should be power of
158 2 to do successfully EDMA transfer.
159 * retval kStatus_Success FLEXSPI successfully start edma transfer.
160 */
FLEXSPI_TransferEDMA(FLEXSPI_Type * base,flexspi_edma_handle_t * handle,flexspi_transfer_t * xfer)161 status_t FLEXSPI_TransferEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, flexspi_transfer_t *xfer)
162 {
163 uint32_t configValue = 0;
164 status_t result = kStatus_Success;
165 edma_transfer_config_t xferConfig;
166 uint32_t instance = FLEXSPI_GetInstance(base);
167 uint8_t power = 0;
168
169 assert(handle);
170 assert(xfer);
171
172 /* Check if the FLEXSPI bus is idle - if not return busy status. */
173 if (handle->state != (uint32_t)kFLEXSPI_Idle)
174 {
175 result = kStatus_FLEXSPI_Busy;
176 }
177 else
178 {
179 handle->transferSize = xfer->dataSize;
180 handle->state = kFLEXSPI_Busy;
181
182 /* Clear sequence pointer before sending data to external devices. */
183 base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
184
185 /* Clear former pending status before start this transfer. */
186 base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
187 FLEXSPI_INTR_IPCMDGE_MASK;
188
189 /* Configure base address. */
190 base->IPCR0 = xfer->deviceAddress;
191
192 /* Reset fifos. */
193 base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
194 base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
195
196 /* Configure data size. */
197 if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write))
198 {
199 configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
200 }
201
202 /* Configure sequence ID. */
203 configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
204 base->IPCR1 = configValue;
205 }
206
207 if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
208 {
209 handle->count = (uint8_t)((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
210
211 if (xfer->dataSize < 8U * (uint32_t)handle->count)
212 {
213 handle->nbytes = (uint8_t)xfer->dataSize;
214 }
215 else
216 {
217 /* Check the handle->count is power of 2 */
218 if (((handle->count) & (handle->count - 1U)) != 0U)
219 {
220 return kStatus_InvalidArgument;
221 }
222 /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
223 handle->nbytes = (8U * handle->count);
224 }
225
226 power = FLEXSPI_CalculatePower(8U * handle->count);
227
228 /* Prepare transfer. */
229 EDMA_PrepareTransfer(&xferConfig, xfer->data, (uint32_t)handle->nsize,
230 (void *)(uint32_t *)FLEXSPI_GetTxFifoAddress(base), (uint32_t)handle->nsize,
231 (uint32_t)handle->nbytes, xfer->dataSize, kEDMA_MemoryToMemory);
232
233 /* Submit transfer. */
234 (void)EDMA_SubmitTransfer(handle->txDmaHandle, &xferConfig);
235 handle->txDmaHandle->base->TCD[handle->txDmaHandle->channel].ATTR |= DMA_ATTR_DMOD(power);
236 EDMA_SetCallback(handle->txDmaHandle, FLEXSPI_TransferEDMACallback,
237 &s_edmaPrivateHandle[FLEXSPI_GetInstance(base)]);
238 EDMA_StartTransfer(handle->txDmaHandle);
239
240 /* Enable FLEXSPI TX EDMA. */
241 FLEXSPI_EnableTxDMA(base, true);
242
243 /* Start Transfer. */
244 base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
245 }
246 else if (xfer->cmdType == kFLEXSPI_Read)
247 {
248 handle->count = (uint8_t)((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
249
250 if (xfer->dataSize < 8U * (uint32_t)handle->count)
251 {
252 handle->nbytes = (uint8_t)xfer->dataSize;
253 }
254 else
255 {
256 /* Check the handle->count is power of 2 */
257 if (((handle->count) & (handle->count - 1U)) != 0U)
258 {
259 return kStatus_InvalidArgument;
260 }
261 /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
262 handle->nbytes = (8U * handle->count);
263 }
264
265 power = FLEXSPI_CalculatePower(8U * handle->count);
266
267 /* Prepare transfer. */
268 EDMA_PrepareTransfer(&xferConfig, (void *)(uint32_t *)FLEXSPI_GetRxFifoAddress(base), (uint32_t)handle->nsize,
269 xfer->data, (uint32_t)handle->nsize, (uint32_t)handle->nbytes, xfer->dataSize,
270 kEDMA_MemoryToMemory);
271
272 /* Submit transfer. */
273 (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
274 handle->rxDmaHandle->base->TCD[handle->rxDmaHandle->channel].ATTR |= DMA_ATTR_SMOD(power);
275 EDMA_SetCallback(handle->rxDmaHandle, FLEXSPI_TransferEDMACallback, &s_edmaPrivateHandle[instance]);
276 EDMA_StartTransfer(handle->rxDmaHandle);
277
278 /* Enable FLEXSPI RX EDMA. */
279 FLEXSPI_EnableRxDMA(base, true);
280
281 /* Start Transfer. */
282 base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
283 }
284 else
285 {
286 /* Start Transfer. */
287 base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
288 /* Wait for bus idle. */
289 while (!FLEXSPI_GetBusIdleStatus(base))
290 {
291 }
292 result = FLEXSPI_CheckAndClearError(base, base->INTR);
293
294 handle->state = kFLEXSPI_Idle;
295
296 if (handle->completionCallback != NULL)
297 {
298 handle->completionCallback(base, handle, result, handle->userData);
299 }
300 }
301
302 return result;
303 }
304
305 /*!
306 * brief Aborts the transfer data using eDMA.
307 *
308 * This function aborts the transfer data using eDMA.
309 *
310 * param base FLEXSPI peripheral base address.
311 * param handle Pointer to flexspi_edma_handle_t structure
312 */
FLEXSPI_TransferAbortEDMA(FLEXSPI_Type * base,flexspi_edma_handle_t * handle)313 void FLEXSPI_TransferAbortEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle)
314 {
315 assert(handle);
316
317 if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
318 {
319 FLEXSPI_EnableTxDMA(base, false);
320 EDMA_AbortTransfer(handle->txDmaHandle);
321 }
322
323 if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
324 {
325 FLEXSPI_EnableRxDMA(base, false);
326 EDMA_AbortTransfer(handle->rxDmaHandle);
327 }
328
329 handle->state = kFLEXSPI_Idle;
330 }
331
FLEXSPI_TransferGetTransferCountEDMA(FLEXSPI_Type * base,flexspi_edma_handle_t * handle,size_t * count)332 status_t FLEXSPI_TransferGetTransferCountEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, size_t *count)
333 {
334 assert(handle);
335 assert(count);
336
337 status_t result = kStatus_Success;
338
339 if (handle->state != (uint32_t)kFLEXSPI_Busy)
340 {
341 result = kStatus_NoTransferInProgress;
342 }
343 else
344 {
345 if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
346 {
347 *count = (handle->transferSize -
348 (uint32_t)handle->nbytes *
349 EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel));
350 }
351 else if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
352 {
353 *count = (handle->transferSize -
354 (uint32_t)handle->nbytes *
355 EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel));
356 }
357 else
358 {
359 ; /* Intentional empty for MISRA C-2012 rule 15.7. */
360 }
361 }
362
363 return result;
364 }
365