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