コード例 #1
0
ファイル: xqspips_hw.c プロジェクト: LukasWoodtli/QFreeRTOS
/**
*
* Initializes QSPI to Linear mode with default QSPI boot settings.
*
* @param	None
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
void XQspiPs_LinearInit(u32 BaseAddress)
{
	u32 BaudRateDiv;
	u32 LinearCfg;

	/*
	 * Baud rate divisor for dividing by 4. Value of CR bits [5:3]
	 * should be set to 0x001; hence shift the value and use the mask.
	 */
	BaudRateDiv = ( (XQSPIPS_CR_PRESC_DIV_BY_4) <<
			XQSPIPS_CR_PRESC_SHIFT) & XQSPIPS_CR_PRESC_MASK;
	/*
	 * Write configuration register with default values, slave selected &
	 * pre-scaler value for divide by 4
	 */
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_CR_OFFSET,
				((XQSPIPS_CR_RESET_STATE |
				XQSPIPS_CR_HOLD_B_MASK | BaudRateDiv) &
				(~XQSPIPS_CR_SSCTRL_MASK) ));

	/*
	 * Write linear configuration register with default value -
	 * enable linear mode and use fast read.
	 */

	if(XPAR_PS7_QSPI_0_QSPI_MODE == XQSPIPS_CONNECTION_MODE_SINGLE){

		LinearCfg = XQSPIPS_LQSPI_CR_RST_STATE;

	}else if(XPAR_PS7_QSPI_0_QSPI_MODE ==
			XQSPIPS_CONNECTION_MODE_STACKED){

		LinearCfg = XQSPIPS_LQSPI_CR_RST_STATE |
				XQSPIPS_LQSPI_CR_TWO_MEM_MASK;

	}else if(XPAR_PS7_QSPI_0_QSPI_MODE ==
	 		XQSPIPS_CONNECTION_MODE_PARALLEL){

		LinearCfg = XQSPIPS_LQSPI_CR_RST_STATE |
				XQSPIPS_LQSPI_CR_TWO_MEM_MASK |
		 		XQSPIPS_LQSPI_CR_SEP_BUS_MASK;

	}

	XQspiPs_WriteReg(BaseAddress, XQSPIPS_LQSPI_CR_OFFSET,
				LinearCfg);

	/*
	 * Enable device
	 */
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_ER_OFFSET,
				XQSPIPS_ER_ENABLE_MASK);

}
コード例 #2
0
/**
*
* This function sets the delay register for the QSPI device driver.
* The delay register controls the Delay Between Transfers, Delay After
* Transfers, and the Delay Initially. The default value is 0x0. The range of
* each delay value is 0-255.
*
* @param	InstancePtr is a pointer to the XQspiPs instance.
* @param	DelayNss is the delay to de-assert slave select between
*		two word transfers.
* @param	DelayBtwn is the delay between one Slave Select being
*		de-activated and the activation of another slave. The delay is
*		the number of master clock periods given by DelayBtwn + 2.
* @param	DelayAfter define the delay between the last bit of the current
*		byte transfer and the first bit of the next byte transfer.
*		The delay in number of master clock periods is given as:
*		CHPA=0:DelayInit+DelayAfter+3
*		CHPA=1:DelayAfter+1
* @param	DelayInit is the delay between asserting the slave select signal
*		and the first bit transfer. The delay int number of master clock
*		periods is DelayInit+1.
*
* @return
*		- XST_SUCCESS if delays are successfully set.
*		- XST_DEVICE_BUSY if the device is currently transferring data.
*		The transfer must complete or be aborted before setting options.
*
* @note		None.
*
******************************************************************************/
int XQspiPs_SetDelays(XQspiPs *InstancePtr, u8 DelayNss, u8 DelayBtwn,
			 u8 DelayAfter, u8 DelayInit)
{
	u32 DelayRegister;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Do not allow the delays to change while a transfer is in
	 * progress. Not thread-safe.
	 */
	if (InstancePtr->IsBusy) {
		return XST_DEVICE_BUSY;
	}

	/* Shift, Mask and OR the values to build the register settings */
	DelayRegister = (u32) DelayNss << XQSPIPS_DR_NSS_SHIFT;
	DelayRegister |= (u32) DelayBtwn << XQSPIPS_DR_BTWN_SHIFT;
	DelayRegister |= (u32) DelayAfter << XQSPIPS_DR_AFTER_SHIFT;
	DelayRegister |= (u32) DelayInit;

	XQspiPs_WriteReg(InstancePtr->Config.BaseAddress,
			  XQSPIPS_DR_OFFSET, DelayRegister);

	return XST_SUCCESS;
}
コード例 #3
0
ファイル: xqspips.c プロジェクト: DavidAlmeida23/DBT_Gang
/**
*
* 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;
}
コード例 #4
0
/**
*
* This function sets the clock prescaler for an QSPI device. The device
* must be idle rather than busy transferring data before setting these device
* options.
*
* @param	InstancePtr is a pointer to the XQspiPs instance.
* @param	Prescaler is the value that determine how much the clock should
*		be divided by. Use the XQSPIPS_CLK_PRESCALE_* constants defined
*		in xqspips.h for this setting.
*
* @return
*		- XST_SUCCESS if options are successfully set.
*		- XST_DEVICE_BUSY if the device is currently transferring data.
*		The transfer must complete or be aborted before setting options.
*
* @note
* This function is not thread-safe.
*
******************************************************************************/
int XQspiPs_SetClkPrescaler(XQspiPs *InstancePtr, u8 Prescaler)
{
	u32 ConfigReg;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid(Prescaler <= XQSPIPS_CR_PRESC_MAXIMUM);

	/*
	 * Do not allow the slave select to change while a transfer is in
	 * progress. Not thread-safe.
	 */
	if (InstancePtr->IsBusy) {
		return XST_DEVICE_BUSY;
	}

	/*
	 * Read the configuration register, mask out the interesting bits, and set
	 * them with the shifted value passed into the function. Write the
	 * results back to the configuration register.
	 */
	ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress,
				      XQSPIPS_CR_OFFSET);

	ConfigReg &= ~XQSPIPS_CR_PRESC_MASK;
	ConfigReg |= (u32) (Prescaler & XQSPIPS_CR_PRESC_MAXIMUM) <<
			    XQSPIPS_CR_PRESC_SHIFT;

	XQspiPs_WriteReg(InstancePtr->Config.BaseAddress,
			  XQSPIPS_CR_OFFSET,
			  ConfigReg);

	return XST_SUCCESS;
}
コード例 #5
0
/**
*
* 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;
}
コード例 #6
0
ファイル: xqspips.c プロジェクト: DavidAlmeida23/DBT_Gang
/**
*
* 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;
	u32 IsLock;

	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);

	/*
	 * QSPI Software Reset
	 */
	IsLock = XQspiPs_ReadReg(XPAR_XSLCR_0_BASEADDR, SLCR_LOCKSTA);
	if (IsLock) {
		XQspiPs_WriteReg(XPAR_XSLCR_0_BASEADDR, SLCR_UNLOCK,
				SLCR_UNLOCK_MASK);
	}
	XQspiPs_WriteReg(XPAR_XSLCR_0_BASEADDR, LQSPI_RST_CTRL,
			LQSPI_RST_CTRL_MASK);
	XQspiPs_WriteReg(XPAR_XSLCR_0_BASEADDR, LQSPI_RST_CTRL, 0x0);
	if (IsLock) {
		XQspiPs_WriteReg(XPAR_XSLCR_0_BASEADDR, SLCR_LOCK,
				SLCR_LOCK_MASK);
	}

	/*
	 * 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);

	InstancePtr->RemainingBytes = 0;
	InstancePtr->RequestedBytes = 0;
	InstancePtr->IsBusy = FALSE;
}
コード例 #7
0
ファイル: xqspips.c プロジェクト: DavidAlmeida23/DBT_Gang
/**
*
* 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);
	ConfigReg |= XQSPIPS_CR_RESET_MASK_SET;
	ConfigReg &= ~XQSPIPS_CR_RESET_MASK_CLR;
	XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET,
			  ConfigReg);
}
コード例 #8
0
ファイル: xqspips_hw.c プロジェクト: LukasWoodtli/QFreeRTOS
/**
*
* Resets QSPI by disabling the device and bringing it to reset state through
* register writes.
*
* @param	None
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
void XQspiPs_ResetHw(u32 BaseAddress)
{
	u32 ConfigReg;

	/*
	 * Disable interrupts
	 */
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_IDR_OFFSET,
				XQSPIPS_IXR_DISABLE_ALL);

	/*
	 * Disable device
	 */
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_ER_OFFSET,
				0);

	/*
	 * De-assert slave select lines.
	 */
	ConfigReg = XQspiPs_ReadReg(BaseAddress, XQSPIPS_CR_OFFSET);
	ConfigReg |= (XQSPIPS_CR_SSCTRL_MASK | XQSPIPS_CR_SSFORCE_MASK);
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg);

	/*
	 * Write default value to RX and TX threshold registers
	 * RX threshold should be set to 1 here because the corresponding
	 * status bit is used next to clear the RXFIFO
	 */
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_TXWR_OFFSET,
			(XQSPIPS_TXWR_RESET_VALUE & XQSPIPS_TXWR_MASK));
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_RXWR_OFFSET,
			(XQSPIPS_RXWR_RESET_VALUE & XQSPIPS_RXWR_MASK));

	/*
	 * Clear RXFIFO
	 */
	while ((XQspiPs_ReadReg(BaseAddress,XQSPIPS_SR_OFFSET) &
		XQSPIPS_IXR_RXNEMPTY_MASK) != 0) {
		XQspiPs_ReadReg(BaseAddress, XQSPIPS_RXD_OFFSET);
	}

	/*
	 * Clear status register by reading register and
	 * writing 1 to clear the write to clear bits
	 */
	XQspiPs_ReadReg(BaseAddress, XQSPIPS_SR_OFFSET);
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_SR_OFFSET,
				XQSPIPS_IXR_WR_TO_CLR_MASK);

	/*
	 * Write default value to configuration register
	 */
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_CR_OFFSET,
				XQSPIPS_CR_RESET_STATE);


	/*
	 * De-select linear mode
	 */
	XQspiPs_WriteReg(BaseAddress, XQSPIPS_LQSPI_CR_OFFSET,
				0x0);

}
コード例 #9
0
/**
*
* This function sets the options for the QSPI device driver. The options control
* how the device behaves relative to the QSPI bus. The device must be idle
* rather than busy transferring data before setting these device options.
*
* @param	InstancePtr is a pointer to the XQspiPs instance.
* @param	Options contains the specified options to be set. This is a bit
*		mask where a 1 means to turn the option on, and a 0 means to
*		turn the option off. One or more bit values may be contained in
*		the mask. See the bit definitions named XQSPIPS_*_OPTIONS in
*		the file xqspips.h.
*
* @return
*		- XST_SUCCESS if options are successfully set.
*		- XST_DEVICE_BUSY if the device is currently transferring data.
*		The transfer must complete or be aborted before setting options.
*
* @note
* This function is not thread-safe.
*
******************************************************************************/
int XQspiPs_SetOptions(XQspiPs *InstancePtr, u32 Options)
{
	u32 ConfigReg;
	unsigned int Index;
	u32 QspiOptions;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Do not allow to modify the Control Register while a transfer is in
	 * progress. Not thread-safe.
	 */
	if (InstancePtr->IsBusy) {
		return XST_DEVICE_BUSY;
	}

	QspiOptions = Options & XQSPIPS_LQSPI_MODE_OPTION;
	Options &= ~XQSPIPS_LQSPI_MODE_OPTION;

	ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress,
				      XQSPIPS_CR_OFFSET);

	/*
	 * Loop through the options table, turning the option on or off
	 * depending on whether the bit is set in the incoming options flag.
	 */
	for (Index = 0; Index < XQSPIPS_NUM_OPTIONS; Index++) {
		if (Options & OptionsTable[Index].Option) {
			/* Turn it on */
			ConfigReg |= OptionsTable[Index].Mask;
		} else {
			/* Turn it off */
			ConfigReg &= ~(OptionsTable[Index].Mask);
		}
	}

	/*
	 * Now write the control register. Leave it to the upper layers
	 * to restart the device.
	 */
	XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET,
			 ConfigReg);

	/*
	 * Check for the LQSPI configuration options.
	 */
	ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress,
				      XQSPIPS_LQSPI_CR_OFFSET);


	if (QspiOptions & XQSPIPS_LQSPI_MODE_OPTION) {
		XQspiPs_WriteReg(InstancePtr->Config.BaseAddress,
				  XQSPIPS_LQSPI_CR_OFFSET,
				  XQSPIPS_LQSPI_CR_RST_STATE);
		XQspiPs_SetSlaveSelect(InstancePtr);
	} else {
		ConfigReg &= ~XQSPIPS_LQSPI_CR_LINEAR_MASK;
		XQspiPs_WriteReg(InstancePtr->Config.BaseAddress,
				  XQSPIPS_LQSPI_CR_OFFSET, ConfigReg);
	}

	return XST_SUCCESS;
}
コード例 #10
0
ファイル: xqspips.c プロジェクト: DavidAlmeida23/DBT_Gang
/**
* 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:
* <pre>
*   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.
*
* </pre>
*
* @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;
}
コード例 #11
0
ファイル: xqspips.c プロジェクト: DavidAlmeida23/DBT_Gang
/**
*
* 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:
* <pre>
*   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.
* </pre>
* 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;
}
コード例 #12
0
ファイル: xqspips.c プロジェクト: DavidAlmeida23/DBT_Gang
/**
*
* 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);
	}
}