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