]> git.sur5r.net Git - freertos/blob
cd415ae07e2e82e004f50a0ab59d17ec5961e0a4
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2014 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xqspipsu.c
36 * @addtogroup qspipsu_v1_0
37 * @{
38 *
39 * This file implements the functions required to use the QSPIPSU hardware to
40 * perform a transfer. These are accessible to the user via xqspipsu.h.
41 *
42 * <pre>
43 * MODIFICATION HISTORY:
44 *
45 * Ver   Who Date     Changes
46 * ----- --- -------- -----------------------------------------------
47 * 1.0   hk  08/21/14 First release
48 *       sk  03/13/15 Added IO mode support.
49 *       hk  03/18/15 Switch to I/O mode before clearing RX FIFO.
50 *                    Clear and disbale DMA interrupts/status in abort.
51 *                    Use DMA DONE bit instead of BUSY as recommended.
52 *       sk  04/24/15 Modified the code according to MISRAC-2012.
53 *       sk  06/17/15 Removed NULL checks for Rx/Tx buffers. As
54 *                    writing/reading from 0x0 location is permitted.
55 *
56 * </pre>
57 *
58 ******************************************************************************/
59
60 /***************************** Include Files *********************************/
61
62 #include "xqspipsu.h"
63
64 /************************** Constant Definitions *****************************/
65
66 /**************************** Type Definitions *******************************/
67
68 /***************** Macros (Inline Functions) Definitions *********************/
69
70 /************************** Function Prototypes ******************************/
71 static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
72                         u32 ByteCount);
73 static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode);
74 static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
75                         u32 *GenFifoEntry);
76 static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr,
77                         XQspiPsu_Msg *Msg, s32 Size);
78 static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr,
79                         XQspiPsu_Msg *Msg);
80 static inline void XQspiPsu_GenFifoEntryCSAssert(XQspiPsu *InstancePtr);
81 static inline void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr,
82                         XQspiPsu_Msg *Msg, s32 Index);
83 static inline void XQspiPsu_GenFifoEntryCSDeAssert(XQspiPsu *InstancePtr);
84 static inline void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr,
85                         XQspiPsu_Msg *Msg, s32 Size);
86
87 /************************** Variable Definitions *****************************/
88
89 /*****************************************************************************/
90 /**
91 *
92 * Initializes a specific XQspiPsu instance such that the driver is ready to use.
93 *
94 *
95 * @param        InstancePtr is a pointer to the XQspiPsu instance.
96 * @param        ConfigPtr is a reference to a structure containing information
97 *               about a specific QSPIPSU device. This function initializes an
98 *               InstancePtr object for a specific device specified by the
99 *               contents of Config.
100 * @param        EffectiveAddr is the device base address in the virtual memory
101 *               address space. The caller is responsible for keeping the address
102 *               mapping from EffectiveAddr to the device physical base address
103 *               unchanged once this function is invoked. Unexpected errors may
104 *               occur if the address mapping changes after this function is
105 *               called. If address translation is not used, use
106 *               ConfigPtr->Config.BaseAddress for this device.
107 *
108 * @return
109 *               - XST_SUCCESS if successful.
110 *               - XST_DEVICE_IS_STARTED if the device is already started.
111 *               It must be stopped to re-initialize.
112 *
113 * @note         None.
114 *
115 ******************************************************************************/
116 s32 XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, XQspiPsu_Config *ConfigPtr,
117                                 u32 EffectiveAddr)
118 {
119         Xil_AssertNonvoid(InstancePtr != NULL);
120         Xil_AssertNonvoid(ConfigPtr != NULL);
121         s32 Status;
122
123         /*
124          * If the device is busy, disallow the initialize and return a status
125          * indicating it is already started. This allows the user to stop the
126          * device and re-initialize, but prevents a user from inadvertently
127          * initializing. This assumes the busy flag is cleared at startup.
128          */
129         if (InstancePtr->IsBusy == TRUE) {
130                 Status = (s32)XST_DEVICE_IS_STARTED;
131         } else {
132
133                 /* Set some default values. */
134                 InstancePtr->IsBusy = FALSE;
135
136                 InstancePtr->Config.BaseAddress = EffectiveAddr + XQSPIPSU_OFFSET;
137                 InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode;
138                 InstancePtr->StatusHandler = StubStatusHandler;
139                 InstancePtr->Config.BusWidth = ConfigPtr->BusWidth;
140
141                 /* Other instance variable initializations */
142                 InstancePtr->SendBufferPtr = NULL;
143                 InstancePtr->RecvBufferPtr = NULL;
144                 InstancePtr->GenFifoBufferPtr = NULL;
145                 InstancePtr->TxBytes = 0;
146                 InstancePtr->RxBytes = 0;
147                 InstancePtr->GenFifoEntries = 0;
148                 InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
149                 InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER;
150                 InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER;
151                 InstancePtr->IsUnaligned = 0;
152                 InstancePtr->IsManualstart = TRUE;
153
154                 /* Select QSPIPSU */
155                 XQspiPsu_Select(InstancePtr);
156
157                 /*
158                  * Reset the QSPIPSU device to get it into its initial state. It is
159                  * expected that device configuration will take place after this
160                  * initialization is done, but before the device is started.
161                  */
162                 XQspiPsu_Reset(InstancePtr);
163
164                 InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
165
166                 Status = XST_SUCCESS;
167         }
168
169         return Status;
170 }
171
172 /*****************************************************************************/
173 /**
174 *
175 * Resets the QSPIPSU device. Reset must only be called after the driver has
176 * been initialized. Any data transfer that is in progress is aborted.
177 *
178 * The upper layer software is responsible for re-configuring (if necessary)
179 * and restarting the QSPIPSU device after the reset.
180 *
181 * @param        InstancePtr is a pointer to the XQspiPsu instance.
182 *
183 * @return       None.
184 *
185 * @note         None.
186 *
187 ******************************************************************************/
188 void XQspiPsu_Reset(XQspiPsu *InstancePtr)
189 {
190         u32 ConfigReg;
191
192         Xil_AssertVoid(InstancePtr != NULL);
193
194         /* Abort any transfer that is in progress */
195         XQspiPsu_Abort(InstancePtr);
196
197         /* Default value to config register */
198         ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
199                         XQSPIPSU_CFG_OFFSET);
200
201         /* DMA mode */
202         ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
203         ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
204         /* Manual start */
205         ConfigReg |= XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK;
206         /* Little endain by default */
207         ConfigReg &= ~XQSPIPSU_CFG_ENDIAN_MASK;
208         /* Disable poll timeout */
209         ConfigReg &= ~XQSPIPSU_CFG_EN_POLL_TO_MASK;
210         /* Set hold bit */
211         ConfigReg |= XQSPIPSU_CFG_WP_HOLD_MASK;
212         /* Clear prescalar by default */
213         ConfigReg &= (u32)(~XQSPIPSU_CFG_BAUD_RATE_DIV_MASK);
214         /* CPOL CPHA 00 */
215         ConfigReg &= (u32)(~XQSPIPSU_CFG_CLK_PHA_MASK);
216         ConfigReg &= (u32)(~XQSPIPSU_CFG_CLK_POL_MASK);
217
218         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
219                 XQSPIPSU_CFG_OFFSET, ConfigReg);
220
221         /* Set by default to allow for high frequencies */
222         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
223                 XQSPIPSU_LPBK_DLY_ADJ_OFFSET,
224                 XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
225                         XQSPIPSU_LPBK_DLY_ADJ_OFFSET) |
226                         XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK);
227
228         /* Reset thresholds */
229         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
230                 XQSPIPSU_TX_THRESHOLD_OFFSET,
231                 XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL);
232         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
233                 XQSPIPSU_RX_THRESHOLD_OFFSET,
234                 XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL);
235         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
236                 XQSPIPSU_GF_THRESHOLD_OFFSET,
237                 XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL);
238
239         /* DMA init */
240         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
241                         XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET,
242                         XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL);
243
244 }
245
246 /*****************************************************************************/
247 /**
248 *
249 * Aborts a transfer in progress by
250 *
251 * @param        InstancePtr is a pointer to the XQspiPsu instance.
252 *
253 * @return       None.
254 *
255 * @note
256 *
257 ******************************************************************************/
258 void XQspiPsu_Abort(XQspiPsu *InstancePtr)
259 {
260
261         u32 IntrStatus, ConfigReg;
262
263         IntrStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
264                                         XQSPIPSU_ISR_OFFSET);
265
266         /* Clear and disable interrupts */
267         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
268                 XQSPIPSU_ISR_OFFSET, IntrStatus | XQSPIPSU_ISR_WR_TO_CLR_MASK);
269         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
270                         XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET,
271                 XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
272                                 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET));
273         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
274                         XQSPIPSU_QSPIDMA_DST_STS_OFFSET,
275                         XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
276                                 XQSPIPSU_QSPIDMA_DST_STS_OFFSET) |
277                                 XQSPIPSU_QSPIDMA_DST_STS_WTC);
278         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
279                 XQSPIPSU_IDR_OFFSET, XQSPIPSU_IDR_ALL_MASK);
280         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
281                         XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET,
282                         XQSPIPSU_QSPIDMA_DST_INTR_ALL_MASK);
283
284         /* Clear FIFO */
285         if((XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
286                         XQSPIPSU_ISR_OFFSET) & XQSPIPSU_ISR_RXEMPTY_MASK) != FALSE) {
287                 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
288                         XQSPIPSU_FIFO_CTRL_OFFSET,
289                         XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK |
290                         XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK);
291         }
292
293         /*
294          * Switch to IO mode to Clear RX FIFO. This is becuase of DMA behaviour
295          * where it waits on RX empty and goes busy assuming there is data
296          * to be transfered even if there is no request.
297          */
298         if ((IntrStatus & XQSPIPSU_ISR_RXEMPTY_MASK) != 0U) {
299                 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
300                                         XQSPIPSU_CFG_OFFSET);
301                 ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
302                 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
303                                 XQSPIPSU_CFG_OFFSET, ConfigReg);
304
305                 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
306                                 XQSPIPSU_FIFO_CTRL_OFFSET,
307                                 XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK);
308
309                 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
310                         ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
311                         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
312                                         XQSPIPSU_CFG_OFFSET, ConfigReg);
313                 }
314         }
315
316         /* Disable QSPIPSU */
317         XQspiPsu_Disable(InstancePtr);
318
319         InstancePtr->TxBytes = 0;
320         InstancePtr->RxBytes = 0;
321         InstancePtr->GenFifoEntries = 0;
322         InstancePtr->IsBusy = FALSE;
323 }
324
325 /*****************************************************************************/
326 /**
327 *
328 * This function performs a transfer on the bus in polled mode. The messages
329 * passed are all transferred on the bus between one CS assert and de-assert.
330 *
331 * @param        InstancePtr is a pointer to the XQspiPsu instance.
332 * @param        Msg is a pointer to the structure containing transfer data.
333 * @param        NumMsg is the number of messages to be transferred.
334 *
335 * @return
336 *               - XST_SUCCESS if successful.
337 *               - XST_FAILURE if transfer fails.
338 *               - XST_DEVICE_BUSY if a transfer is already in progress.
339 *
340 * @note         None.
341 *
342 ******************************************************************************/
343 s32 XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
344                                 u32 NumMsg)
345 {
346         u32 StatusReg;
347         u32 ConfigReg;
348         s32 Index;
349         u32 QspiPsuStatusReg, DmaStatusReg;
350         u32 BaseAddress;
351         s32 Status;
352         s32 RxThr;
353         u32 IOPending = (u32)FALSE;
354
355         Xil_AssertNonvoid(InstancePtr != NULL);
356         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
357         for (Index = 0; Index < (s32)NumMsg; Index++) {
358                 Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
359         }
360
361         /* Check whether there is another transfer in progress. Not thread-safe */
362         if (InstancePtr->IsBusy == TRUE) {
363                 return (s32)XST_DEVICE_BUSY;
364         }
365
366         /* Check for ByteCount upper limit - 2^28 for DMA */
367         for (Index = 0; Index < (s32)NumMsg; Index++) {
368                 if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) &&
369                                 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
370                         return (s32)XST_FAILURE;
371                 }
372         }
373
374         /*
375          * Set the busy flag, which will be cleared when the transfer is
376          * entirely done.
377          */
378         InstancePtr->IsBusy = TRUE;
379
380         BaseAddress = InstancePtr->Config.BaseAddress;
381
382         /* Enable */
383         XQspiPsu_Enable(InstancePtr);
384
385         /* Select slave */
386         XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
387
388         /* list */
389         Index = 0;
390         while (Index < (s32)NumMsg) {
391                 XQspiPsu_GenFifoEntryData(InstancePtr, Msg, Index);
392
393                 if (InstancePtr->IsManualstart == TRUE) {
394                         XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
395                                 XQspiPsu_ReadReg(BaseAddress,
396                                         XQSPIPSU_CFG_OFFSET) |
397                                         XQSPIPSU_CFG_START_GEN_FIFO_MASK);
398                 }
399
400                 /* Use thresholds here */
401                 /* If there is more data to be transmitted */
402                 do {
403                         QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress,
404                                                 XQSPIPSU_ISR_OFFSET);
405
406                         /* Transmit more data if left */
407                         if (((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != FALSE) &&
408                                 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
409                                 (InstancePtr->TxBytes > 0)) {
410                                 XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index],
411                                                 XQSPIPSU_TXD_DEPTH);
412                         }
413
414                         /* Check if DMA RX is complete and update RxBytes */
415                         if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) &&
416                                 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
417                                 u32 DmaIntrSts;
418                                 DmaIntrSts = XQspiPsu_ReadReg(BaseAddress,
419                                                                 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET);
420                                 if ((DmaIntrSts & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != FALSE) {
421                                         XQspiPsu_WriteReg(BaseAddress,
422                                                 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET,
423                                                 DmaIntrSts);
424                                         /* Read remaining bytes using IO mode */
425                                         if((InstancePtr->RxBytes % 4) != 0 ) {
426                                                 XQspiPsu_WriteReg(BaseAddress,
427                                                         XQSPIPSU_CFG_OFFSET,
428                                                         (XQspiPsu_ReadReg(BaseAddress,
429                                                         XQSPIPSU_CFG_OFFSET) &
430                                                         ~XQSPIPSU_CFG_MODE_EN_MASK));
431                                                 InstancePtr->ReadMode = XQSPIPSU_READMODE_IO;
432                                                 Msg[Index].ByteCount =
433                                                         (InstancePtr->RxBytes % 4);
434                                                 Msg[Index].RxBfrPtr += (InstancePtr->RxBytes -
435                                                                 (InstancePtr->RxBytes % 4));
436                                                 InstancePtr->IsUnaligned = 1;
437                                                 IOPending = (u32)TRUE;
438                                                 break;
439                                         }
440                                         InstancePtr->RxBytes = 0;
441                                 }
442                         } else {
443                                 if ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE) {
444                                         /* Check if PIO RX is complete and update RxBytes */
445                                         RxThr = (s32)XQspiPsu_ReadReg(BaseAddress,
446                                                         XQSPIPSU_RX_THRESHOLD_OFFSET);
447                                         if ((QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK)
448                                                                         != 0U) {
449                                                 XQspiPsu_ReadRxFifo(InstancePtr,
450                                                                 &Msg[Index], RxThr*4);
451
452                                         } else {
453                                                 if ((QspiPsuStatusReg &
454                                                         XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) {
455                                                                 XQspiPsu_ReadRxFifo(InstancePtr,
456                                                                         &Msg[Index], InstancePtr->RxBytes);
457                                                 }
458                                         }
459                                 }
460                         }
461                 } while (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == FALSE) ||
462                         (InstancePtr->TxBytes != 0) ||
463                         ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == FALSE) ||
464                         (InstancePtr->RxBytes != 0));
465
466                 if((InstancePtr->IsUnaligned != 0) && (IOPending == (u32)FALSE)) {
467                         InstancePtr->IsUnaligned = 0;
468                         XQspiPsu_WriteReg(BaseAddress,
469                                 XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(
470                                 BaseAddress,
471                                 XQSPIPSU_CFG_OFFSET) |
472                                 XQSPIPSU_CFG_MODE_EN_DMA_MASK));
473                         InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
474                 }
475
476                 if (IOPending == (u32)TRUE) {
477                         IOPending = (u32)FALSE;
478                 } else {
479                         Index++;
480                 }
481         }
482
483         /* De-select slave */
484         XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
485
486         if (InstancePtr->IsManualstart == TRUE) {
487                 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
488                         XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) |
489                                 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
490         }
491
492         QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET);
493         while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == FALSE) {
494                 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress,
495                                                 XQSPIPSU_ISR_OFFSET);
496         }
497
498         /* Clear the busy flag. */
499         InstancePtr->IsBusy = FALSE;
500
501         /* Disable the device. */
502         XQspiPsu_Disable(InstancePtr);
503
504         return XST_SUCCESS;
505 }
506
507 /*****************************************************************************/
508 /**
509 *
510 * This function initiates a transfer on the bus and enables interrupts.
511 * The transfer is completed by the interrupt handler. The messages passed are
512 * all transferred on the bus between one CS assert and de-assert.
513 *
514 * @param        InstancePtr is a pointer to the XQspiPsu instance.
515 * @param        Msg is a pointer to the structure containing transfer data.
516 * @param        NumMsg is the number of messages to be transferred.
517 *
518 * @return
519 *               - XST_SUCCESS if successful.
520 *               - XST_FAILURE if transfer fails.
521 *               - XST_DEVICE_BUSY if a transfer is already in progress.
522 *
523 * @note         None.
524 *
525 ******************************************************************************/
526 s32 XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
527                                 u32 NumMsg)
528 {
529         u32 StatusReg;
530         u32 ConfigReg;
531         s32 Index;
532         u32 BaseAddress;
533         s32 Status;
534
535         Xil_AssertNonvoid(InstancePtr != NULL);
536         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
537         for (Index = 0; Index < (s32)NumMsg; Index++) {
538                 Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
539         }
540
541         /* Check whether there is another transfer in progress. Not thread-safe */
542         if (InstancePtr->IsBusy == TRUE) {
543                 return (s32)XST_DEVICE_BUSY;
544         }
545
546         /* Check for ByteCount upper limit - 2^28 for DMA */
547         for (Index = 0; Index < (s32)NumMsg; Index++) {
548                 if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) &&
549                                 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
550                         return (s32)XST_FAILURE;
551                 }
552         }
553
554         /*
555          * Set the busy flag, which will be cleared when the transfer is
556          * entirely done.
557          */
558         InstancePtr->IsBusy = TRUE;
559
560         BaseAddress = InstancePtr->Config.BaseAddress;
561
562         InstancePtr->Msg = Msg;
563         InstancePtr->NumMsg = (s32)NumMsg;
564         InstancePtr->MsgCnt = 0;
565
566         /* Enable */
567         XQspiPsu_Enable(InstancePtr);
568
569         /* Select slave */
570         XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
571
572         /* This might not work if not manual start */
573         /* Put first message in FIFO along with the above slave select */
574         XQspiPsu_GenFifoEntryData(InstancePtr, Msg, 0);
575
576         if (InstancePtr->IsManualstart == TRUE) {
577                 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
578                         XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) |
579                                 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
580         }
581
582         /* Enable interrupts */
583         XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IER_OFFSET,
584                 (u32)XQSPIPSU_IER_TXNOT_FULL_MASK | (u32)XQSPIPSU_IER_TXEMPTY_MASK |
585                 (u32)XQSPIPSU_IER_RXNEMPTY_MASK | (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
586                 (u32)XQSPIPSU_IER_RXEMPTY_MASK);
587
588         if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
589                 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET,
590                                 XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK);
591         }
592
593         return XST_SUCCESS;
594 }
595
596 /*****************************************************************************/
597 /**
598 *
599 * Handles interrupt based transfers by acting on GENFIFO and DMA interurpts.
600 *
601 * @param        InstancePtr is a pointer to the XQspiPsu instance.
602 *
603 * @return
604 *               - XST_SUCCESS if successful.
605 *               - XST_FAILURE if transfer fails.
606 *
607 * @note         None.
608 *
609 ******************************************************************************/
610 s32 XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr)
611 {
612         u32 QspiPsuStatusReg, DmaIntrStatusReg = 0;
613         u32 BaseAddress;
614         XQspiPsu_Msg *Msg;
615         s32 NumMsg;
616         s32 MsgCnt;
617         u8 DeltaMsgCnt = 0;
618         s32 RxThr;
619         u32 TxRxFlag;
620
621         Xil_AssertNonvoid(InstancePtr != NULL);
622
623         BaseAddress = InstancePtr->Config.BaseAddress;
624         Msg = InstancePtr->Msg;
625         NumMsg = InstancePtr->NumMsg;
626         MsgCnt = InstancePtr->MsgCnt;
627         TxRxFlag = Msg[MsgCnt].Flags;
628
629         /* QSPIPSU Intr cleared on read */
630         QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET);
631         if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
632                 /* DMA Intr write to clear */
633                 DmaIntrStatusReg = XQspiPsu_ReadReg(BaseAddress,
634                                         XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET);
635
636                 XQspiPsu_WriteReg(BaseAddress,
637                         XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrStatusReg);
638         }
639         if (((QspiPsuStatusReg & XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK) != FALSE) ||
640                 ((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK) != FALSE)) {
641                 /* Call status handler to indicate error */
642                 InstancePtr->StatusHandler(InstancePtr->StatusRef,
643                                         XST_SPI_COMMAND_ERROR, 0);
644         }
645
646         /* Fill more data to be txed if required */
647         if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
648                 ((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != FALSE) &&
649                 (InstancePtr->TxBytes > 0)) {
650                 XQspiPsu_FillTxFifo(InstancePtr, &Msg[MsgCnt],
651                                 XQSPIPSU_TXD_DEPTH);
652         }
653
654         /*
655          * Check if the entry is ONLY TX and increase MsgCnt.
656          * This is to allow TX and RX together in one entry - corner case.
657          */
658         if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
659                 ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) != FALSE) &&
660                 ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) &&
661                 (InstancePtr->TxBytes == 0) &&
662                 ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == FALSE)) {
663                 MsgCnt += 1;
664                 DeltaMsgCnt = 1U;
665         }
666
667         if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) &&
668                 (MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
669                 if ((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != FALSE) {
670                                 /* Read remaining bytes using IO mode */
671                         if((InstancePtr->RxBytes % 4) != 0 ) {
672                                 XQspiPsu_WriteReg(BaseAddress,
673                                         XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(
674                                         BaseAddress, XQSPIPSU_CFG_OFFSET) &
675                                         ~XQSPIPSU_CFG_MODE_EN_MASK));
676                                 InstancePtr->ReadMode = XQSPIPSU_READMODE_IO;
677                                 Msg[MsgCnt].ByteCount = (InstancePtr->RxBytes % 4);
678                                 Msg[MsgCnt].RxBfrPtr += (InstancePtr->RxBytes -
679                                                 (InstancePtr->RxBytes % 4));
680                                 InstancePtr->IsUnaligned = 1;
681                                 XQspiPsu_GenFifoEntryData(InstancePtr, Msg,
682                                                 MsgCnt);
683                                 if(InstancePtr->IsManualstart == TRUE) {
684                                         XQspiPsu_WriteReg(BaseAddress,
685                                                 XQSPIPSU_CFG_OFFSET,
686                                                 XQspiPsu_ReadReg(BaseAddress,
687                                                 XQSPIPSU_CFG_OFFSET) |
688                                                 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
689                                 }
690                         }
691                         else {
692                                 InstancePtr->RxBytes = 0;
693                                 MsgCnt += 1;
694                                 DeltaMsgCnt = 1U;
695                         }
696                 }
697         } else {
698                 if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
699                         if (InstancePtr->RxBytes != 0) {
700                                 if ((QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK)
701                                                                 != FALSE) {
702                                         RxThr = (s32)XQspiPsu_ReadReg(BaseAddress,
703                                                                 XQSPIPSU_RX_THRESHOLD_OFFSET);
704                                         XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt],
705                                                 RxThr*4);
706                                 } else {
707                                         if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) &&
708                                                 ((QspiPsuStatusReg & XQSPIPSU_ISR_RXEMPTY_MASK) == FALSE)) {
709                                                 XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt],
710                                                         InstancePtr->RxBytes);
711                                         }
712                                 }
713                                 if (InstancePtr->RxBytes == 0) {
714                                         MsgCnt += 1;
715                                         DeltaMsgCnt = 1U;
716                                 }
717                         }
718                 }
719         }
720
721         /*
722          * Dummy byte transfer
723          * MsgCnt < NumMsg check is to ensure is it a valid dummy cycle message
724          * If one of the above conditions increased MsgCnt, then
725          * the new message is yet to be placed in the FIFO; hence !DeltaMsgCnt.
726          */
727         if ((MsgCnt < NumMsg) && (DeltaMsgCnt == FALSE) &&
728                 ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == FALSE) &&
729                 ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) == FALSE) &&
730                 ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE)) {
731                 MsgCnt += 1;
732                 DeltaMsgCnt = 1U;
733         }
734         InstancePtr->MsgCnt = MsgCnt;
735
736         /*
737          * DeltaMsgCnt is to handle conditions where genfifo empty can be set
738          * while tx is still not empty or rx dma is not yet done.
739          * MsgCnt > NumMsg indicates CS de-assert entry was also executed.
740          */
741         if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) &&
742                 ((DeltaMsgCnt != FALSE) || (MsgCnt > NumMsg))) {
743                 if (MsgCnt < NumMsg) {
744                         if(InstancePtr->IsUnaligned != 0) {
745                                 InstancePtr->IsUnaligned = 0;
746                                 XQspiPsu_WriteReg(InstancePtr->Config.
747                                         BaseAddress, XQSPIPSU_CFG_OFFSET,
748                                         (XQspiPsu_ReadReg(InstancePtr->Config.
749                                         BaseAddress, XQSPIPSU_CFG_OFFSET) |
750                                         XQSPIPSU_CFG_MODE_EN_DMA_MASK));
751                                 InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
752                         }
753                         /* This might not work if not manual start */
754                         XQspiPsu_GenFifoEntryData(InstancePtr, Msg, MsgCnt);
755
756                         if (InstancePtr->IsManualstart == TRUE) {
757                                 XQspiPsu_WriteReg(BaseAddress,
758                                         XQSPIPSU_CFG_OFFSET,
759                                         XQspiPsu_ReadReg(BaseAddress,
760                                                 XQSPIPSU_CFG_OFFSET) |
761                                                 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
762                         }
763                 } else if (MsgCnt == NumMsg) {
764                         /* This is just to keep track of the de-assert entry */
765                         MsgCnt += 1;
766                         InstancePtr->MsgCnt = MsgCnt;
767
768                         /* De-select slave */
769                         XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
770
771                         if (InstancePtr->IsManualstart == TRUE) {
772                                 XQspiPsu_WriteReg(BaseAddress,
773                                         XQSPIPSU_CFG_OFFSET,
774                                         XQspiPsu_ReadReg(BaseAddress,
775                                                 XQSPIPSU_CFG_OFFSET) |
776                                                 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
777                         }
778                 } else {
779                         /* Disable interrupts */
780                         XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IDR_OFFSET,
781                                         (u32)XQSPIPSU_IER_TXNOT_FULL_MASK |
782                                         (u32)XQSPIPSU_IER_TXEMPTY_MASK |
783                                         (u32)XQSPIPSU_IER_RXNEMPTY_MASK |
784                                         (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
785                                         (u32)XQSPIPSU_IER_RXEMPTY_MASK);
786                         if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
787                                 XQspiPsu_WriteReg(BaseAddress,
788                                         XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET,
789                                         XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK);
790                         }
791
792                         /* Clear the busy flag. */
793                         InstancePtr->IsBusy = FALSE;
794
795                         /* Disable the device. */
796                         XQspiPsu_Disable(InstancePtr);
797
798                         /* Call status handler to indicate completion */
799                         InstancePtr->StatusHandler(InstancePtr->StatusRef,
800                                                 XST_SPI_TRANSFER_DONE, 0);
801                 }
802         }
803
804         return XST_SUCCESS;
805 }
806
807 /*****************************************************************************/
808 /**
809 *
810 * Sets the status callback function, the status handler, which the driver
811 * calls when it encounters conditions that should be reported to upper
812 * layer software. The handler executes in an interrupt context, so it must
813 * minimize the amount of processing performed. One of the following status
814 * events is passed to the status handler.
815 *
816 * <pre>
817 *
818 * XST_SPI_TRANSFER_DONE         The requested data transfer is done
819 *
820 * XST_SPI_TRANSMIT_UNDERRUN     As a slave device, the master clocked data
821 *                               but there were none available in the transmit
822 *                               register/FIFO. This typically means the slave
823 *                               application did not issue a transfer request
824 *                               fast enough, or the processor/driver could not
825 *                               fill the transmit register/FIFO fast enough.
826 *
827 * XST_SPI_RECEIVE_OVERRUN       The QSPIPSU device lost data. Data was received
828 *                               but the receive data register/FIFO was full.
829 *
830 * </pre>
831 * @param        InstancePtr is a pointer to the XQspiPsu instance.
832 * @param        CallBackRef is the upper layer callback reference passed back
833 *               when the callback function is invoked.
834 * @param        FuncPointer is the pointer to the callback function.
835 *
836 * @return       None.
837 *
838 * @note
839 *
840 * The handler is called within interrupt context, so it should do its work
841 * quickly and queue potentially time-consuming work to a task-level thread.
842 *
843 ******************************************************************************/
844 void XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef,
845                                 XQspiPsu_StatusHandler FuncPointer)
846 {
847         Xil_AssertVoid(InstancePtr != NULL);
848         Xil_AssertVoid(FuncPointer != NULL);
849         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
850
851         InstancePtr->StatusHandler = FuncPointer;
852         InstancePtr->StatusRef = CallBackRef;
853 }
854
855 /*****************************************************************************/
856 /**
857 *
858 * This is a stub for the status callback. The stub is here in case the upper
859 * layers forget to set the handler.
860 *
861 * @param        CallBackRef is a pointer to the upper layer callback reference
862 * @param        StatusEvent is the event that just occurred.
863 * @param        ByteCount is the number of bytes transferred up until the event
864 *               occurred.
865 *
866 * @return       None.
867 *
868 * @note         None.
869 *
870 ******************************************************************************/
871 static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
872                                 u32 ByteCount)
873 {
874         (void *) CallBackRef;
875         (void) StatusEvent;
876         (void) ByteCount;
877
878         Xil_AssertVoidAlways();
879 }
880
881 /*****************************************************************************/
882 /**
883 *
884 * Selects SPI mode - x1 or x2 or x4.
885 *
886 * @param        SpiMode - spi or dual or quad.
887 * @return       Mask to set desired SPI mode in GENFIFO entry.
888 *
889 * @note         None.
890 *
891 ******************************************************************************/
892 static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode)
893 {
894         u32 Mask;
895         switch (SpiMode) {
896                 case XQSPIPSU_SELECT_MODE_DUALSPI:
897                         Mask = XQSPIPSU_GENFIFO_MODE_DUALSPI;
898                         break;
899                 case XQSPIPSU_SELECT_MODE_QUADSPI:
900                         Mask = XQSPIPSU_GENFIFO_MODE_QUADSPI;
901                         break;
902                 case XQSPIPSU_SELECT_MODE_SPI:
903                         Mask = XQSPIPSU_GENFIFO_MODE_SPI;
904                         break;
905                 default:
906                         Mask = XQSPIPSU_GENFIFO_MODE_SPI;
907                         break;
908         }
909
910         return Mask;
911 }
912
913 /*****************************************************************************/
914 /**
915 *
916 * This function checks the TX/RX buffers in the message and setups up the
917 * GENFIFO entries, TX FIFO or RX DMA as required.
918 *
919 * @param        InstancePtr is a pointer to the XQspiPsu instance.
920 * @param        Msg is a pointer to the structure containing transfer data.
921 * @param        GenFifoEntry is pointer to the variable in which GENFIFO mask
922 *               is returned to calling function
923 *
924 * @return       None
925 *
926 * @note         None.
927 *
928 ******************************************************************************/
929 static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
930                                         u32 *GenFifoEntry)
931 {
932         Xil_AssertVoid(InstancePtr != NULL);
933
934         /* Transmit */
935         if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
936                         ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == FALSE)) {
937                 /* Setup data to be TXed */
938                 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
939                 *GenFifoEntry |= XQSPIPSU_GENFIFO_TX;
940                 InstancePtr->TxBytes = (s32)Msg->ByteCount;
941                 InstancePtr->SendBufferPtr = Msg->TxBfrPtr;
942                 InstancePtr->RecvBufferPtr = NULL;
943                 XQspiPsu_FillTxFifo(InstancePtr, Msg, XQSPIPSU_TXD_DEPTH);
944                 /* Discard RX data */
945                 *GenFifoEntry &= ~XQSPIPSU_GENFIFO_RX;
946                 InstancePtr->RxBytes = 0;
947         }
948
949         /* Receive */
950         if (((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE) &&
951                         ((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == FALSE)) {
952                 /* TX auto fill */
953                 *GenFifoEntry &= ~XQSPIPSU_GENFIFO_TX;
954                 InstancePtr->TxBytes = 0;
955                 /* Setup RX */
956                 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
957                 *GenFifoEntry |= XQSPIPSU_GENFIFO_RX;
958                 InstancePtr->RxBytes = (s32)Msg->ByteCount;
959                 InstancePtr->SendBufferPtr = NULL;
960                 InstancePtr->RecvBufferPtr = Msg->RxBfrPtr;
961                 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
962                         XQspiPsu_SetupRxDma(InstancePtr, Msg);
963                 }
964         }
965
966         /* If only dummy is requested as a separate entry */
967         if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == FALSE) &&
968                         (Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == FALSE) {
969                 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
970                 *GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX);
971                 InstancePtr->TxBytes = 0;
972                 InstancePtr->RxBytes = 0;
973                 InstancePtr->SendBufferPtr = NULL;
974                 InstancePtr->RecvBufferPtr = NULL;
975         }
976
977         /* Dummy and cmd sent by upper layer to received data */
978         if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
979                         ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
980                 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
981                 *GenFifoEntry |= (XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX);
982                 InstancePtr->TxBytes = (s32)Msg->ByteCount;
983                 InstancePtr->RxBytes = (s32)Msg->ByteCount;
984                 InstancePtr->SendBufferPtr = Msg->TxBfrPtr;
985                 InstancePtr->RecvBufferPtr = Msg->RxBfrPtr;
986                 XQspiPsu_FillTxFifo(InstancePtr, Msg, XQSPIPSU_TXD_DEPTH);
987                 /* Add check for DMA or PIO here */
988                 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
989                         XQspiPsu_SetupRxDma(InstancePtr, Msg);
990                 }
991         }
992 }
993
994 /*****************************************************************************/
995 /**
996 *
997 * Fills the TX FIFO as long as there is room in the FIFO or the bytes required
998 * to be transmitted.
999 *
1000 * @param        InstancePtr is a pointer to the XQspiPsu instance.
1001 * @param        Msg is a pointer to the structure containing transfer data.
1002 * @param        Size is the number of bytes to be transmitted.
1003 *
1004 * @return       None
1005 *
1006 * @note         None.
1007 *
1008 ******************************************************************************/
1009 static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr,
1010                                         XQspiPsu_Msg *Msg, s32 Size)
1011 {
1012         s32 Count = 0;
1013         u32 Data;
1014
1015         Xil_AssertVoid(InstancePtr != NULL);
1016
1017         while ((InstancePtr->TxBytes > 0) && (Count < Size)) {
1018                 if (InstancePtr->TxBytes >= 4) {
1019                         (void)memcpy(&Data, Msg->TxBfrPtr, 4);
1020                         Msg->TxBfrPtr += 4;
1021                         InstancePtr->TxBytes -= 4;
1022                         Count += 4;
1023                 } else {
1024                         (void)memcpy(&Data, Msg->TxBfrPtr, InstancePtr->TxBytes);
1025                         Msg->TxBfrPtr += InstancePtr->TxBytes;
1026                         Count += InstancePtr->TxBytes;
1027                         InstancePtr->TxBytes = 0;
1028                 }
1029                 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1030                                 XQSPIPSU_TXD_OFFSET, Data);
1031
1032         }
1033         if (InstancePtr->TxBytes < 0) {
1034                 InstancePtr->TxBytes = 0;
1035         }
1036 }
1037
1038 /*****************************************************************************/
1039 /**
1040 *
1041 * This function sets up the RX DMA operation.
1042 *
1043 * @param        InstancePtr is a pointer to the XQspiPsu instance.
1044 * @param        Msg is a pointer to the structure containing transfer data.
1045 *
1046 * @return       None
1047 *
1048 * @note         None.
1049 *
1050 ******************************************************************************/
1051 static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr,
1052                                         XQspiPsu_Msg *Msg)
1053 {
1054         s32 Remainder;
1055         s32 DmaRxBytes;
1056         u64 AddrTemp;
1057
1058         Xil_AssertVoid(InstancePtr != NULL);
1059
1060         AddrTemp = (u64)((INTPTR)(Msg->RxBfrPtr) &
1061                                 XQSPIPSU_QSPIDMA_DST_ADDR_MASK);
1062         /* Check for RXBfrPtr to be word aligned */
1063         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1064                         XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET,
1065                         (u32)AddrTemp);
1066
1067         AddrTemp = AddrTemp >> 32;
1068         if ((AddrTemp & 0xFFFU) != FALSE) {
1069                 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1070                                 XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET,
1071                                 (u32)AddrTemp &
1072                                 XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK);
1073         }
1074
1075         Remainder = InstancePtr->RxBytes % 4;
1076         DmaRxBytes = InstancePtr->RxBytes;
1077         if (Remainder != 0) {
1078                 /* This is done to make Dma bytes aligned */
1079                 DmaRxBytes = InstancePtr->RxBytes - Remainder;
1080                 Msg->ByteCount = (u32)DmaRxBytes;
1081         }
1082
1083         Xil_DCacheInvalidateRange((INTPTR)InstancePtr->RecvBufferPtr, Msg->ByteCount);
1084
1085         /* Write no. of words to DMA DST SIZE */
1086         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1087                         XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes);
1088
1089 }
1090
1091 /*****************************************************************************/
1092 /**
1093 *
1094 * This function writes the GENFIFO entry to assert CS.
1095 *
1096 * @param        InstancePtr is a pointer to the XQspiPsu instance.
1097 *
1098 * @return       None
1099 *
1100 * @note         None.
1101 *
1102 ******************************************************************************/
1103 static inline void XQspiPsu_GenFifoEntryCSAssert(XQspiPsu *InstancePtr)
1104 {
1105         u32 GenFifoEntry;
1106
1107         GenFifoEntry = 0x0U;
1108         GenFifoEntry &= ~((u32)XQSPIPSU_GENFIFO_DATA_XFER | (u32)XQSPIPSU_GENFIFO_EXP);
1109         GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_MODE_MASK);
1110         GenFifoEntry |= XQSPIPSU_GENFIFO_MODE_SPI;
1111         GenFifoEntry |= InstancePtr->GenFifoCS;
1112         GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_BUS_MASK);
1113         GenFifoEntry |= InstancePtr->GenFifoBus;
1114         GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX |
1115                         XQSPIPSU_GENFIFO_STRIPE | XQSPIPSU_GENFIFO_POLL);
1116         GenFifoEntry |= XQSPIPSU_GENFIFO_CS_SETUP;
1117
1118         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1119                 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1120 }
1121
1122 /*****************************************************************************/
1123 /**
1124 *
1125 * This function writes the GENFIFO entries to transmit the messages requested.
1126 *
1127 * @param        InstancePtr is a pointer to the XQspiPsu instance.
1128 * @param        Msg is a pointer to the structure containing transfer data.
1129 * @param        Index of the current message to be handled.
1130 *
1131 * @return
1132 *               - XST_SUCCESS if successful.
1133 *               - XST_FAILURE if transfer fails.
1134 *               - XST_DEVICE_BUSY if a transfer is already in progress.
1135 *
1136 * @note         None.
1137 *
1138 ******************************************************************************/
1139 static inline void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr,
1140                                                 XQspiPsu_Msg *Msg, s32 Index)
1141 {
1142         u32 GenFifoEntry;
1143         u32 BaseAddress;
1144         u32 TempCount;
1145         u32 ImmData;
1146
1147         BaseAddress = InstancePtr->Config.BaseAddress;
1148
1149         GenFifoEntry = 0x0U;
1150         /* Bus width */
1151         GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_MODE_MASK);
1152         GenFifoEntry |= XQspiPsu_SelectSpiMode((u8)Msg[Index].BusWidth);
1153
1154         GenFifoEntry |= InstancePtr->GenFifoCS;
1155         GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_BUS_MASK);
1156         GenFifoEntry |= InstancePtr->GenFifoBus;
1157
1158         /* Data */
1159         if (((Msg[Index].Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != FALSE) {
1160                 GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE;
1161         } else {
1162                 GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE;
1163         }
1164
1165         /* If Byte Count is less than 8 bytes do the transfer in IO mode */
1166         if ((Msg[Index].ByteCount < 8U) &&
1167                 (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA)) {
1168                         InstancePtr->ReadMode = XQSPIPSU_READMODE_IO;
1169                         XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
1170                                 (XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) &
1171                                                 ~XQSPIPSU_CFG_MODE_EN_MASK));
1172                         InstancePtr->IsUnaligned = 1;
1173         }
1174
1175         XQspiPsu_TXRXSetup(InstancePtr, &Msg[Index], &GenFifoEntry);
1176
1177         if (Msg[Index].ByteCount < XQSPIPSU_GENFIFO_IMM_DATA_MASK) {
1178                 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK);
1179                 GenFifoEntry |= Msg[Index].ByteCount;
1180                 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET,
1181                                 GenFifoEntry);
1182         } else {
1183                 TempCount = Msg[Index].ByteCount;
1184                 u32 Exponent = 8;       /* 2^8 = 256 */
1185
1186                 ImmData = TempCount & 0xFFU;
1187                 /* Exponent entries */
1188                 GenFifoEntry |= XQSPIPSU_GENFIFO_EXP;
1189                 while (TempCount != 0U) {
1190                         if ((TempCount & XQSPIPSU_GENFIFO_EXP_START) != FALSE) {
1191                                 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK);
1192                                 GenFifoEntry |= Exponent;
1193                                 XQspiPsu_WriteReg(BaseAddress,
1194                                         XQSPIPSU_GEN_FIFO_OFFSET,
1195                                         GenFifoEntry);
1196                         }
1197                         TempCount = TempCount >> 1;
1198                         Exponent++;
1199                 }
1200
1201                 /* Immediate entry */
1202                 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_EXP);
1203                 if ((ImmData & 0xFFU) != FALSE) {
1204                         GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK);
1205                         GenFifoEntry |= ImmData & 0xFFU;
1206                         XQspiPsu_WriteReg(BaseAddress,
1207                                 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1208                 }
1209         }
1210
1211         /* One dummy GenFifo entry in case of IO mode */
1212         if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) &&
1213                         ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
1214                 GenFifoEntry = 0x0U;
1215                 XQspiPsu_WriteReg(BaseAddress,
1216                                 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1217         }
1218 }
1219
1220 /*****************************************************************************/
1221 /**
1222 *
1223 * This function writes the GENFIFO entry to de-assert CS.
1224 *
1225 * @param        InstancePtr is a pointer to the XQspiPsu instance.
1226 *
1227 * @return       None
1228 *
1229 * @note         None.
1230 *
1231 ******************************************************************************/
1232 static inline void XQspiPsu_GenFifoEntryCSDeAssert(XQspiPsu *InstancePtr)
1233 {
1234         u32 GenFifoEntry;
1235
1236         GenFifoEntry = 0x0U;
1237         GenFifoEntry &= ~((u32)XQSPIPSU_GENFIFO_DATA_XFER | (u32)XQSPIPSU_GENFIFO_EXP);
1238         GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_MODE_MASK);
1239         GenFifoEntry |= XQSPIPSU_GENFIFO_MODE_SPI;
1240         GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_BUS_MASK);
1241         GenFifoEntry |= InstancePtr->GenFifoBus;
1242         GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX |
1243                         XQSPIPSU_GENFIFO_STRIPE | XQSPIPSU_GENFIFO_POLL);
1244         GenFifoEntry |= XQSPIPSU_GENFIFO_CS_HOLD;
1245
1246         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1247                 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1248 }
1249
1250 /*****************************************************************************/
1251 /**
1252 *
1253 * Read the specified number of bytes from RX FIFO
1254 *
1255 * @param        InstancePtr is a pointer to the XQspiPsu instance.
1256 * @param        Msg is a pointer to the structure containing transfer data.
1257 * @param        Size is the number of bytes to be read.
1258 *
1259 * @return       None
1260 *
1261 * @note         None.
1262 *
1263 ******************************************************************************/
1264 static inline void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr,
1265                                         XQspiPsu_Msg *Msg, s32 Size)
1266 {
1267         s32 Count = 0;
1268         u32 Data;
1269
1270         Xil_AssertVoid(InstancePtr != NULL);
1271         Xil_AssertVoid(Msg != NULL);
1272
1273         while ((InstancePtr->RxBytes != 0) && (Count < Size)) {
1274                 Data = XQspiPsu_ReadReg(InstancePtr->
1275                                 Config.BaseAddress, XQSPIPSU_RXD_OFFSET);
1276                 if (InstancePtr->RxBytes >= 4) {
1277                         (void)memcpy(Msg->RxBfrPtr, &Data, 4);
1278                         InstancePtr->RxBytes -= 4;
1279                         Msg->RxBfrPtr += 4;
1280                         Count += 4;
1281                 } else {
1282                         /* Read unaligned bytes (< 4 bytes) */
1283                         (void)memcpy(Msg->RxBfrPtr, &Data, InstancePtr->RxBytes);
1284                         Msg->RxBfrPtr += InstancePtr->RxBytes;
1285                         Count += InstancePtr->RxBytes;
1286                         InstancePtr->RxBytes = 0;
1287                 }
1288         }
1289 }
1290 /** @} */