1 /******************************************************************************
3 * Copyright (C) 2014 Xilinx, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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.
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
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.
31 ******************************************************************************/
32 /*****************************************************************************/
36 * @addtogroup qspipsu_v1_0
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.
43 * MODIFICATION HISTORY:
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 * 1.1 sk 04/12/16 Added debug message prints.
56 * 1.2 nsk 07/01/16 Changed XQspiPsu_Select to support GQSPI and LQSPI
58 * rk 07/15/16 Added support for TapDelays at different frequencies.
59 * nsk 08/05/16 Added example support PollData and PollTimeout
60 * 1.3 nsk 09/16/16 Update PollData and PollTimeout support for dual
61 * parallel configurations, modified XQspiPsu_PollData()
62 * and XQspiPsu_Create_PollConfigData()
66 ******************************************************************************/
68 /***************************** Include Files *********************************/
72 /************************** Constant Definitions *****************************/
74 /**************************** Type Definitions *******************************/
76 /***************** Macros (Inline Functions) Definitions *********************/
78 /************************** Function Prototypes ******************************/
79 static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
81 static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode);
82 static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
84 static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr,
85 XQspiPsu_Msg *Msg, s32 Size);
86 static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr,
88 static inline void XQspiPsu_GenFifoEntryCSAssert(XQspiPsu *InstancePtr);
89 static inline void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr,
90 XQspiPsu_Msg *Msg, s32 Index);
91 static inline void XQspiPsu_GenFifoEntryCSDeAssert(XQspiPsu *InstancePtr);
92 static inline void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr,
93 XQspiPsu_Msg *Msg, s32 Size);
94 static inline void XQspiPsu_PollData(XQspiPsu *QspiPsuPtr,
95 XQspiPsu_Msg *FlashMsg);
96 static inline u32 XQspiPsu_Create_PollConfigData(XQspiPsu *QspiPsuPtr,
97 XQspiPsu_Msg *FlashMsg);
99 /************************** Variable Definitions *****************************/
101 /*****************************************************************************/
104 * Initializes a specific XQspiPsu instance such that the driver is ready to use.
107 * @param InstancePtr is a pointer to the XQspiPsu instance.
108 * @param ConfigPtr is a reference to a structure containing information
109 * about a specific QSPIPSU device. This function initializes an
110 * InstancePtr object for a specific device specified by the
111 * contents of Config.
112 * @param EffectiveAddr is the device base address in the virtual memory
113 * address space. The caller is responsible for keeping the address
114 * mapping from EffectiveAddr to the device physical base address
115 * unchanged once this function is invoked. Unexpected errors may
116 * occur if the address mapping changes after this function is
117 * called. If address translation is not used, use
118 * ConfigPtr->Config.BaseAddress for this device.
121 * - XST_SUCCESS if successful.
122 * - XST_DEVICE_IS_STARTED if the device is already started.
123 * It must be stopped to re-initialize.
127 ******************************************************************************/
128 s32 XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, XQspiPsu_Config *ConfigPtr,
131 Xil_AssertNonvoid(InstancePtr != NULL);
132 Xil_AssertNonvoid(ConfigPtr != NULL);
136 * If the device is busy, disallow the initialize and return a status
137 * indicating it is already started. This allows the user to stop the
138 * device and re-initialize, but prevents a user from inadvertently
139 * initializing. This assumes the busy flag is cleared at startup.
141 if (InstancePtr->IsBusy == TRUE) {
142 Status = (s32)XST_DEVICE_IS_STARTED;
145 /* Set some default values. */
146 InstancePtr->IsBusy = FALSE;
148 InstancePtr->Config.BaseAddress = EffectiveAddr + XQSPIPSU_OFFSET;
149 InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode;
150 InstancePtr->StatusHandler = StubStatusHandler;
151 InstancePtr->Config.BusWidth = ConfigPtr->BusWidth;
152 InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz;
153 /* Other instance variable initializations */
154 InstancePtr->SendBufferPtr = NULL;
155 InstancePtr->RecvBufferPtr = NULL;
156 InstancePtr->GenFifoBufferPtr = NULL;
157 InstancePtr->TxBytes = 0;
158 InstancePtr->RxBytes = 0;
159 InstancePtr->GenFifoEntries = 0;
160 InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
161 InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER;
162 InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER;
163 InstancePtr->IsUnaligned = 0;
164 InstancePtr->IsManualstart = TRUE;
167 XQspiPsu_Select(InstancePtr, XQSPIPSU_SEL_GQSPI_MASK);
170 * Reset the QSPIPSU device to get it into its initial state. It is
171 * expected that device configuration will take place after this
172 * initialization is done, but before the device is started.
174 XQspiPsu_Reset(InstancePtr);
176 InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
178 Status = XST_SUCCESS;
184 /*****************************************************************************/
187 * Resets the QSPIPSU device. Reset must only be called after the driver has
188 * been initialized. Any data transfer that is in progress is aborted.
190 * The upper layer software is responsible for re-configuring (if necessary)
191 * and restarting the QSPIPSU device after the reset.
193 * @param InstancePtr is a pointer to the XQspiPsu instance.
199 ******************************************************************************/
200 void XQspiPsu_Reset(XQspiPsu *InstancePtr)
204 Xil_AssertVoid(InstancePtr != NULL);
206 /* Abort any transfer that is in progress */
207 XQspiPsu_Abort(InstancePtr);
209 /* Default value to config register */
210 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
211 XQSPIPSU_CFG_OFFSET);
214 ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
215 ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
217 ConfigReg |= XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK;
218 /* Little endain by default */
219 ConfigReg &= ~XQSPIPSU_CFG_ENDIAN_MASK;
220 /* Disable poll timeout */
221 ConfigReg &= ~XQSPIPSU_CFG_EN_POLL_TO_MASK;
223 ConfigReg |= XQSPIPSU_CFG_WP_HOLD_MASK;
224 /* Clear prescalar by default */
225 ConfigReg &= (u32)(~XQSPIPSU_CFG_BAUD_RATE_DIV_MASK);
227 ConfigReg &= (u32)(~XQSPIPSU_CFG_CLK_PHA_MASK);
228 ConfigReg &= (u32)(~XQSPIPSU_CFG_CLK_POL_MASK);
230 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
231 XQSPIPSU_CFG_OFFSET, ConfigReg);
233 /* Set by default to allow for high frequencies */
234 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
235 XQSPIPSU_LPBK_DLY_ADJ_OFFSET,
236 XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
237 XQSPIPSU_LPBK_DLY_ADJ_OFFSET) |
238 XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK);
240 /* Reset thresholds */
241 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
242 XQSPIPSU_TX_THRESHOLD_OFFSET,
243 XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL);
244 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
245 XQSPIPSU_RX_THRESHOLD_OFFSET,
246 XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL);
247 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
248 XQSPIPSU_GF_THRESHOLD_OFFSET,
249 XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL);
252 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
253 XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET,
254 XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL);
258 /*****************************************************************************/
261 * Aborts a transfer in progress by
263 * @param InstancePtr is a pointer to the XQspiPsu instance.
269 ******************************************************************************/
270 void XQspiPsu_Abort(XQspiPsu *InstancePtr)
273 u32 IntrStatus, ConfigReg;
275 IntrStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
276 XQSPIPSU_ISR_OFFSET);
278 /* Clear and disable interrupts */
279 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
280 XQSPIPSU_ISR_OFFSET, IntrStatus | XQSPIPSU_ISR_WR_TO_CLR_MASK);
281 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
282 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET,
283 XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
284 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET));
285 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
286 XQSPIPSU_QSPIDMA_DST_STS_OFFSET,
287 XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
288 XQSPIPSU_QSPIDMA_DST_STS_OFFSET) |
289 XQSPIPSU_QSPIDMA_DST_STS_WTC);
290 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
291 XQSPIPSU_IDR_OFFSET, XQSPIPSU_IDR_ALL_MASK);
292 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
293 XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET,
294 XQSPIPSU_QSPIDMA_DST_INTR_ALL_MASK);
297 if((XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
298 XQSPIPSU_ISR_OFFSET) & XQSPIPSU_ISR_RXEMPTY_MASK) != FALSE) {
299 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
300 XQSPIPSU_FIFO_CTRL_OFFSET,
301 XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK |
302 XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK);
306 * Switch to IO mode to Clear RX FIFO. This is becuase of DMA behaviour
307 * where it waits on RX empty and goes busy assuming there is data
308 * to be transfered even if there is no request.
310 if ((IntrStatus & XQSPIPSU_ISR_RXEMPTY_MASK) != 0U) {
311 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
312 XQSPIPSU_CFG_OFFSET);
313 ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
314 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
315 XQSPIPSU_CFG_OFFSET, ConfigReg);
317 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
318 XQSPIPSU_FIFO_CTRL_OFFSET,
319 XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK);
321 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
322 ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
323 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
324 XQSPIPSU_CFG_OFFSET, ConfigReg);
328 /* Disable QSPIPSU */
329 XQspiPsu_Disable(InstancePtr);
331 InstancePtr->TxBytes = 0;
332 InstancePtr->RxBytes = 0;
333 InstancePtr->GenFifoEntries = 0;
334 InstancePtr->IsBusy = FALSE;
337 /*****************************************************************************/
340 * This function performs a transfer on the bus in polled mode. The messages
341 * passed are all transferred on the bus between one CS assert and de-assert.
343 * @param InstancePtr is a pointer to the XQspiPsu instance.
344 * @param Msg is a pointer to the structure containing transfer data.
345 * @param NumMsg is the number of messages to be transferred.
348 * - XST_SUCCESS if successful.
349 * - XST_FAILURE if transfer fails.
350 * - XST_DEVICE_BUSY if a transfer is already in progress.
354 ******************************************************************************/
355 s32 XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
360 u32 QspiPsuStatusReg;
363 u32 IOPending = (u32)FALSE;
365 Xil_AssertNonvoid(InstancePtr != NULL);
366 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
367 for (Index = 0; Index < (s32)NumMsg; Index++) {
368 Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
371 /* Check whether there is another transfer in progress. Not thread-safe */
372 if (InstancePtr->IsBusy == TRUE) {
373 return (s32)XST_DEVICE_BUSY;
376 /* Check for ByteCount upper limit - 2^28 for DMA */
377 for (Index = 0; Index < (s32)NumMsg; Index++) {
378 if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) &&
379 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
380 return (s32)XST_FAILURE;
385 * Set the busy flag, which will be cleared when the transfer is
388 InstancePtr->IsBusy = TRUE;
390 BaseAddress = InstancePtr->Config.BaseAddress;
393 XQspiPsu_Enable(InstancePtr);
396 XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
400 while (Index < (s32)NumMsg) {
401 XQspiPsu_GenFifoEntryData(InstancePtr, Msg, Index);
403 if (InstancePtr->IsManualstart == TRUE) {
405 xil_printf("\nManual Start\r\n");
407 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
408 XQspiPsu_ReadReg(BaseAddress,
409 XQSPIPSU_CFG_OFFSET) |
410 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
413 /* Use thresholds here */
414 /* If there is more data to be transmitted */
416 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress,
417 XQSPIPSU_ISR_OFFSET);
419 /* Transmit more data if left */
420 if (((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != FALSE) &&
421 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
422 (InstancePtr->TxBytes > 0)) {
423 XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index],
427 /* Check if DMA RX is complete and update RxBytes */
428 if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) &&
429 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
431 DmaIntrSts = XQspiPsu_ReadReg(BaseAddress,
432 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET);
433 if ((DmaIntrSts & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != FALSE) {
434 XQspiPsu_WriteReg(BaseAddress,
435 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET,
437 /* Read remaining bytes using IO mode */
438 if((InstancePtr->RxBytes % 4) != 0 ) {
439 XQspiPsu_WriteReg(BaseAddress,
441 (XQspiPsu_ReadReg(BaseAddress,
442 XQSPIPSU_CFG_OFFSET) &
443 ~XQSPIPSU_CFG_MODE_EN_MASK));
444 InstancePtr->ReadMode = XQSPIPSU_READMODE_IO;
445 Msg[Index].ByteCount =
446 (InstancePtr->RxBytes % 4);
447 Msg[Index].RxBfrPtr += (InstancePtr->RxBytes -
448 (InstancePtr->RxBytes % 4));
449 InstancePtr->IsUnaligned = 1;
450 IOPending = (u32)TRUE;
453 InstancePtr->RxBytes = 0;
456 if ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE) {
457 /* Check if PIO RX is complete and update RxBytes */
458 RxThr = (s32)XQspiPsu_ReadReg(BaseAddress,
459 XQSPIPSU_RX_THRESHOLD_OFFSET);
460 if ((QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK)
462 XQspiPsu_ReadRxFifo(InstancePtr,
463 &Msg[Index], RxThr*4);
466 if ((QspiPsuStatusReg &
467 XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) {
468 XQspiPsu_ReadRxFifo(InstancePtr,
469 &Msg[Index], InstancePtr->RxBytes);
474 } while (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == FALSE) ||
475 (InstancePtr->TxBytes != 0) ||
476 ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == FALSE) ||
477 (InstancePtr->RxBytes != 0));
479 if((InstancePtr->IsUnaligned != 0) && (IOPending == (u32)FALSE)) {
480 InstancePtr->IsUnaligned = 0;
481 XQspiPsu_WriteReg(BaseAddress,
482 XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(
484 XQSPIPSU_CFG_OFFSET) |
485 XQSPIPSU_CFG_MODE_EN_DMA_MASK));
486 InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
489 if (IOPending == (u32)TRUE) {
490 IOPending = (u32)FALSE;
496 /* De-select slave */
497 XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
499 if (InstancePtr->IsManualstart == TRUE) {
501 xil_printf("\nManual Start\r\n");
503 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
504 XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) |
505 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
508 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET);
509 while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == FALSE) {
510 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress,
511 XQSPIPSU_ISR_OFFSET);
514 /* Clear the busy flag. */
515 InstancePtr->IsBusy = FALSE;
517 /* Disable the device. */
518 XQspiPsu_Disable(InstancePtr);
523 /*****************************************************************************/
526 * This function initiates a transfer on the bus and enables interrupts.
527 * The transfer is completed by the interrupt handler. The messages passed are
528 * all transferred on the bus between one CS assert and de-assert.
530 * @param InstancePtr is a pointer to the XQspiPsu instance.
531 * @param Msg is a pointer to the structure containing transfer data.
532 * @param NumMsg is the number of messages to be transferred.
535 * - XST_SUCCESS if successful.
536 * - XST_FAILURE if transfer fails.
537 * - XST_DEVICE_BUSY if a transfer is already in progress.
541 ******************************************************************************/
542 s32 XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
549 Xil_AssertNonvoid(InstancePtr != NULL);
550 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
551 for (Index = 0; Index < (s32)NumMsg; Index++) {
552 Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
555 /* Check whether there is another transfer in progress. Not thread-safe */
556 if (InstancePtr->IsBusy == TRUE) {
557 return (s32)XST_DEVICE_BUSY;
560 if (Msg[0].Flags & XQSPIPSU_MSG_FLAG_POLL) {
561 InstancePtr->IsBusy = TRUE;
562 XQspiPsu_PollData(InstancePtr, Msg);
564 /* Check for ByteCount upper limit - 2^28 for DMA */
565 for (Index = 0; Index < (s32)NumMsg; Index++) {
566 if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) &&
567 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
568 return (s32)XST_FAILURE;
573 * Set the busy flag, which will be cleared when the transfer is
576 InstancePtr->IsBusy = TRUE;
578 BaseAddress = InstancePtr->Config.BaseAddress;
580 InstancePtr->Msg = Msg;
581 InstancePtr->NumMsg = (s32)NumMsg;
582 InstancePtr->MsgCnt = 0;
585 XQspiPsu_Enable(InstancePtr);
588 XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
590 /* This might not work if not manual start */
591 /* Put first message in FIFO along with the above slave select */
592 XQspiPsu_GenFifoEntryData(InstancePtr, Msg, 0);
594 if (InstancePtr->IsManualstart == TRUE) {
596 xil_printf("\nManual Start\r\n");
598 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
599 XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) |
600 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
603 /* Enable interrupts */
604 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IER_OFFSET,
605 (u32)XQSPIPSU_IER_TXNOT_FULL_MASK | (u32)XQSPIPSU_IER_TXEMPTY_MASK |
606 (u32)XQSPIPSU_IER_RXNEMPTY_MASK | (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
607 (u32)XQSPIPSU_IER_RXEMPTY_MASK);
609 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
610 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET,
611 XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK);
617 /*****************************************************************************/
620 * Handles interrupt based transfers by acting on GENFIFO and DMA interurpts.
622 * @param InstancePtr is a pointer to the XQspiPsu instance.
625 * - XST_SUCCESS if successful.
626 * - XST_FAILURE if transfer fails.
630 ******************************************************************************/
631 s32 XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr)
633 u32 QspiPsuStatusReg, DmaIntrStatusReg = 0;
642 Xil_AssertNonvoid(InstancePtr != NULL);
644 BaseAddress = InstancePtr->Config.BaseAddress;
645 Msg = InstancePtr->Msg;
646 NumMsg = InstancePtr->NumMsg;
647 MsgCnt = InstancePtr->MsgCnt;
648 TxRxFlag = Msg[MsgCnt].Flags;
650 /* QSPIPSU Intr cleared on read */
651 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET);
652 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
653 /* DMA Intr write to clear */
654 DmaIntrStatusReg = XQspiPsu_ReadReg(BaseAddress,
655 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET);
657 XQspiPsu_WriteReg(BaseAddress,
658 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrStatusReg);
660 if (((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK) != FALSE)) {
661 /* Call status handler to indicate error */
662 InstancePtr->StatusHandler(InstancePtr->StatusRef,
663 XST_SPI_COMMAND_ERROR, 0);
666 /* Fill more data to be txed if required */
667 if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
668 ((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != FALSE) &&
669 (InstancePtr->TxBytes > 0)) {
670 XQspiPsu_FillTxFifo(InstancePtr, &Msg[MsgCnt],
675 * Check if the entry is ONLY TX and increase MsgCnt.
676 * This is to allow TX and RX together in one entry - corner case.
678 if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
679 ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) != FALSE) &&
680 ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) &&
681 (InstancePtr->TxBytes == 0) &&
682 ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == FALSE)) {
687 if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) &&
688 (MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
689 if ((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != FALSE) {
690 /* Read remaining bytes using IO mode */
691 if((InstancePtr->RxBytes % 4) != 0 ) {
692 XQspiPsu_WriteReg(BaseAddress,
693 XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(
694 BaseAddress, XQSPIPSU_CFG_OFFSET) &
695 ~XQSPIPSU_CFG_MODE_EN_MASK));
696 InstancePtr->ReadMode = XQSPIPSU_READMODE_IO;
697 Msg[MsgCnt].ByteCount = (InstancePtr->RxBytes % 4);
698 Msg[MsgCnt].RxBfrPtr += (InstancePtr->RxBytes -
699 (InstancePtr->RxBytes % 4));
700 InstancePtr->IsUnaligned = 1;
701 XQspiPsu_GenFifoEntryData(InstancePtr, Msg,
703 if(InstancePtr->IsManualstart == TRUE) {
705 xil_printf("\nManual Start\r\n");
707 XQspiPsu_WriteReg(BaseAddress,
709 XQspiPsu_ReadReg(BaseAddress,
710 XQSPIPSU_CFG_OFFSET) |
711 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
715 InstancePtr->RxBytes = 0;
721 if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
722 if (InstancePtr->RxBytes != 0) {
723 if ((QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK)
725 RxThr = (s32)XQspiPsu_ReadReg(BaseAddress,
726 XQSPIPSU_RX_THRESHOLD_OFFSET);
727 XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt],
730 if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) &&
731 ((QspiPsuStatusReg & XQSPIPSU_ISR_RXEMPTY_MASK) == FALSE)) {
732 XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt],
733 InstancePtr->RxBytes);
736 if (InstancePtr->RxBytes == 0) {
745 * Dummy byte transfer
746 * MsgCnt < NumMsg check is to ensure is it a valid dummy cycle message
747 * If one of the above conditions increased MsgCnt, then
748 * the new message is yet to be placed in the FIFO; hence !DeltaMsgCnt.
750 if ((MsgCnt < NumMsg) && (DeltaMsgCnt == FALSE) &&
751 ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == FALSE) &&
752 ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) == FALSE) &&
753 ((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) == FALSE) &&
754 ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE)) {
758 InstancePtr->MsgCnt = MsgCnt;
761 * DeltaMsgCnt is to handle conditions where genfifo empty can be set
762 * while tx is still not empty or rx dma is not yet done.
763 * MsgCnt > NumMsg indicates CS de-assert entry was also executed.
765 if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) &&
766 ((DeltaMsgCnt != FALSE) || (MsgCnt > NumMsg))) {
767 if (MsgCnt < NumMsg) {
768 if(InstancePtr->IsUnaligned != 0) {
769 InstancePtr->IsUnaligned = 0;
770 XQspiPsu_WriteReg(InstancePtr->Config.
771 BaseAddress, XQSPIPSU_CFG_OFFSET,
772 (XQspiPsu_ReadReg(InstancePtr->Config.
773 BaseAddress, XQSPIPSU_CFG_OFFSET) |
774 XQSPIPSU_CFG_MODE_EN_DMA_MASK));
775 InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
777 /* This might not work if not manual start */
778 XQspiPsu_GenFifoEntryData(InstancePtr, Msg, MsgCnt);
780 if (InstancePtr->IsManualstart == TRUE) {
782 xil_printf("\nManual Start\r\n");
784 XQspiPsu_WriteReg(BaseAddress,
786 XQspiPsu_ReadReg(BaseAddress,
787 XQSPIPSU_CFG_OFFSET) |
788 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
790 } else if (MsgCnt == NumMsg) {
791 /* This is just to keep track of the de-assert entry */
793 InstancePtr->MsgCnt = MsgCnt;
795 /* De-select slave */
796 XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
798 if (InstancePtr->IsManualstart == TRUE) {
800 xil_printf("\nManual Start\r\n");
802 XQspiPsu_WriteReg(BaseAddress,
804 XQspiPsu_ReadReg(BaseAddress,
805 XQSPIPSU_CFG_OFFSET) |
806 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
809 /* Disable interrupts */
810 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IDR_OFFSET,
811 (u32)XQSPIPSU_IER_TXNOT_FULL_MASK |
812 (u32)XQSPIPSU_IER_TXEMPTY_MASK |
813 (u32)XQSPIPSU_IER_RXNEMPTY_MASK |
814 (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
815 (u32)XQSPIPSU_IER_RXEMPTY_MASK);
816 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
817 XQspiPsu_WriteReg(BaseAddress,
818 XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET,
819 XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK);
822 /* Clear the busy flag. */
823 InstancePtr->IsBusy = FALSE;
825 /* Disable the device. */
826 XQspiPsu_Disable(InstancePtr);
828 /* Call status handler to indicate completion */
829 InstancePtr->StatusHandler(InstancePtr->StatusRef,
830 XST_SPI_TRANSFER_DONE, 0);
833 if ((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) != FALSE){
834 if (QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK){
836 * Read data from RXFIFO, since when data from the flash device
837 * (status data) matched with configured value in poll_cfg, then
838 * controller writes the matched data into RXFIFO.
840 XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_RXD_OFFSET);
842 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IDR_OFFSET,
843 (u32)XQSPIPSU_IER_TXNOT_FULL_MASK |
844 (u32)XQSPIPSU_IER_TXEMPTY_MASK |
845 (u32)XQSPIPSU_IER_RXNEMPTY_MASK |
846 (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
847 (u32)XQSPIPSU_IER_RXEMPTY_MASK |
848 (u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK);
849 InstancePtr->StatusHandler(InstancePtr->StatusRef, XST_SPI_POLL_DONE, 0);
851 InstancePtr->IsBusy = FALSE;
852 /* Disable the device. */
853 XQspiPsu_Disable(InstancePtr);
856 if (QspiPsuStatusReg & XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK){
857 InstancePtr->StatusHandler(InstancePtr->StatusRef,
858 XST_FLASH_TIMEOUT_ERROR, 0);
864 /*****************************************************************************/
867 * Sets the status callback function, the status handler, which the driver
868 * calls when it encounters conditions that should be reported to upper
869 * layer software. The handler executes in an interrupt context, so it must
870 * minimize the amount of processing performed. One of the following status
871 * events is passed to the status handler.
875 * XST_SPI_TRANSFER_DONE The requested data transfer is done
877 * XST_SPI_TRANSMIT_UNDERRUN As a slave device, the master clocked data
878 * but there were none available in the transmit
879 * register/FIFO. This typically means the slave
880 * application did not issue a transfer request
881 * fast enough, or the processor/driver could not
882 * fill the transmit register/FIFO fast enough.
884 * XST_SPI_RECEIVE_OVERRUN The QSPIPSU device lost data. Data was received
885 * but the receive data register/FIFO was full.
888 * @param InstancePtr is a pointer to the XQspiPsu instance.
889 * @param CallBackRef is the upper layer callback reference passed back
890 * when the callback function is invoked.
891 * @param FuncPointer is the pointer to the callback function.
897 * The handler is called within interrupt context, so it should do its work
898 * quickly and queue potentially time-consuming work to a task-level thread.
900 ******************************************************************************/
901 void XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef,
902 XQspiPsu_StatusHandler FuncPointer)
904 Xil_AssertVoid(InstancePtr != NULL);
905 Xil_AssertVoid(FuncPointer != NULL);
906 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
908 InstancePtr->StatusHandler = FuncPointer;
909 InstancePtr->StatusRef = CallBackRef;
912 /*****************************************************************************/
915 * This is a stub for the status callback. The stub is here in case the upper
916 * layers forget to set the handler.
918 * @param CallBackRef is a pointer to the upper layer callback reference
919 * @param StatusEvent is the event that just occurred.
920 * @param ByteCount is the number of bytes transferred up until the event
927 ******************************************************************************/
928 static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
931 (void *) CallBackRef;
935 Xil_AssertVoidAlways();
938 /*****************************************************************************/
941 * Selects SPI mode - x1 or x2 or x4.
943 * @param SpiMode - spi or dual or quad.
944 * @return Mask to set desired SPI mode in GENFIFO entry.
948 ******************************************************************************/
949 static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode)
954 xil_printf("\nXQspiPsu_SelectSpiMode\r\n");
958 case XQSPIPSU_SELECT_MODE_DUALSPI:
959 Mask = XQSPIPSU_GENFIFO_MODE_DUALSPI;
961 case XQSPIPSU_SELECT_MODE_QUADSPI:
962 Mask = XQSPIPSU_GENFIFO_MODE_QUADSPI;
964 case XQSPIPSU_SELECT_MODE_SPI:
965 Mask = XQSPIPSU_GENFIFO_MODE_SPI;
968 Mask = XQSPIPSU_GENFIFO_MODE_SPI;
972 xil_printf("\nSPIMode is %08x\r\n", SpiMode);
978 /*****************************************************************************/
981 * This function checks the TX/RX buffers in the message and setups up the
982 * GENFIFO entries, TX FIFO or RX DMA as required.
984 * @param InstancePtr is a pointer to the XQspiPsu instance.
985 * @param Msg is a pointer to the structure containing transfer data.
986 * @param GenFifoEntry is pointer to the variable in which GENFIFO mask
987 * is returned to calling function
993 ******************************************************************************/
994 static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
997 Xil_AssertVoid(InstancePtr != NULL);
1000 if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
1001 ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == FALSE)) {
1002 /* Setup data to be TXed */
1003 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
1004 *GenFifoEntry |= XQSPIPSU_GENFIFO_TX;
1005 InstancePtr->TxBytes = (s32)Msg->ByteCount;
1006 InstancePtr->SendBufferPtr = Msg->TxBfrPtr;
1007 InstancePtr->RecvBufferPtr = NULL;
1008 XQspiPsu_FillTxFifo(InstancePtr, Msg, XQSPIPSU_TXD_DEPTH);
1009 /* Discard RX data */
1010 *GenFifoEntry &= ~XQSPIPSU_GENFIFO_RX;
1011 InstancePtr->RxBytes = 0;
1015 if (((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE) &&
1016 ((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == FALSE)) {
1018 *GenFifoEntry &= ~XQSPIPSU_GENFIFO_TX;
1019 InstancePtr->TxBytes = 0;
1021 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
1022 *GenFifoEntry |= XQSPIPSU_GENFIFO_RX;
1023 InstancePtr->RxBytes = (s32)Msg->ByteCount;
1024 InstancePtr->SendBufferPtr = NULL;
1025 InstancePtr->RecvBufferPtr = Msg->RxBfrPtr;
1026 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
1027 XQspiPsu_SetupRxDma(InstancePtr, Msg);
1031 /* If only dummy is requested as a separate entry */
1032 if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == FALSE) &&
1033 (Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == FALSE) {
1034 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
1035 *GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX);
1036 InstancePtr->TxBytes = 0;
1037 InstancePtr->RxBytes = 0;
1038 InstancePtr->SendBufferPtr = NULL;
1039 InstancePtr->RecvBufferPtr = NULL;
1042 /* Dummy and cmd sent by upper layer to received data */
1043 if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != FALSE) &&
1044 ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
1045 *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
1046 *GenFifoEntry |= (XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX);
1047 InstancePtr->TxBytes = (s32)Msg->ByteCount;
1048 InstancePtr->RxBytes = (s32)Msg->ByteCount;
1049 InstancePtr->SendBufferPtr = Msg->TxBfrPtr;
1050 InstancePtr->RecvBufferPtr = Msg->RxBfrPtr;
1051 XQspiPsu_FillTxFifo(InstancePtr, Msg, XQSPIPSU_TXD_DEPTH);
1052 /* Add check for DMA or PIO here */
1053 if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
1054 XQspiPsu_SetupRxDma(InstancePtr, Msg);
1059 /*****************************************************************************/
1062 * Fills the TX FIFO as long as there is room in the FIFO or the bytes required
1063 * to be transmitted.
1065 * @param InstancePtr is a pointer to the XQspiPsu instance.
1066 * @param Msg is a pointer to the structure containing transfer data.
1067 * @param Size is the number of bytes to be transmitted.
1073 ******************************************************************************/
1074 static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr,
1075 XQspiPsu_Msg *Msg, s32 Size)
1080 Xil_AssertVoid(InstancePtr != NULL);
1083 xil_printf("\nXQspiPsu_FillTxFifo\r\n");
1086 while ((InstancePtr->TxBytes > 0) && (Count < Size)) {
1087 if (InstancePtr->TxBytes >= 4) {
1088 (void)memcpy(&Data, Msg->TxBfrPtr, 4);
1090 InstancePtr->TxBytes -= 4;
1093 (void)memcpy(&Data, Msg->TxBfrPtr, InstancePtr->TxBytes);
1094 Msg->TxBfrPtr += InstancePtr->TxBytes;
1095 Count += InstancePtr->TxBytes;
1096 InstancePtr->TxBytes = 0;
1098 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1099 XQSPIPSU_TXD_OFFSET, Data);
1101 xil_printf("\nData is %08x\r\n", Data);
1105 if (InstancePtr->TxBytes < 0) {
1106 InstancePtr->TxBytes = 0;
1110 /*****************************************************************************/
1113 * This function sets up the RX DMA operation.
1115 * @param InstancePtr is a pointer to the XQspiPsu instance.
1116 * @param Msg is a pointer to the structure containing transfer data.
1122 ******************************************************************************/
1123 static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr,
1130 Xil_AssertVoid(InstancePtr != NULL);
1132 AddrTemp = (u64)((INTPTR)(Msg->RxBfrPtr) &
1133 XQSPIPSU_QSPIDMA_DST_ADDR_MASK);
1134 /* Check for RXBfrPtr to be word aligned */
1135 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1136 XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET,
1139 AddrTemp = AddrTemp >> 32;
1140 if ((AddrTemp & 0xFFFU) != FALSE) {
1141 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1142 XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET,
1144 XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK);
1147 Remainder = InstancePtr->RxBytes % 4;
1148 DmaRxBytes = InstancePtr->RxBytes;
1149 if (Remainder != 0) {
1150 /* This is done to make Dma bytes aligned */
1151 DmaRxBytes = InstancePtr->RxBytes - Remainder;
1152 Msg->ByteCount = (u32)DmaRxBytes;
1155 Xil_DCacheInvalidateRange((INTPTR)InstancePtr->RecvBufferPtr, Msg->ByteCount);
1157 /* Write no. of words to DMA DST SIZE */
1158 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1159 XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes);
1163 /*****************************************************************************/
1166 * This function writes the GENFIFO entry to assert CS.
1168 * @param InstancePtr is a pointer to the XQspiPsu instance.
1174 ******************************************************************************/
1175 static inline void XQspiPsu_GenFifoEntryCSAssert(XQspiPsu *InstancePtr)
1180 xil_printf("\nXQspiPsu_GenFifoEntryCSAssert\r\n");
1183 GenFifoEntry = 0x0U;
1184 GenFifoEntry &= ~((u32)XQSPIPSU_GENFIFO_DATA_XFER | (u32)XQSPIPSU_GENFIFO_EXP);
1185 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_MODE_MASK);
1186 GenFifoEntry |= XQSPIPSU_GENFIFO_MODE_SPI;
1187 GenFifoEntry |= InstancePtr->GenFifoCS;
1188 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_BUS_MASK);
1189 GenFifoEntry |= InstancePtr->GenFifoBus;
1190 GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX |
1191 XQSPIPSU_GENFIFO_STRIPE | XQSPIPSU_GENFIFO_POLL);
1192 GenFifoEntry |= XQSPIPSU_GENFIFO_CS_SETUP;
1194 xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry);
1196 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1197 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1200 /*****************************************************************************/
1203 * This function writes the GENFIFO entries to transmit the messages requested.
1205 * @param InstancePtr is a pointer to the XQspiPsu instance.
1206 * @param Msg is a pointer to the structure containing transfer data.
1207 * @param Index of the current message to be handled.
1210 * - XST_SUCCESS if successful.
1211 * - XST_FAILURE if transfer fails.
1212 * - XST_DEVICE_BUSY if a transfer is already in progress.
1216 ******************************************************************************/
1217 static inline void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr,
1218 XQspiPsu_Msg *Msg, s32 Index)
1226 xil_printf("\nXQspiPsu_GenFifoEntryData\r\n");
1229 BaseAddress = InstancePtr->Config.BaseAddress;
1231 GenFifoEntry = 0x0U;
1233 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_MODE_MASK);
1234 GenFifoEntry |= XQspiPsu_SelectSpiMode((u8)Msg[Index].BusWidth);
1236 GenFifoEntry |= InstancePtr->GenFifoCS;
1237 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_BUS_MASK);
1238 GenFifoEntry |= InstancePtr->GenFifoBus;
1241 if (((Msg[Index].Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != FALSE) {
1242 GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE;
1244 GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE;
1247 /* If Byte Count is less than 8 bytes do the transfer in IO mode */
1248 if ((Msg[Index].ByteCount < 8U) &&
1249 (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA)) {
1250 InstancePtr->ReadMode = XQSPIPSU_READMODE_IO;
1251 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
1252 (XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) &
1253 ~XQSPIPSU_CFG_MODE_EN_MASK));
1254 InstancePtr->IsUnaligned = 1;
1257 XQspiPsu_TXRXSetup(InstancePtr, &Msg[Index], &GenFifoEntry);
1259 if (Msg[Index].ByteCount < XQSPIPSU_GENFIFO_IMM_DATA_MASK) {
1260 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK);
1261 GenFifoEntry |= Msg[Index].ByteCount;
1263 xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry);
1265 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET,
1268 TempCount = Msg[Index].ByteCount;
1269 u32 Exponent = 8; /* 2^8 = 256 */
1271 ImmData = TempCount & 0xFFU;
1272 /* Exponent entries */
1273 GenFifoEntry |= XQSPIPSU_GENFIFO_EXP;
1274 while (TempCount != 0U) {
1275 if ((TempCount & XQSPIPSU_GENFIFO_EXP_START) != FALSE) {
1276 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK);
1277 GenFifoEntry |= Exponent;
1279 xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry);
1281 XQspiPsu_WriteReg(BaseAddress,
1282 XQSPIPSU_GEN_FIFO_OFFSET,
1285 TempCount = TempCount >> 1;
1289 /* Immediate entry */
1290 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_EXP);
1291 if ((ImmData & 0xFFU) != FALSE) {
1292 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK);
1293 GenFifoEntry |= ImmData & 0xFFU;
1295 xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry);
1297 XQspiPsu_WriteReg(BaseAddress,
1298 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1302 /* One dummy GenFifo entry in case of IO mode */
1303 if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) &&
1304 ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) {
1305 GenFifoEntry = 0x0U;
1307 xil_printf("\nDummy FifoEntry=%08x\r\n",GenFifoEntry);
1309 XQspiPsu_WriteReg(BaseAddress,
1310 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1314 /*****************************************************************************/
1317 * This function writes the GENFIFO entry to de-assert CS.
1319 * @param InstancePtr is a pointer to the XQspiPsu instance.
1325 ******************************************************************************/
1326 static inline void XQspiPsu_GenFifoEntryCSDeAssert(XQspiPsu *InstancePtr)
1331 xil_printf("\nXQspiPsu_GenFifoEntryCSDeAssert\r\n");
1334 GenFifoEntry = 0x0U;
1335 GenFifoEntry &= ~((u32)XQSPIPSU_GENFIFO_DATA_XFER | (u32)XQSPIPSU_GENFIFO_EXP);
1336 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_MODE_MASK);
1337 GenFifoEntry |= XQSPIPSU_GENFIFO_MODE_SPI;
1338 GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_BUS_MASK);
1339 GenFifoEntry |= InstancePtr->GenFifoBus;
1340 GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX |
1341 XQSPIPSU_GENFIFO_STRIPE | XQSPIPSU_GENFIFO_POLL);
1342 GenFifoEntry |= XQSPIPSU_GENFIFO_CS_HOLD;
1344 xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry);
1346 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1347 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1350 /*****************************************************************************/
1353 * Read the specified number of bytes from RX FIFO
1355 * @param InstancePtr is a pointer to the XQspiPsu instance.
1356 * @param Msg is a pointer to the structure containing transfer data.
1357 * @param Size is the number of bytes to be read.
1363 ******************************************************************************/
1364 static inline void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr,
1365 XQspiPsu_Msg *Msg, s32 Size)
1371 xil_printf("\nXQspiPsu_ReadRxFifo\r\n");
1374 Xil_AssertVoid(InstancePtr != NULL);
1375 Xil_AssertVoid(Msg != NULL);
1377 while ((InstancePtr->RxBytes != 0) && (Count < Size)) {
1378 Data = XQspiPsu_ReadReg(InstancePtr->
1379 Config.BaseAddress, XQSPIPSU_RXD_OFFSET);
1381 xil_printf("\nData is %08x\r\n", Data);
1383 if (InstancePtr->RxBytes >= 4) {
1384 (void)memcpy(Msg->RxBfrPtr, &Data, 4);
1385 InstancePtr->RxBytes -= 4;
1389 /* Read unaligned bytes (< 4 bytes) */
1390 (void)memcpy(Msg->RxBfrPtr, &Data, InstancePtr->RxBytes);
1391 Msg->RxBfrPtr += InstancePtr->RxBytes;
1392 Count += InstancePtr->RxBytes;
1393 InstancePtr->RxBytes = 0;
1398 /*****************************************************************************/
1401 * This function enables the polling functionality of controller
1403 * @param QspiPsuPtr is a pointer to the XQspiPsu instance.
1405 * @param Statuscommand is the status command which send by controller.
1407 * @param FlashMsg is a pointer to the structure containing transfer data
1413 ******************************************************************************/
1414 void XQspiPsu_PollData(XQspiPsu *QspiPsuPtr, XQspiPsu_Msg *FlashMsg)
1420 Xil_AssertVoid(QspiPsuPtr != NULL);
1421 Xil_AssertVoid(FlashMsg != NULL );
1423 Value = XQspiPsu_Create_PollConfigData(QspiPsuPtr, FlashMsg);
1424 XQspiPsu_WriteReg(QspiPsuPtr->Config.BaseAddress,
1425 XQSPIPSU_POLL_CFG_OFFSET, Value);
1426 XQspiPsu_WriteReg(QspiPsuPtr->Config.BaseAddress,
1427 XQSPIPSU_P_TO_OFFSET, FlashMsg->PollTimeout);
1429 XQspiPsu_Enable(QspiPsuPtr);
1431 GenFifoEntry = (u32)0;
1432 GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_TX;
1433 GenFifoEntry |= QspiPsuPtr->GenFifoBus;
1434 GenFifoEntry |= QspiPsuPtr->GenFifoCS;
1435 GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI;
1436 GenFifoEntry |= (u32)FlashMsg->PollStatusCmd;
1438 XQspiPsu_WriteReg(QspiPsuPtr->Config.BaseAddress,
1439 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1440 XQspiPsu_WriteReg(QspiPsuPtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
1441 (XQSPIPSU_CFG_START_GEN_FIFO_MASK
1442 | XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK));
1444 GenFifoEntry = (u32)0;
1445 GenFifoEntry = (u32)XQSPIPSU_GENFIFO_POLL;
1446 GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_RX;
1447 GenFifoEntry |= QspiPsuPtr->GenFifoBus;
1448 GenFifoEntry |= QspiPsuPtr->GenFifoCS;
1449 GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI;
1450 if (((FlashMsg->Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != FALSE)
1451 GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE;
1453 GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE;
1455 XQspiPsu_WriteReg(QspiPsuPtr->Config.BaseAddress,
1456 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1458 QspiPsuPtr->Msg = FlashMsg;
1459 QspiPsuPtr->NumMsg = (s32)1;
1460 QspiPsuPtr->MsgCnt = 0;
1462 Value = XQspiPsu_ReadReg(QspiPsuPtr->Config.BaseAddress,
1463 XQSPIPSU_CFG_OFFSET);
1464 Value |= (XQSPIPSU_CFG_START_GEN_FIFO_MASK |
1465 XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK |
1466 XQSPIPSU_CFG_EN_POLL_TO_MASK);
1467 XQspiPsu_WriteReg(QspiPsuPtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
1470 /* Enable interrupts */
1471 Value = ((u32)XQSPIPSU_IER_TXNOT_FULL_MASK |
1472 (u32)XQSPIPSU_IER_TXEMPTY_MASK |
1473 (u32)XQSPIPSU_IER_RXNEMPTY_MASK |
1474 (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
1475 (u32)XQSPIPSU_IER_RXEMPTY_MASK |
1476 (u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK);
1477 XQspiPsu_WriteReg(QspiPsuPtr->Config.BaseAddress, XQSPIPSU_IER_OFFSET,
1481 /*****************************************************************************/
1484 * This function creates Poll config register data to write
1486 * @param BusMask is mask to enable/disable upper/lower data bus masks.
1488 * @param DataBusMask is Data bus mask value during poll operation.
1490 * @param Data is the poll data value to write into config regsiter.
1496 ******************************************************************************/
1497 static inline u32 XQspiPsu_Create_PollConfigData(XQspiPsu *QspiPsuPtr,
1498 XQspiPsu_Msg *FlashMsg)
1502 if (QspiPsuPtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_UPPER)
1503 ConfigData = XQSPIPSU_SELECT_FLASH_BUS_LOWER <<
1504 XQSPIPSU_POLL_CFG_EN_MASK_UPPER_SHIFT;
1505 if (QspiPsuPtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_LOWER)
1506 ConfigData |= XQSPIPSU_SELECT_FLASH_BUS_LOWER <<
1507 XQSPIPSU_POLL_CFG_EN_MASK_LOWER_SHIFT;
1508 ConfigData |= ((FlashMsg->PollBusMask << XQSPIPSU_POLL_CFG_MASK_EN_SHIFT)
1509 & XQSPIPSU_POLL_CFG_MASK_EN_MASK);
1510 ConfigData |= ((FlashMsg->PollData << XQSPIPSU_POLL_CFG_DATA_VALUE_SHIFT)
1511 & XQSPIPSU_POLL_CFG_DATA_VALUE_MASK);