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 /*****************************************************************************/
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.
41 * MODIFICATION HISTORY:
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.
53 ******************************************************************************/
55 /***************************** Include Files *********************************/
59 /************************** Constant Definitions *****************************/
61 /**************************** Type Definitions *******************************/
63 /***************** Macros (Inline Functions) Definitions *********************/
65 /************************** Function Prototypes ******************************/
66 static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
68 static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode);
69 static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
71 static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr,
72 XQspiPsu_Msg *Msg, int Size);
73 static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr,
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);
82 /************************** Variable Definitions *****************************/
84 /*****************************************************************************/
87 * Initializes a specific XQspiPsu instance such that the driver is ready to use.
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
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.
104 * - XST_SUCCESS if successful.
105 * - XST_DEVICE_IS_STARTED if the device is already started.
106 * It must be stopped to re-initialize.
110 ******************************************************************************/
111 int XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, XQspiPsu_Config *ConfigPtr,
114 Xil_AssertNonvoid(InstancePtr != NULL);
115 Xil_AssertNonvoid(ConfigPtr != NULL);
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.
123 if (InstancePtr->IsBusy == TRUE) {
124 return XST_DEVICE_IS_STARTED;
127 /* Set some default values. */
128 InstancePtr->IsBusy = FALSE;
130 InstancePtr->Config.BaseAddress = EffectiveAddr + XQSPIPSU_OFFSET;
131 InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode;
132 InstancePtr->StatusHandler = StubStatusHandler;
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;
147 XQspiPsu_Select(InstancePtr);
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.
154 XQspiPsu_Reset(InstancePtr);
156 InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
161 /*****************************************************************************/
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.
167 * The upper layer software is responsible for re-configuring (if necessary)
168 * and restarting the QSPIPSU device after the reset.
170 * @param InstancePtr is a pointer to the XQspiPsu instance.
176 ******************************************************************************/
177 void XQspiPsu_Reset(XQspiPsu *InstancePtr)
181 Xil_AssertVoid(InstancePtr != NULL);
183 /* Abort any transfer that is in progress */
184 XQspiPsu_Abort(InstancePtr);
186 /* Default value to config register */
187 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
188 XQSPIPSU_CFG_OFFSET);
191 ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
192 ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
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;
200 ConfigReg |= XQSPIPSU_CFG_WP_HOLD_MASK;
201 /* Clear prescalar by default */
202 ConfigReg &= ~XQSPIPSU_CFG_BAUD_RATE_DIV_MASK;
204 ConfigReg &= ~XQSPIPSU_CFG_CLK_PHA_MASK;
205 ConfigReg &= ~XQSPIPSU_CFG_CLK_POL_MASK;
207 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
208 XQSPIPSU_CFG_OFFSET, ConfigReg);
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);
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);
229 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
230 XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET,
231 XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL);
235 /*****************************************************************************/
238 * Aborts a transfer in progress by
240 * @param InstancePtr is a pointer to the XQspiPsu instance.
246 ******************************************************************************/
247 void XQspiPsu_Abort(XQspiPsu *InstancePtr)
250 u32 IntrStatus, ConfigReg;
252 IntrStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
253 XQSPIPSU_ISR_OFFSET);
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);
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);
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.
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);
294 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
295 XQSPIPSU_FIFO_CTRL_OFFSET,
296 XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK);
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);
305 /* Disable QSPIPSU */
306 XQspiPsu_Disable(InstancePtr);
308 InstancePtr->TxBytes = 0;
309 InstancePtr->RxBytes = 0;
310 InstancePtr->GenFifoEntries = 0;
311 InstancePtr->IsBusy = FALSE;
314 /*****************************************************************************/
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.
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.
325 * - XST_SUCCESS if successful.
326 * - XST_FAILURE if transfer fails.
327 * - XST_DEVICE_BUSY if a transfer is already in progress.
331 ******************************************************************************/
332 int XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
338 u8 IsManualStart = FALSE;
339 u32 QspiPsuStatusReg, DmaStatusReg;
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);
350 /* Check whether there is another transfer in progress. Not thread-safe */
351 if (InstancePtr->IsBusy) {
352 return XST_DEVICE_BUSY;
356 * Set the busy flag, which will be cleared when the transfer is
359 InstancePtr->IsBusy = TRUE;
361 BaseAddress = InstancePtr->Config.BaseAddress;
363 /* Start if manual start */
364 IsManualStart = XQspiPsu_IsManualStart(InstancePtr);
367 XQspiPsu_Enable(InstancePtr);
370 XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
373 for (Index = 0; Index < NumMsg; Index++) {
376 Status = XQspiPsu_GenFifoEntryData(InstancePtr, Msg, Index);
377 if (Status != XST_SUCCESS) {
382 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
383 XQspiPsu_ReadReg(BaseAddress,
384 XQSPIPSU_CFG_OFFSET) |
385 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
388 /* Use thresholds here */
389 /* If there is more data to be transmitted */
391 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress,
392 XQSPIPSU_ISR_OFFSET);
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],
402 /* Check if DMA RX is complete and update RxBytes */
403 if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) &&
404 (Msg[Index].RxBfrPtr != NULL)) {
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,
412 /* Read remaining bytes using IO mode */
413 if(InstancePtr->RxBytes % 4 != 0 ) {
414 XQspiPsu_WriteReg(BaseAddress,
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;
427 InstancePtr->RxBytes = 0;
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)
435 XQspiPsu_ReadRxFifo(InstancePtr,
438 } else if ((QspiPsuStatusReg &
439 XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) {
440 XQspiPsu_ReadRxFifo(InstancePtr,
441 &Msg[Index], InstancePtr->RxBytes);
444 } while (!(QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) ||
445 (InstancePtr->TxBytes != 0) ||
446 !(QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) ||
447 (InstancePtr->RxBytes != 0));
449 if(InstancePtr->IsUnaligned) {
450 InstancePtr->IsUnaligned = 0;
451 XQspiPsu_WriteReg(BaseAddress,
452 XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(
454 XQSPIPSU_CFG_OFFSET) |
455 XQSPIPSU_CFG_MODE_EN_DMA_MASK));
456 InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
460 /* De-select slave */
461 XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
464 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
465 XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) |
466 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
469 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET);
470 while (!(QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK)) {
471 QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress,
472 XQSPIPSU_ISR_OFFSET);
475 /* Clear the busy flag. */
476 InstancePtr->IsBusy = FALSE;
478 /* Disable the device. */
479 XQspiPsu_Disable(InstancePtr);
484 /*****************************************************************************/
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.
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.
496 * - XST_SUCCESS if successful.
497 * - XST_FAILURE if transfer fails.
498 * - XST_DEVICE_BUSY if a transfer is already in progress.
502 ******************************************************************************/
503 int XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
509 u8 IsManualStart = FALSE;
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);
519 /* Check whether there is another transfer in progress. Not thread-safe */
520 if (InstancePtr->IsBusy) {
521 return XST_DEVICE_BUSY;
525 * Set the busy flag, which will be cleared when the transfer is
528 InstancePtr->IsBusy = TRUE;
530 BaseAddress = InstancePtr->Config.BaseAddress;
532 /* Start if manual start */
533 IsManualStart = XQspiPsu_IsManualStart(InstancePtr);
535 InstancePtr->Msg = Msg;
536 InstancePtr->NumMsg = NumMsg;
537 InstancePtr->MsgCnt = 0;
540 XQspiPsu_Enable(InstancePtr);
543 XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
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) {
553 XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET,
554 XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) |
555 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
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);
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);
571 /*****************************************************************************/
574 * Handles interrupt based transfers by acting on GENFIFO and DMA interurpts.
576 * @param InstancePtr is a pointer to the XQspiPsu instance.
579 * - XST_SUCCESS if successful.
580 * - XST_FAILURE if transfer fails.
584 ******************************************************************************/
585 int XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr)
587 u8 IsManualStart = FALSE;
588 u32 QspiPsuStatusReg, DmaIntrStatusReg;
596 Xil_AssertNonvoid(InstancePtr != NULL);
598 BaseAddress = InstancePtr->Config.BaseAddress;
599 Msg = InstancePtr->Msg;
600 NumMsg = InstancePtr->NumMsg;
601 MsgCnt = InstancePtr->MsgCnt;
603 /* Start if manual start */
604 IsManualStart = XQspiPsu_IsManualStart(InstancePtr);
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);
613 XQspiPsu_WriteReg(BaseAddress,
614 XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrStatusReg);
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);
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],
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.
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)) {
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,
661 XQspiPsu_WriteReg(BaseAddress,
663 XQspiPsu_ReadReg(BaseAddress,
664 XQSPIPSU_CFG_OFFSET) |
665 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
669 InstancePtr->RxBytes = 0;
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)
680 XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt],
682 } else if ((QspiPsuStatusReg &
683 XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0) {
684 XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt],
685 InstancePtr->RxBytes);
687 if (InstancePtr->RxBytes == 0) {
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.
700 if ((MsgCnt < NumMsg) && !DeltaMsgCnt &&
701 (Msg[MsgCnt].RxBfrPtr == NULL) &&
702 (Msg[MsgCnt].TxBfrPtr == NULL) &&
703 (QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK)) {
707 InstancePtr->MsgCnt = MsgCnt;
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.
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;
726 /* This might not work if not manual start */
727 XQspiPsu_GenFifoEntryData(InstancePtr, Msg, MsgCnt);
730 XQspiPsu_WriteReg(BaseAddress,
732 XQspiPsu_ReadReg(BaseAddress,
733 XQSPIPSU_CFG_OFFSET) |
734 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
736 } else if (MsgCnt == NumMsg) {
737 /* This is just to keep track of the de-assert entry */
739 InstancePtr->MsgCnt = MsgCnt;
741 /* De-select slave */
742 XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
745 XQspiPsu_WriteReg(BaseAddress,
747 XQspiPsu_ReadReg(BaseAddress,
748 XQSPIPSU_CFG_OFFSET) |
749 XQSPIPSU_CFG_START_GEN_FIFO_MASK);
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);
764 /* Clear the busy flag. */
765 InstancePtr->IsBusy = FALSE;
767 /* Disable the device. */
768 XQspiPsu_Disable(InstancePtr);
770 /* Call status handler to indicate completion */
771 InstancePtr->StatusHandler(InstancePtr->StatusRef,
772 XST_SPI_TRANSFER_DONE, 0);
779 /*****************************************************************************/
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.
790 * XST_SPI_TRANSFER_DONE The requested data transfer is done
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.
799 * XST_SPI_RECEIVE_OVERRUN The QSPIPSU device lost data. Data was received
800 * but the receive data register/FIFO was full.
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.
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.
815 ******************************************************************************/
816 void XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef,
817 XQspiPsu_StatusHandler FuncPtr)
819 Xil_AssertVoid(InstancePtr != NULL);
820 Xil_AssertVoid(FuncPtr != NULL);
821 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
823 InstancePtr->StatusHandler = FuncPtr;
824 InstancePtr->StatusRef = CallBackRef;
827 /*****************************************************************************/
830 * This is a stub for the status callback. The stub is here in case the upper
831 * layers forget to set the handler.
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
842 ******************************************************************************/
843 static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
850 Xil_AssertVoidAlways();
853 /*****************************************************************************/
856 * Selects SPI mode - x1 or x2 or x4.
858 * @param SpiMode - spi or dual or quad.
859 * @return Mask to set desired SPI mode in GENFIFO entry.
863 ******************************************************************************/
864 static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode)
868 case XQSPIPSU_SELECT_MODE_DUALSPI:
869 Mask = XQSPIPSU_GENFIFO_MODE_DUALSPI;
871 case XQSPIPSU_SELECT_MODE_QUADSPI:
872 Mask = XQSPIPSU_GENFIFO_MODE_QUADSPI;
874 case XQSPIPSU_SELECT_MODE_SPI:
876 Mask = XQSPIPSU_GENFIFO_MODE_SPI;
882 /*****************************************************************************/
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.
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
897 ******************************************************************************/
898 static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
901 Xil_AssertVoid(InstancePtr != NULL);
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;
916 if ((Msg->TxBfrPtr == NULL) && (Msg->RxBfrPtr != NULL)) {
918 *GenFifoEntry &= ~XQSPIPSU_GENFIFO_TX;
919 InstancePtr->TxBytes = 0;
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);
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;
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);
951 /*****************************************************************************/
954 * Fills the TX FIFO as long as there is room in the FIFO or the bytes required
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.
965 ******************************************************************************/
966 static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr,
967 XQspiPsu_Msg *Msg, int Size)
972 Xil_AssertVoid(InstancePtr != NULL);
973 Xil_AssertVoid(Msg->TxBfrPtr != NULL);
975 while ((InstancePtr->TxBytes > 0) && (Count < Size)) {
976 Data = *((u32*)Msg->TxBfrPtr);
977 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
978 XQSPIPSU_TXD_OFFSET, Data);
980 InstancePtr->TxBytes -= 4;
983 if (InstancePtr->TxBytes < 0)
984 InstancePtr->TxBytes = 0;
987 /*****************************************************************************/
990 * This function sets up the RX DMA operation.
992 * @param InstancePtr is a pointer to the XQspiPsu instance.
993 * @param Msg is a pointer to the structure containing transfer data.
999 ******************************************************************************/
1000 static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr,
1007 Xil_AssertVoid(InstancePtr != NULL);
1008 Xil_AssertVoid(Msg->RxBfrPtr != NULL);
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,
1017 AddrTemp = AddrTemp >> 32;
1018 if (AddrTemp & 0xFFF) {
1019 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1020 XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET,
1022 XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK);
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;
1033 /* Write no. of words to DMA DST SIZE */
1034 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1035 XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, DmaRxBytes);
1039 /*****************************************************************************/
1042 * This function writes the GENFIFO entry to assert CS.
1044 * @param InstancePtr is a pointer to the XQspiPsu instance.
1050 ******************************************************************************/
1051 static inline void XQspiPsu_GenFifoEntryCSAssert(XQspiPsu *InstancePtr)
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;
1066 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1067 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1070 /*****************************************************************************/
1073 * This function writes the GENFIFO entries to transmit the messages requested.
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.
1080 * - XST_SUCCESS if successful.
1081 * - XST_FAILURE if transfer fails.
1082 * - XST_DEVICE_BUSY if a transfer is already in progress.
1086 ******************************************************************************/
1087 static inline int XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr,
1088 XQspiPsu_Msg *Msg, int Index)
1095 BaseAddress = InstancePtr->Config.BaseAddress;
1099 GenFifoEntry &= ~XQSPIPSU_GENFIFO_MODE_MASK;
1100 GenFifoEntry |= XQspiPsu_SelectSpiMode(Msg[Index].BusWidth);
1102 GenFifoEntry |= InstancePtr->GenFifoCS;
1103 GenFifoEntry &= ~XQSPIPSU_GENFIFO_BUS_MASK;
1104 GenFifoEntry |= InstancePtr->GenFifoBus;
1107 if (Msg[Index].Flags & XQSPIPSU_MSG_FLAG_STRIPE)
1108 GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE;
1110 GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE;
1112 XQspiPsu_TXRXSetup(InstancePtr, &Msg[Index], &GenFifoEntry);
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,
1120 TempCount = Msg[Index].ByteCount;
1121 u32 Exponent = 8; /* 2^8 = 256 */
1123 /* Check for ByteCount upper limit - 2^28 for DMA */
1124 if (TempCount > XQSPIPSU_DMA_BYTES_MAX) {
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,
1139 TempCount = TempCount >> 1;
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);
1156 /*****************************************************************************/
1159 * This function writes the GENFIFO entry to de-assert CS.
1161 * @param InstancePtr is a pointer to the XQspiPsu instance.
1167 ******************************************************************************/
1168 static inline void XQspiPsu_GenFifoEntryCSDeAssert(XQspiPsu *InstancePtr)
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;
1182 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
1183 XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
1186 /*****************************************************************************/
1189 * Read the specified number of bytes from RX FIFO
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.
1199 ******************************************************************************/
1200 static inline void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr,
1201 XQspiPsu_Msg *Msg, int Size)
1206 Xil_AssertVoid(InstancePtr != NULL);
1207 Xil_AssertVoid(Msg != NULL);
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;
1218 /* Read unaligned bytes (< 4 bytes) */
1219 while (InstancePtr->RxBytes != 0) {
1220 *Msg->RxBfrPtr = Data;
1221 InstancePtr->RxBytes--;