/****************************************************************************** * * Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * * @file xqspips.c * * Contains implements the interface functions of the XQspiPs driver. * See xqspips.h for a detailed description of the device and driver. * *
* MODIFICATION HISTORY:
*
* Ver   Who Date     Changes
* ----- --- -------- -----------------------------------------------
* 1.00  sdm 11/25/10 First release
* 2.00a kka 07/25/12 Removed XQspiPs_GetWriteData API.
*		     The XQspiPs_SetSlaveSelect has been modified to remove
*		     the argument of the slave select as the QSPI controller
*		     only supports one slave.
* 		     XQspiPs_GetSlaveSelect API has been removed
* 		     Added logic to XQspiPs_GetReadData to handle data
*		     shift for normal data reads and instruction/status
*		     reads differently based on the ShiftReadData flag.
* 		     Removed the selection for the following options:
*		     Master mode (XQSPIPS_MASTER_OPTION) and
*		     Flash interface mode (XQSPIPS_FLASH_MODE_OPTION) option
*		     as the QSPI driver supports the Master mode
*		     and Flash Interface mode and doesnot support
*		     Slave mode or the legacy mode.
*		     Modified the XQspiPs_PolledTransfer and XQspiPs_Transfer
*		     APIs so that the last argument (IsInst) specifying whether
*		     it is instruction or data has been removed. The first byte
*		     in the SendBufPtr argument of these APIs specify the
*		     instruction to be sent to the Flash Device.
*		     The XQspiPs_PolledTransfer function has been updated
*		     to fill the data to fifo depth.
*		     This version of the driver fixes CRs 670197/663787.
* 2.01a sg  02/03/13 Added flash opcodes for DUAL_IO_READ,QUAD_IO_READ.
*		     Created macros XQspiPs_IsManualStart and
*		     XQspiPs_IsManualChipSelect.
*		     Changed QSPI transfer logic for polled and interrupt
*		     modes to be based on filled tx fifo count and receive
*		     based on it. RXNEMPTY interrupt is not used.
*		     Added assertions to XQspiPs_LqspiRead function.
*
* 2.02a hk  05/14/13 Added enable and disable to the XQspiPs_LqspiRead()
*			 function
*            Added instructions for bank selection, die erase and
*            flag status register to the flash instruction table
*            Handling for instructions not in flash instruction
*			 table added. Checking for Tx FIFO empty when switching from
*			 TXD1/2/3 to TXD0 added. If WRSR instruction is sent with
*            byte count 3 (spansion), instruction size and TXD register
*			 changed accordingly. CR# 712502 and 703869.
*            Added (#ifdef linear base address) in the Linear read function.
*            Changed  XPAR_XQSPIPS_0_LINEAR_BASEADDR to
*            XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR in
*            XQspiPs_LqspiRead function. Fix for CR#718141
*
* 2.03a hk  09/05/13 Modified polled and interrupt transfers to make use of
*                    thresholds. This is to improve performance.
*                    Added RX and TX threshold reset to one in XQspiPs_Abort.
*                    Added RX threshold reset(1) after transfer in polled and
*                    interrupt transfers. Made changes to make sure threshold
*                    change is done only when no transfer is in progress.
* 3.1   hk  06/19/14 When writng configuration register, set/reset
*                    required bits leaving reserved bits untouched. CR# 796813.
*
* 
* ******************************************************************************/ /***************************** Include Files *********************************/ #include "xqspips.h" /************************** Constant Definitions *****************************/ /**************************** Type Definitions *******************************/ /** * This typedef defines qspi flash instruction format */ typedef struct { u8 OpCode; /**< Operational code of the instruction */ u8 InstSize; /**< Size of the instruction including address bytes */ u8 TxOffset; /**< Register address where instruction has to be written */ } XQspiPsInstFormat; /***************** Macros (Inline Functions) Definitions *********************/ #define ARRAY_SIZE(Array) (sizeof(Array) / sizeof((Array)[0])) /************************** Function Prototypes ******************************/ static void XQspiPs_GetReadData(XQspiPs *InstancePtr, u32 Data, u8 Size); static void StubStatusHandler(void *CallBackRef, u32 StatusEvent, unsigned ByteCount); /************************** Variable Definitions *****************************/ /* * List of all the QSPI instructions and its format */ static XQspiPsInstFormat FlashInst[] = { { XQSPIPS_FLASH_OPCODE_WREN, 1, XQSPIPS_TXD_01_OFFSET }, { XQSPIPS_FLASH_OPCODE_WRDS, 1, XQSPIPS_TXD_01_OFFSET }, { XQSPIPS_FLASH_OPCODE_RDSR1, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_RDSR2, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_WRSR, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_PP, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_SE, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_BE_32K, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_BE_4K, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_BE, 1, XQSPIPS_TXD_01_OFFSET }, { XQSPIPS_FLASH_OPCODE_ERASE_SUS, 1, XQSPIPS_TXD_01_OFFSET }, { XQSPIPS_FLASH_OPCODE_ERASE_RES, 1, XQSPIPS_TXD_01_OFFSET }, { XQSPIPS_FLASH_OPCODE_RDID, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_NORM_READ, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_FAST_READ, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_DUAL_READ, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_QUAD_READ, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_DUAL_IO_READ, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_QUAD_IO_READ, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_BRWR, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_BRRD, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_EARWR, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_EARRD, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_DIE_ERASE, 4, XQSPIPS_TXD_00_OFFSET }, { XQSPIPS_FLASH_OPCODE_READ_FLAG_SR, 2, XQSPIPS_TXD_10_OFFSET }, { XQSPIPS_FLASH_OPCODE_CLEAR_FLAG_SR, 1, XQSPIPS_TXD_01_OFFSET }, /* Add all the instructions supported by the flash device */ }; /*****************************************************************************/ /** * * Initializes a specific XQspiPs instance such that the driver is ready to use. * * The state of the device after initialization is: * - Master mode * - Active high clock polarity * - Clock phase 0 * - Baud rate divisor 2 * - Transfer width 32 * - Master reference clock = pclk * - No chip select active * - Manual CS and Manual Start disabled * * @param InstancePtr is a pointer to the XQspiPs instance. * @param ConfigPtr is a reference to a structure containing information * about a specific QSPI device. This function initializes an * InstancePtr object for a specific device specified by the * contents of Config. * @param EffectiveAddr is the device base address in the virtual memory * address space. The caller is responsible for keeping the address * mapping from EffectiveAddr to the device physical base address * unchanged once this function is invoked. Unexpected errors may * occur if the address mapping changes after this function is * called. If address translation is not used, use * ConfigPtr->Config.BaseAddress for this device. * * @return * - XST_SUCCESS if successful. * - XST_DEVICE_IS_STARTED if the device is already started. * It must be stopped to re-initialize. * * @note None. * ******************************************************************************/ int XQspiPs_CfgInitialize(XQspiPs *InstancePtr, XQspiPs_Config *ConfigPtr, u32 EffectiveAddr) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(ConfigPtr != NULL); /* * If the device is busy, disallow the initialize and return a status * indicating it is already started. This allows the user to stop the * device and re-initialize, but prevents a user from inadvertently * initializing. This assumes the busy flag is cleared at startup. */ if (InstancePtr->IsBusy == TRUE) { return XST_DEVICE_IS_STARTED; } /* * Set some default values. */ InstancePtr->IsBusy = FALSE; InstancePtr->Config.BaseAddress = EffectiveAddr; InstancePtr->StatusHandler = StubStatusHandler; InstancePtr->SendBufferPtr = NULL; InstancePtr->RecvBufferPtr = NULL; InstancePtr->RequestedBytes = 0; InstancePtr->RemainingBytes = 0; InstancePtr->IsReady = XIL_COMPONENT_IS_READY; InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode; /* * Reset the QSPI device to get it into its initial state. It is * expected that device configuration will take place after this * initialization is done, but before the device is started. */ XQspiPs_Reset(InstancePtr); return XST_SUCCESS; } /*****************************************************************************/ /** * * Resets the QSPI device. Reset must only be called after the driver has been * initialized. Any data transfer that is in progress is aborted. * * The upper layer software is responsible for re-configuring (if necessary) * and restarting the QSPI device after the reset. * * @param InstancePtr is a pointer to the XQspiPs instance. * * @return None. * * @note None. * ******************************************************************************/ void XQspiPs_Reset(XQspiPs *InstancePtr) { u32 ConfigReg; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Abort any transfer that is in progress */ XQspiPs_Abort(InstancePtr); /* * Write default value to configuration register. * Do not modify reserved bits. */ ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg | XQSPIPS_CR_RESET_STATE); } /*****************************************************************************/ /** * * Aborts a transfer in progress by disabling the device and flush the RxFIFO. * The byte counts are cleared, the busy flag is cleared. * * @param InstancePtr is a pointer to the XQspiPs instance. * * @return None. * * @note * * This function does a read/modify/write of the config register. The user of * this function needs to take care of critical sections. * ******************************************************************************/ void XQspiPs_Abort(XQspiPs *InstancePtr) { u32 ConfigReg; XQspiPs_Disable(InstancePtr); /* * De-assert slave select lines. */ ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= (XQSPIPS_CR_SSCTRL_MASK | XQSPIPS_CR_SSFORCE_MASK); XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); /* * Set the RX and TX FIFO threshold to reset value (one) */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXWR_OFFSET, XQSPIPS_RXWR_RESET_VALUE); XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_TXWR_OFFSET, XQSPIPS_TXWR_RESET_VALUE); /* * Clear the RX FIFO and drop any data. */ while ((XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_SR_OFFSET) & XQSPIPS_IXR_RXNEMPTY_MASK) != 0) { XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); } InstancePtr->RemainingBytes = 0; InstancePtr->RequestedBytes = 0; InstancePtr->IsBusy = FALSE; } /*****************************************************************************/ /** * * Transfers specified data on the QSPI bus. Initiates bus communication and * sends/receives data to/from the selected QSPI slave. For every byte sent, * a byte is received. * * The caller has the option of providing two different buffers for send and * receive, or one buffer for both send and receive, or no buffer for receive. * The receive buffer must be at least as big as the send buffer to prevent * unwanted memory writes. This implies that the byte count passed in as an * argument must be the smaller of the two buffers if they differ in size. * Here are some sample usages: *
*   XQspiPs_Transfer(InstancePtr, SendBuf, RecvBuf, ByteCount)
*	The caller wishes to send and receive, and provides two different
*	buffers for send and receive.
*
*   XQspiPs_Transfer(InstancePtr, SendBuf, NULL, ByteCount)
*	The caller wishes only to send and does not care about the received
*	data. The driver ignores the received data in this case.
*
*   XQspiPs_Transfer(InstancePtr, SendBuf, SendBuf, ByteCount)
*	The caller wishes to send and receive, but provides the same buffer
*	for doing both. The driver sends the data and overwrites the send
*	buffer with received data as it transfers the data.
*
*   XQspiPs_Transfer(InstancePtr, RecvBuf, RecvBuf, ByteCount)
*	The caller wishes to only receive and does not care about sending
*	data.  In this case, the caller must still provide a send buffer, but
*	it can be the same as the receive buffer if the caller does not care
*	what it sends.  The device must send N bytes of data if it wishes to
*	receive N bytes of data.
* 
* Although this function takes entire buffers as arguments, the driver can only * transfer a limited number of bytes at a time, limited by the size of the * FIFO. A call to this function only starts the transfer, then subsequent * transfers of the data is performed by the interrupt service routine until * the entire buffer has been transferred. The status callback function is * called when the entire buffer has been sent/received. * * This function is non-blocking. The SetSlaveSelect function must be called * prior to this function. * * @param InstancePtr is a pointer to the XQspiPs instance. * @param SendBufPtr is a pointer to a data buffer that needs to be * transmitted. This buffer must not be NULL. * @param RecvBufPtr is a pointer to a buffer for received data. * This argument can be NULL if do not care about receiving. * @param ByteCount contains the number of bytes to send/receive. * The number of bytes received always equals the number of bytes * sent. * * @return * - XST_SUCCESS if the buffers are successfully handed off to the * device for transfer. * - XST_DEVICE_BUSY indicates that a data transfer is already in * progress. This is determined by the driver. * * @note * * This function is not thread-safe. The higher layer software must ensure that * no two threads are transferring data on the QSPI bus at the same time. * ******************************************************************************/ int XQspiPs_Transfer(XQspiPs *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, unsigned ByteCount) { u32 StatusReg; u32 ConfigReg; u8 Instruction; u32 Data; unsigned int Index; u8 TransCount = 0; XQspiPsInstFormat *CurrInst; XQspiPsInstFormat NewInst[2]; u8 SwitchFlag = 0; CurrInst = &NewInst[0]; /* * The RecvBufPtr argument can be null */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(SendBufPtr != NULL); Xil_AssertNonvoid(ByteCount > 0); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Check whether there is another transfer in progress. Not thread-safe. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Set the busy flag, which will be cleared in the ISR when the * transfer is entirely done. */ InstancePtr->IsBusy = TRUE; /* * Set up buffer pointers. */ InstancePtr->SendBufferPtr = SendBufPtr; InstancePtr->RecvBufferPtr = RecvBufPtr; InstancePtr->RequestedBytes = ByteCount; InstancePtr->RemainingBytes = ByteCount; /* * The first byte with every chip-select assertion is always * expected to be an instruction for flash interface mode */ Instruction = *InstancePtr->SendBufferPtr; for (Index = 0 ; Index < ARRAY_SIZE(FlashInst); Index++) { if (Instruction == FlashInst[Index].OpCode) { break; } } /* * Set the RX FIFO threshold */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXWR_OFFSET, XQSPIPS_RXFIFO_THRESHOLD_OPT); /* * If the slave select is "Forced" or under manual control, * set the slave select now, before beginning the transfer. */ if (XQspiPs_IsManualChipSelect(InstancePtr)) { ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg &= ~XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Enable the device. */ XQspiPs_Enable(InstancePtr); /* * Clear all the interrrupts. */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_SR_OFFSET, XQSPIPS_IXR_WR_TO_CLR_MASK); if (Index < ARRAY_SIZE(FlashInst)) { CurrInst = &FlashInst[Index]; /* * Check for WRSR instruction which has different size for * Spansion (3 bytes) and Micron (2 bytes) */ if( (CurrInst->OpCode == XQSPIPS_FLASH_OPCODE_WRSR) && (ByteCount == 3) ) { CurrInst->InstSize = 3; CurrInst->TxOffset = XQSPIPS_TXD_11_OFFSET; } } /* * If instruction not present in table */ if (Index == ARRAY_SIZE(FlashInst)) { /* * Assign current instruction, size and TXD register to be used * The InstSize mentioned in case of instructions greater than * 4 bytes is not the actual size, but is indicative of * the TXD register used. * The remaining bytes of the instruction will be transmitted * through TXD0 below. */ switch(ByteCount%4) { case XQSPIPS_SIZE_ONE: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_ONE; CurrInst->TxOffset = XQSPIPS_TXD_01_OFFSET; if(ByteCount > 4) { SwitchFlag = 1; } break; case XQSPIPS_SIZE_TWO: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_TWO; CurrInst->TxOffset = XQSPIPS_TXD_10_OFFSET; if(ByteCount > 4) { SwitchFlag = 1; } break; case XQSPIPS_SIZE_THREE: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_THREE; CurrInst->TxOffset = XQSPIPS_TXD_11_OFFSET; if(ByteCount > 4) { SwitchFlag = 1; } break; default: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_FOUR; CurrInst->TxOffset = XQSPIPS_TXD_00_OFFSET; break; } } /* * If the instruction size in not 4 bytes then the data received needs * to be shifted */ if( CurrInst->InstSize != 4 ) { InstancePtr->ShiftReadData = 1; } else { InstancePtr->ShiftReadData = 0; } /* Get the complete command (flash inst + address/data) */ Data = *((u32 *)InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += CurrInst->InstSize; InstancePtr->RemainingBytes -= CurrInst->InstSize; if (InstancePtr->RemainingBytes < 0) { InstancePtr->RemainingBytes = 0; } /* Write the command to the FIFO */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, CurrInst->TxOffset, Data); TransCount++; /* * If switching from TXD1/2/3 to TXD0, then start transfer and * check for FIFO empty */ if(SwitchFlag == 1) { SwitchFlag = 0; /* * If, in Manual Start mode, start the transfer. */ if (XQspiPs_IsManualStart(InstancePtr)) { ConfigReg = XQspiPs_ReadReg( InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_MANSTRT_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Wait for the transfer to finish by polling Tx fifo status. */ do { StatusReg = XQspiPs_ReadReg( InstancePtr->Config.BaseAddress, XQSPIPS_SR_OFFSET); } while ((StatusReg & XQSPIPS_IXR_TXOW_MASK) == 0); } /* * Fill the Tx FIFO with as many bytes as it takes (or as many as * we have to send). */ while ((InstancePtr->RemainingBytes > 0) && (TransCount < XQSPIPS_FIFO_DEPTH)) { XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_TXD_00_OFFSET, *((u32 *)InstancePtr->SendBufferPtr)); InstancePtr->SendBufferPtr += 4; InstancePtr->RemainingBytes -= 4; if (InstancePtr->RemainingBytes < 0) { InstancePtr->RemainingBytes = 0; } TransCount++; } /* * Enable QSPI interrupts (connecting to the interrupt controller and * enabling interrupts should have been done by the caller). */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_IER_OFFSET, XQSPIPS_IXR_RXNEMPTY_MASK | XQSPIPS_IXR_TXOW_MASK | XQSPIPS_IXR_RXOVR_MASK | XQSPIPS_IXR_TXUF_MASK); /* * If, in Manual Start mode, Start the transfer. */ if (XQspiPs_IsManualStart(InstancePtr)) { ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_MANSTRT_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } return XST_SUCCESS; } /*****************************************************************************/ /** * Transfers specified data on the QSPI bus in polled mode. * * The caller has the option of providing two different buffers for send and * receive, or one buffer for both send and receive, or no buffer for receive. * The receive buffer must be at least as big as the send buffer to prevent * unwanted memory writes. This implies that the byte count passed in as an * argument must be the smaller of the two buffers if they differ in size. * Here are some sample usages: *
*   XQspiPs_PolledTransfer(InstancePtr, SendBuf, RecvBuf, ByteCount)
*	The caller wishes to send and receive, and provides two different
*	buffers for send and receive.
*
*   XQspiPs_PolledTransfer(InstancePtr, SendBuf, NULL, ByteCount)
*	The caller wishes only to send and does not care about the received
*	data. The driver ignores the received data in this case.
*
*   XQspiPs_PolledTransfer(InstancePtr, SendBuf, SendBuf, ByteCount)
*	The caller wishes to send and receive, but provides the same buffer
*	for doing both. The driver sends the data and overwrites the send
*	buffer with received data as it transfers the data.
*
*   XQspiPs_PolledTransfer(InstancePtr, RecvBuf, RecvBuf, ByteCount)
*	The caller wishes to only receive and does not care about sending
*	data.  In this case, the caller must still provide a send buffer, but
*	it can be the same as the receive buffer if the caller does not care
*	what it sends.  The device must send N bytes of data if it wishes to
*	receive N bytes of data.
*
* 
* * @param InstancePtr is a pointer to the XQspiPs instance. * @param SendBufPtr is a pointer to a data buffer that needs to be * transmitted. This buffer must not be NULL. * @param RecvBufPtr is a pointer to a buffer for received data. * This argument can be NULL if do not care about receiving. * @param ByteCount contains the number of bytes to send/receive. * The number of bytes received always equals the number of bytes * sent. * @return * - XST_SUCCESS if the buffers are successfully handed off to the * device for transfer. * - XST_DEVICE_BUSY indicates that a data transfer is already in * progress. This is determined by the driver. * * @note * * This function is not thread-safe. The higher layer software must ensure that * no two threads are transferring data on the QSPI bus at the same time. * ******************************************************************************/ int XQspiPs_PolledTransfer(XQspiPs *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, unsigned ByteCount) { u32 StatusReg; u32 ConfigReg; u8 Instruction; u32 Data; u8 TransCount; unsigned int Index; XQspiPsInstFormat *CurrInst; XQspiPsInstFormat NewInst[2]; u8 SwitchFlag = 0; u8 IsManualStart = FALSE; u32 RxCount = 0; CurrInst = &NewInst[0]; /* * The RecvBufPtr argument can be NULL. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(SendBufPtr != NULL); Xil_AssertNonvoid(ByteCount > 0); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Check whether there is another transfer in progress. Not thread-safe. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Set the busy flag, which will be cleared when the transfer is * entirely done. */ InstancePtr->IsBusy = TRUE; /* * Set up buffer pointers. */ InstancePtr->SendBufferPtr = SendBufPtr; InstancePtr->RecvBufferPtr = RecvBufPtr; InstancePtr->RequestedBytes = ByteCount; InstancePtr->RemainingBytes = ByteCount; /* * The first byte with every chip-select assertion is always * expected to be an instruction for flash interface mode */ Instruction = *InstancePtr->SendBufferPtr; for (Index = 0 ; Index < ARRAY_SIZE(FlashInst); Index++) { if (Instruction == FlashInst[Index].OpCode) { break; } } /* * Set the RX FIFO threshold */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXWR_OFFSET, XQSPIPS_RXFIFO_THRESHOLD_OPT); /* * If the slave select is "Forced" or under manual control, * set the slave select now, before beginning the transfer. */ if (XQspiPs_IsManualChipSelect(InstancePtr)) { ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg &= ~XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Enable the device. */ XQspiPs_Enable(InstancePtr); if (Index < ARRAY_SIZE(FlashInst)) { CurrInst = &FlashInst[Index]; /* * Check for WRSR instruction which has different size for * Spansion (3 bytes) and Micron (2 bytes) */ if( (CurrInst->OpCode == XQSPIPS_FLASH_OPCODE_WRSR) && (ByteCount == 3) ) { CurrInst->InstSize = 3; CurrInst->TxOffset = XQSPIPS_TXD_11_OFFSET; } } /* * If instruction not present in table */ if (Index == ARRAY_SIZE(FlashInst)) { /* * Assign current instruction, size and TXD register to be used. * The InstSize mentioned in case of instructions greater than 4 bytes * is not the actual size, but is indicative of the TXD register used. * The remaining bytes of the instruction will be transmitted * through TXD0 below. */ switch(ByteCount%4) { case XQSPIPS_SIZE_ONE: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_ONE; CurrInst->TxOffset = XQSPIPS_TXD_01_OFFSET; if(ByteCount > 4) { SwitchFlag = 1; } break; case XQSPIPS_SIZE_TWO: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_TWO; CurrInst->TxOffset = XQSPIPS_TXD_10_OFFSET; if(ByteCount > 4) { SwitchFlag = 1; } break; case XQSPIPS_SIZE_THREE: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_THREE; CurrInst->TxOffset = XQSPIPS_TXD_11_OFFSET; if(ByteCount > 4) { SwitchFlag = 1; } break; default: CurrInst->OpCode = Instruction; CurrInst->InstSize = XQSPIPS_SIZE_FOUR; CurrInst->TxOffset = XQSPIPS_TXD_00_OFFSET; break; } } /* * If the instruction size in not 4 bytes then the data received needs * to be shifted */ if( CurrInst->InstSize != 4 ) { InstancePtr->ShiftReadData = 1; } else { InstancePtr->ShiftReadData = 0; } TransCount = 0; /* Get the complete command (flash inst + address/data) */ Data = *((u32 *)InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += CurrInst->InstSize; InstancePtr->RemainingBytes -= CurrInst->InstSize; if (InstancePtr->RemainingBytes < 0) { InstancePtr->RemainingBytes = 0; } /* Write the command to the FIFO */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, CurrInst->TxOffset, Data); ++TransCount; /* * If switching from TXD1/2/3 to TXD0, then start transfer and * check for FIFO empty */ if(SwitchFlag == 1) { SwitchFlag = 0; /* * If, in Manual Start mode, start the transfer. */ if (XQspiPs_IsManualStart(InstancePtr)) { ConfigReg = XQspiPs_ReadReg( InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_MANSTRT_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Wait for the transfer to finish by polling Tx fifo status. */ do { StatusReg = XQspiPs_ReadReg( InstancePtr->Config.BaseAddress, XQSPIPS_SR_OFFSET); } while ((StatusReg & XQSPIPS_IXR_TXOW_MASK) == 0); } /* * Check if manual start is selected and store it in a * local varibale for reference. This is to avoid reading * the config register everytime. */ IsManualStart = XQspiPs_IsManualStart(InstancePtr); /* * Fill the DTR/FIFO with as many bytes as it will take (or as * many as we have to send). */ while ((InstancePtr->RemainingBytes > 0) && (TransCount < XQSPIPS_FIFO_DEPTH)) { XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_TXD_00_OFFSET, *((u32 *)InstancePtr->SendBufferPtr)); InstancePtr->SendBufferPtr += 4; InstancePtr->RemainingBytes -= 4; if (InstancePtr->RemainingBytes < 0) { InstancePtr->RemainingBytes = 0; } ++TransCount; } while((InstancePtr->RemainingBytes > 0) || (InstancePtr->RequestedBytes > 0)) { /* * Fill the TX FIFO with RX threshold no. of entries (or as * many as we have to send, in case that's less). */ while ((InstancePtr->RemainingBytes > 0) && (TransCount < XQSPIPS_RXFIFO_THRESHOLD_OPT)) { XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_TXD_00_OFFSET, *((u32 *)InstancePtr->SendBufferPtr)); InstancePtr->SendBufferPtr += 4; InstancePtr->RemainingBytes -= 4; if (InstancePtr->RemainingBytes < 0) { InstancePtr->RemainingBytes = 0; } ++TransCount; } /* * If, in Manual Start mode, start the transfer. */ if (IsManualStart == TRUE) { ConfigReg = XQspiPs_ReadReg( InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_MANSTRT_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Reset TransCount - this is only used to fill TX FIFO * in the above loop; * RxCount is used to keep track of data received */ TransCount = 0; /* * Wait for RX FIFO to reach threshold (or) * TX FIFO to become empty. * The latter check is required for * small transfers (<32 words) and * when the last chunk in a large data transfer is < 32 words. */ do { StatusReg = XQspiPs_ReadReg( InstancePtr->Config.BaseAddress, XQSPIPS_SR_OFFSET); } while ( ((StatusReg & XQSPIPS_IXR_TXOW_MASK) == 0) && ((StatusReg & XQSPIPS_IXR_RXNEMPTY_MASK) == 0) ); /* * A transmit has just completed. Process received data * and check for more data to transmit. * First get the data received as a result of the * transmit that just completed. Receive data based on the * count obtained while filling tx fifo. Always get * the received data, but only fill the receive * buffer if it points to something (the upper layer * software may not care to receive data). */ while ((InstancePtr->RequestedBytes > 0) && (RxCount < XQSPIPS_RXFIFO_THRESHOLD_OPT )) { u32 Data; RxCount++; if (InstancePtr->RecvBufferPtr != NULL) { if (InstancePtr->RequestedBytes < 4) { Data = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); XQspiPs_GetReadData(InstancePtr, Data, InstancePtr->RequestedBytes); } else { (*(u32 *)InstancePtr->RecvBufferPtr) = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); InstancePtr->RecvBufferPtr += 4; InstancePtr->RequestedBytes -= 4; if (InstancePtr->RequestedBytes < 0) { InstancePtr->RequestedBytes = 0; } } } else { Data = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); InstancePtr->RequestedBytes -= 4; } } RxCount = 0; } /* * If the Slave select lines are being manually controlled, disable * them because the transfer is complete. */ if (XQspiPs_IsManualChipSelect(InstancePtr)) { ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Clear the busy flag. */ InstancePtr->IsBusy = FALSE; /* * Disable the device. */ XQspiPs_Disable(InstancePtr); /* * Reset the RX FIFO threshold to one */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_RXWR_OFFSET, XQSPIPS_RXWR_RESET_VALUE); return XST_SUCCESS; } /*****************************************************************************/ /** * * Read the flash in Linear QSPI mode. * * @param InstancePtr is a pointer to the XQspiPs instance. * @param RecvBufPtr is a pointer to a buffer for received data. * @param Address is the starting address within the flash from * from where data needs to be read. * @param ByteCount contains the number of bytes to receive. * * @return * - XST_SUCCESS if read is performed * - XST_FAILURE if Linear mode is not set * * @note None. * * ******************************************************************************/ int XQspiPs_LqspiRead(XQspiPs *InstancePtr, u8 *RecvBufPtr, u32 Address, unsigned ByteCount) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(RecvBufPtr != NULL); Xil_AssertNonvoid(ByteCount > 0); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); #ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR /* * Enable the controller */ XQspiPs_Enable(InstancePtr); if (XQspiPs_GetLqspiConfigReg(InstancePtr) & XQSPIPS_LQSPI_CR_LINEAR_MASK) { memcpy((void*)RecvBufPtr, (const void*)(XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR + Address), (size_t)ByteCount); return XST_SUCCESS; } else { return XST_FAILURE; } /* * Disable the controller */ XQspiPs_Disable(InstancePtr); #else return XST_FAILURE; #endif } /*****************************************************************************/ /** * * Selects the slave with which the master communicates. * * The user is not allowed to select the slave while a transfer is in progress. * * @param InstancePtr is a pointer to the XQspiPs instance. * * @return * - XST_SUCCESS if the slave is selected or deselected * successfully. * - XST_DEVICE_BUSY if a transfer is in progress, slave cannot be * changed. * * @note * * This function only sets the slave which will be selected when a transfer * occurs. The slave is not selected when the QSPI is idle. * ******************************************************************************/ int XQspiPs_SetSlaveSelect(XQspiPs *InstancePtr) { u32 ConfigReg; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Do not allow the slave select to change while a transfer is in * progress. Not thread-safe. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Select the slave */ ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg &= ~XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); return XST_SUCCESS; } /*****************************************************************************/ /** * * Sets the status callback function, the status handler, which the driver * calls when it encounters conditions that should be reported to upper * layer software. The handler executes in an interrupt context, so it must * minimize the amount of processing performed. One of the following status * events is passed to the status handler. * *
*
* XST_SPI_TRANSFER_DONE		The requested data transfer is done
*
* XST_SPI_TRANSMIT_UNDERRUN	As a slave device, the master clocked data
*				but there were none available in the transmit
*				register/FIFO. This typically means the slave
*				application did not issue a transfer request
*				fast enough, or the processor/driver could not
*				fill the transmit register/FIFO fast enough.
*
* XST_SPI_RECEIVE_OVERRUN	The QSPI device lost data. Data was received
*				but the receive data register/FIFO was full.
*
* 
* @param InstancePtr is a pointer to the XQspiPs instance. * @param CallBackRef is the upper layer callback reference passed back * when the callback function is invoked. * @param FuncPtr is the pointer to the callback function. * * @return None. * * @note * * The handler is called within interrupt context, so it should do its work * quickly and queue potentially time-consuming work to a task-level thread. * ******************************************************************************/ void XQspiPs_SetStatusHandler(XQspiPs *InstancePtr, void *CallBackRef, XQspiPs_StatusHandler FuncPtr) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(FuncPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); InstancePtr->StatusHandler = FuncPtr; InstancePtr->StatusRef = CallBackRef; } /*****************************************************************************/ /** * * This is a stub for the status callback. The stub is here in case the upper * layers forget to set the handler. * * @param CallBackRef is a pointer to the upper layer callback reference * @param StatusEvent is the event that just occurred. * @param ByteCount is the number of bytes transferred up until the event * occurred. * * @return None. * * @note None. * ******************************************************************************/ static void StubStatusHandler(void *CallBackRef, u32 StatusEvent, unsigned ByteCount) { (void) CallBackRef; (void) StatusEvent; (void) ByteCount; Xil_AssertVoidAlways(); } /*****************************************************************************/ /** * * The interrupt handler for QSPI interrupts. This function must be connected * by the user to an interrupt controller. * * The interrupts that are handled are: * * * - Data Transmit Register (FIFO) Empty. This interrupt is generated when the * transmit register or FIFO is empty. The driver uses this interrupt during a * transmission to continually send/receive data until the transfer is done. * * - Data Transmit Register (FIFO) Underflow. This interrupt is generated when * the QSPI device, when configured as a slave, attempts to read an empty * DTR/FIFO. An empty DTR/FIFO usually means that software is not giving the * device data in a timely manner. No action is taken by the driver other than * to inform the upper layer software of the error. * * - Data Receive Register (FIFO) Overflow. This interrupt is generated when the * QSPI device attempts to write a received byte to an already full DRR/FIFO. * A full DRR/FIFO usually means software is not emptying the data in a timely * manner. No action is taken by the driver other than to inform the upper * layer software of the error. * * @param InstancePtr is a pointer to the XQspiPs instance. * * @return None. * * @note * * The slave select register is being set to deselect the slave when a transfer * is complete. * ******************************************************************************/ void XQspiPs_InterruptHandler(void *InstancePtr) { XQspiPs *QspiPtr = (XQspiPs *)InstancePtr; u32 IntrStatus; u32 ConfigReg; u32 Data; u32 TransCount; u32 Count = 0; unsigned BytesDone; /* Number of bytes done so far. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(QspiPtr->IsReady == XIL_COMPONENT_IS_READY); /* * Immediately clear the interrupts in case the ISR causes another * interrupt to be generated. If we clear at the end of the ISR, * we may miss newly generated interrupts. This occurs because we * transmit from within the ISR, which could potentially cause another * TX_EMPTY interrupt. */ IntrStatus = XQspiPs_ReadReg(QspiPtr->Config.BaseAddress, XQSPIPS_SR_OFFSET); XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_SR_OFFSET, (IntrStatus & XQSPIPS_IXR_WR_TO_CLR_MASK)); XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_IDR_OFFSET, XQSPIPS_IXR_TXOW_MASK | XQSPIPS_IXR_RXNEMPTY_MASK | XQSPIPS_IXR_RXOVR_MASK | XQSPIPS_IXR_TXUF_MASK); if ((IntrStatus & XQSPIPS_IXR_TXOW_MASK) || (IntrStatus & XQSPIPS_IXR_RXNEMPTY_MASK)) { /* * Rx FIFO has just reached threshold no. of entries. * Read threshold no. of entries from RX FIFO * Another possiblity of entering this loop is when * the last byte has been transmitted and TX FIFO is empty, * in which case, read all the data from RX FIFO. * Always get the received data, but only fill the * receive buffer if it is not null (it can be null when * the device does not care to receive data). */ TransCount = QspiPtr->RequestedBytes - QspiPtr->RemainingBytes; if (TransCount % 4) { TransCount = TransCount/4 + 1; } else { TransCount = TransCount/4; } while ((Count < TransCount) && (Count < XQSPIPS_RXFIFO_THRESHOLD_OPT)) { if (QspiPtr->RecvBufferPtr != NULL) { if (QspiPtr->RequestedBytes < 4) { Data = XQspiPs_ReadReg(QspiPtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); XQspiPs_GetReadData(QspiPtr, Data, QspiPtr->RequestedBytes); } else { (*(u32 *)QspiPtr->RecvBufferPtr) = XQspiPs_ReadReg(QspiPtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); QspiPtr->RecvBufferPtr += 4; QspiPtr->RequestedBytes -= 4; if (QspiPtr->RequestedBytes < 0) { QspiPtr->RequestedBytes = 0; } } } else { XQspiPs_ReadReg(QspiPtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); QspiPtr->RequestedBytes -= 4; if (QspiPtr->RequestedBytes < 0) { QspiPtr->RequestedBytes = 0; } } Count++; } Count = 0; /* * Interrupt asserted as TX_OW got asserted * See if there is more data to send. * Fill TX FIFO with RX threshold no. of entries or * remaining entries (in case that is less than threshold) */ while ((QspiPtr->RemainingBytes > 0) && (Count < XQSPIPS_RXFIFO_THRESHOLD_OPT)) { /* * Send more data. */ XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_TXD_00_OFFSET, *((u32 *)QspiPtr->SendBufferPtr)); QspiPtr->SendBufferPtr += 4; QspiPtr->RemainingBytes -= 4; if (QspiPtr->RemainingBytes < 0) { QspiPtr->RemainingBytes = 0; } Count++; } if ((QspiPtr->RemainingBytes == 0) && (QspiPtr->RequestedBytes == 0)) { /* * No more data to send. Disable the interrupt * and inform the upper layer software that the * transfer is done. The interrupt will be re-enabled * when another transfer is initiated. */ XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_IDR_OFFSET, XQSPIPS_IXR_RXNEMPTY_MASK | XQSPIPS_IXR_TXOW_MASK | XQSPIPS_IXR_RXOVR_MASK | XQSPIPS_IXR_TXUF_MASK); /* * If the Slave select is being manually controlled, * disable it because the transfer is complete. */ if (XQspiPs_IsManualChipSelect(InstancePtr)) { ConfigReg = XQspiPs_ReadReg( QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Clear the busy flag. */ QspiPtr->IsBusy = FALSE; /* * Disable the device. */ XQspiPs_Disable(QspiPtr); /* * Reset the RX FIFO threshold to one */ XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_RXWR_OFFSET, XQSPIPS_RXWR_RESET_VALUE); QspiPtr->StatusHandler(QspiPtr->StatusRef, XST_SPI_TRANSFER_DONE, QspiPtr->RequestedBytes); } else { /* * Enable the TXOW interrupt. */ XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_IER_OFFSET, XQSPIPS_IXR_RXNEMPTY_MASK | XQSPIPS_IXR_TXOW_MASK | XQSPIPS_IXR_RXOVR_MASK | XQSPIPS_IXR_TXUF_MASK); /* * If, in Manual Start mode, start the transfer. */ if (XQspiPs_IsManualStart(QspiPtr)) { ConfigReg = XQspiPs_ReadReg( QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_MANSTRT_MASK; XQspiPs_WriteReg( QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } } } /* * Check for overflow and underflow errors. */ if (IntrStatus & XQSPIPS_IXR_RXOVR_MASK) { BytesDone = QspiPtr->RequestedBytes - QspiPtr->RemainingBytes; QspiPtr->IsBusy = FALSE; /* * If the Slave select lines is being manually controlled, * disable it because the transfer is complete. */ if (XQspiPs_IsManualChipSelect(InstancePtr)) { ConfigReg = XQspiPs_ReadReg( QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Disable the device. */ XQspiPs_Disable(QspiPtr); /* * Reset the RX FIFO threshold to one */ XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_RXWR_OFFSET, XQSPIPS_RXWR_RESET_VALUE); QspiPtr->StatusHandler(QspiPtr->StatusRef, XST_SPI_RECEIVE_OVERRUN, BytesDone); } if (IntrStatus & XQSPIPS_IXR_TXUF_MASK) { BytesDone = QspiPtr->RequestedBytes - QspiPtr->RemainingBytes; QspiPtr->IsBusy = FALSE; /* * If the Slave select lines is being manually controlled, * disable it because the transfer is complete. */ if (XQspiPs_IsManualChipSelect(InstancePtr)) { ConfigReg = XQspiPs_ReadReg( QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); ConfigReg |= XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); } /* * Disable the device. */ XQspiPs_Disable(QspiPtr); /* * Reset the RX FIFO threshold to one */ XQspiPs_WriteReg(QspiPtr->Config.BaseAddress, XQSPIPS_RXWR_OFFSET, XQSPIPS_RXWR_RESET_VALUE); QspiPtr->StatusHandler(QspiPtr->StatusRef, XST_SPI_TRANSMIT_UNDERRUN, BytesDone); } } /*****************************************************************************/ /** * * Copies data from Data to the Receive buffer. * * @param InstancePtr is a pointer to the XQspiPs instance. * @param Data is the data which needs to be copied to the Rx buffer. * @param Size is the number of bytes to be copied to the Receive buffer. * * @return None. * * @note None. * ******************************************************************************/ static void XQspiPs_GetReadData(XQspiPs *InstancePtr, u32 Data, u8 Size) { u8 DataByte3; if (InstancePtr->RecvBufferPtr) { switch (Size) { case 1: if (InstancePtr->ShiftReadData == 1) { *((u8 *)InstancePtr->RecvBufferPtr) = ((Data & 0xFF000000) >> 24); } else { *((u8 *)InstancePtr->RecvBufferPtr) = (Data & 0xFF); } InstancePtr->RecvBufferPtr += 1; break; case 2: if (InstancePtr->ShiftReadData == 1) { *((u16 *)InstancePtr->RecvBufferPtr) = ((Data & 0xFFFF0000) >> 16); } else { *((u16 *)InstancePtr->RecvBufferPtr) = (Data & 0xFFFF); } InstancePtr->RecvBufferPtr += 2; break; case 3: if (InstancePtr->ShiftReadData == 1) { *((u16 *)InstancePtr->RecvBufferPtr) = ((Data & 0x00FFFF00) >> 8); InstancePtr->RecvBufferPtr += 2; DataByte3 = ((Data & 0xFF000000) >> 24); *((u8 *)InstancePtr->RecvBufferPtr) = DataByte3; } else { *((u16 *)InstancePtr->RecvBufferPtr) = (Data & 0xFFFF); InstancePtr->RecvBufferPtr += 2; DataByte3 = ((Data & 0x00FF0000) >> 16); *((u8 *)InstancePtr->RecvBufferPtr) = DataByte3; } InstancePtr->RecvBufferPtr += 1; break; default: /* This will never execute */ break; } } InstancePtr->ShiftReadData = 0; InstancePtr->RequestedBytes -= Size; if (InstancePtr->RequestedBytes < 0) { InstancePtr->RequestedBytes = 0; } }