summaryrefslogblamecommitdiffstats
path: root/bsps/shared/dev/spi/xqspipsu.c
blob: 93d3fa4c98ea6f905c71f0632c2b61cf0f0f70e8 (plain) (tree)
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086





















































































                                                                                  


                              






























































































































































































                                                                                





                                                         


















































                                                                               



                                                                              

                                                                   
      








                                                                                      


                                                                                              
                                                                                   
      







































































































                                                                                    




                                                                                                         
         



                                                                          










































































































































                                                                                                                 


                
                                                             







                                                                                                         














































































































































































































































































































































































































































































                                                                                                                               
/******************************************************************************
* Copyright (C) 2014 - 2022 Xilinx, Inc.  All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/


/*****************************************************************************/
/**
 *
 * @file xqspipsu.c
 * @addtogroup Overview
 * @{
 *
 * This file implements the functions required to use the QSPIPSU hardware to
 * perform a transfer. These are accessible to the user via xqspipsu.h.
 *
 * <pre>
 * MODIFICATION HISTORY:
 *
 * Ver   Who Date     Changes
 * ----- --- -------- -----------------------------------------------
 * 1.0   hk  08/21/14 First release
 *       sk  03/13/15 Added IO mode support.
 *       hk  03/18/15 Switch to I/O mode before clearing RX FIFO.
 *                    Clear and disable DMA interrupts/status in abort.
 *                    Use DMA DONE bit instead of BUSY as recommended.
 *       sk  04/24/15 Modified the code according to MISRAC-2012.
 *       sk  06/17/15 Removed NULL checks for Rx/Tx buffers. As
 *                    writing/reading from 0x0 location is permitted.
 * 1.1   sk  04/12/16 Added debug message prints.
 * 1.2 nsk 07/01/16 Changed XQspiPsu_Select to support GQSPI and LQSPI
 *                  selection.
 *       rk  07/15/16 Added support for TapDelays at different frequencies.
 *     nsk 08/05/16 Added example support PollData and PollTimeout
 * 1.3 nsk 09/16/16 Update PollData and PollTimeout support for dual
 *                  parallel configurations, modified XQspiPsu_PollData()
 *                  and XQspiPsu_Create_PollConfigData()
 * 1,5 nsk 08/14/17 Added CCI support
 * 1.7 tjs 01/16/18 Removed the check for DMA MSB to be written. (CR#992560)
 * 1.7 tjs 01/17/18 Added a support to toggle WP pin of the flash.
 * 1.7 tjs 03/14/18 Added support in EL1 NS mode (CR#974882)
 * 1.8 tjs 06/26/18 Added an example for accessing 64bit dma within
 *                  32 bit application. CR#1004701
 * 1.8 tjs 06/26/18 Removed checkpatch warnings.
 * 1.8 tjs 07/09/18 Fixed cppcheck and doxygen warnings. (CR#1006336)
 * 1.8 tjs 07/18/18 Setup64BRxDma() should be called only if the RxAddress is
 *                  greater than 32 bit address space. (CR#1006862)
 * 1.8 tjs 09/06/18 Fixed the code in XQspiPsu_GenFifoEntryData() for data
 *                  transfer length up to 255 for reducing the extra loop.
 * 1.8  mus 11/05/18 Support 64 bit DMA addresses for Microblaze-X platform.
 * 1.9 tjs 11/22/17 Added the check for A72 and R5 processors (CR-987075)
 * 1.9 tjs 04/17/18 Updated register addresses as per the latest revision
 *		    of versal (CR#999610)
 * 1.9  aru 01/17/19 Fixes violations according to MISRAC-2012
 *                  in safety mode and modified the code such as
 *                  Added UNITPTR inplace of INTPTR,Declared the pointer param
 *		    as Pointer to const .
 * 1.9  nsk 02/01/19 Clear DMA_DST_ADDR_MSB register on 32bit machine, if the
 *		     address is of only 32bit (CR#1020031)
 * 1.9  nsk 02/01/19 Added QSPI idling support.
 * 1.9  rama 03/13/19 Fixed MISRA violations related to UR data anamoly,
 *					  expression is not a boolean
 * 1.9  nsk 03/27/19 Update 64bit dma support
 * 1.10 sk  08/20/19 Fixed issues in poll timeout feature.
 * 1.11 akm 02/19/20 Added XQspiPsu_StartDmaTransfer() and XQspiPsu_CheckDmaDone()
 * 		     APIs for non-blocking transfer.
 * 1.11 sd  01/02/20 Added clocking support
 * 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and
 *		     interrupts in XQspiPsu_CfgInitialize() API.
 * 1.11 akm 03/26/20 Fixed issue by updating XQspiPsu_CfgInitialize to return
 *		     XST_DEVICE_IS_STARTED instead of asserting, when the
 *		     instance is already configured.
 * 1.13 akm 01/04/21 Fix MISRA-C violations.
 * 1.14 akm 06/24/21 Allow enough time for the controller to reset the FIFOs.
 * 1.14 akm 08/12/21 Perform Dcache invalidate at the end of the DMA transfer.
 * 1.15 akm 10/21/21 Fix MISRA-C violations.
 *
 * </pre>
 *
 ******************************************************************************/

/***************************** Include Files *********************************/

#include "xqspipsu.h"
#include "xqspipsu_control.h"
#include "sleep.h"
#ifdef __rtems__
#include <rtems/rtems/cache.h>
#endif

/************************** Constant Definitions *****************************/
#define MAX_DELAY_CNT	10000000U	/**< Max delay count */

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

/************************** Variable Definitions *****************************/

/*****************************************************************************/
/**
 *
 * Initializes a specific XQspiPsu instance as such the driver is ready to use.
 *
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 * @param	ConfigPtr is a reference to a structure containing information
 *		about a specific QSPIPSU 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.
 *
 ******************************************************************************/
s32 XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr,
			   const XQspiPsu_Config *ConfigPtr,
			   UINTPTR EffectiveAddr)
{
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(ConfigPtr != NULL);
	s32 Status;

	/*
	 * 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 == (u32)TRUE) ||
	    (InstancePtr->IsReady == XIL_COMPONENT_IS_READY)) {
		Status = (s32)XST_DEVICE_IS_STARTED;
	} else {
		/* Set some default values. */
		InstancePtr->IsBusy = (u32)FALSE;
		InstancePtr->Config.BaseAddress =
			EffectiveAddr + XQSPIPSU_OFFSET;
		InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode;
		InstancePtr->StatusHandler = StubStatusHandler;
		InstancePtr->Config.BusWidth = ConfigPtr->BusWidth;
		InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz;
#if defined  (XCLOCKING)
		InstancePtr->Config.RefClk = ConfigPtr->RefClk;
#endif
		InstancePtr->Config.IsCacheCoherent =
			ConfigPtr->IsCacheCoherent;
		/* Other instance variable initializations */
		InstancePtr->SendBufferPtr = NULL;
		InstancePtr->RecvBufferPtr = NULL;
		InstancePtr->GenFifoBufferPtr = NULL;
		InstancePtr->TxBytes = 0;
		InstancePtr->RxBytes = 0;
		InstancePtr->GenFifoEntries = 0;
		InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
		InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER;
		InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER;
		InstancePtr->IsUnaligned = 0;
		InstancePtr->IsManualstart = (u8)TRUE;

		/* Select QSPIPSU */
		XQspiPsu_Select(InstancePtr, XQSPIPSU_SEL_GQSPI_MASK);
		/*
		 * Reset the QSPIPSU 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.
		 */
		XQspiPsu_Reset(InstancePtr);
		/* Enable */
		XQspiPsu_Enable(InstancePtr);

		InstancePtr->IsReady = XIL_COMPONENT_IS_READY;

		Status = (s32)XST_SUCCESS;
	}

	return Status;
}

/*****************************************************************************/
/**
 *
 * Stops the transfer of data to internal DST FIFO from stream interface and
 * also stops the issuing of new write commands to memory.
 *
 * By calling this API, any ongoing Dma transfers will be paused and DMA will
 * not issue AXI write commands to memory
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 *
 * @return	None.
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_Idle(const XQspiPsu *InstancePtr)
{
	u32 RegEn;
	u32 DmaStatus;

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

	/* Check for QSPI enable */
	RegEn = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_EN_OFFSET);
	if ((RegEn & XQSPIPSU_EN_MASK) != 0U) {
		DmaStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET);
		DmaStatus |= XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_MASK;
		DmaStatus |= XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_MASK;
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET, DmaStatus);
	}
#if defined  (XCLOCKING)
	Xil_ClockDisable(InstancePtr->Config.RefClk);
#endif
}

/*****************************************************************************/
/**
 *
 * Resets the QSPIPSU 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 QSPIPSU device after the reset.
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 *
 * @return	None.
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_Reset(XQspiPsu *InstancePtr)
{
	Xil_AssertVoid(InstancePtr != NULL);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_Reset\r\n");
#endif

	/* Abort any transfer that is in progress */
	XQspiPsu_Abort(InstancePtr);

	/* Default value to config register */
	XQspiPsu_SetDefaultConfig(InstancePtr);

}

/*****************************************************************************/
/**
 *
 * Aborts a transfer in progress.
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 *
 * @return	None.
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_Abort(XQspiPsu *InstancePtr)
{
	u32 IntrStatus, ConfigReg, FifoStatus;
	u32 DelayCount = 0U;

#ifdef __rtems__
	u32 FifoStatusMask = XQSPIPSU_ISR_RXEMPTY_MASK;
	FifoStatusMask |= XQSPIPSU_ISR_TXEMPTY_MASK;
	FifoStatusMask |= XQSPIPSU_ISR_GENFIFOEMPTY_MASK;
#endif

	Xil_AssertVoid(InstancePtr != NULL);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_Abort\r\n");
#endif
	IntrStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
					XQSPIPSU_ISR_OFFSET);

	/* Clear and disable interrupts */
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_ISR_OFFSET, IntrStatus | XQSPIPSU_ISR_WR_TO_CLR_MASK);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET,
		XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET));
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_STS_OFFSET,
			XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_QSPIDMA_DST_STS_OFFSET) |
				XQSPIPSU_QSPIDMA_DST_STS_WTC);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_IDR_OFFSET, XQSPIPSU_IDR_ALL_MASK);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET,
			XQSPIPSU_QSPIDMA_DST_INTR_ALL_MASK);

	/*
	 * Clear GEN FIFO, TX FIFO & RX FIFO. Switch to IO mode to Clear
	 * RX FIFO. This is because of DMA behaviour where it waits on
	 * RX empty and goes busy assuming there is data to be transferred
	 * even if there is no request.
	 */
	ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_CFG_OFFSET);
	ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_CFG_OFFSET, ConfigReg);

	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			  XQSPIPSU_FIFO_CTRL_OFFSET,
			  XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK |
			  XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK |
			  XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK);
	/*
	 * QSPI Controller takes few clock cycles to update the RX_FIFO_Empty,
	 * TX_FIFO_Empty and GEN_FIFO_Empty status bit. Checking the GQSPI FIFO
	 * Control register bits gives enough time for the QSPI controller to
	 * update the status bit. The opeartion timesout, if the status bit are
	 * not updated after 10secs.
	 */

	FifoStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
#ifdef __rtems__
					XQSPIPSU_ISR_OFFSET) & FifoStatusMask;
	while(FifoStatus != FifoStatusMask) {
#else
					XQSPIPSU_FIFO_CTRL_OFFSET);
	while(FifoStatus != 0U) {
#endif
		if (DelayCount == MAX_DELAY_CNT) {
#ifdef DEBUG
			xil_printf("Timeout error, FIFO reset failed.\r\n");
#endif
		} else {
			/* Wait for 1 usec */
			usleep(1);
			DelayCount++;
			FifoStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
#ifdef __rtems__
							XQSPIPSU_ISR_OFFSET) & FifoStatusMask;
#else
							XQSPIPSU_FIFO_CTRL_OFFSET);
#endif
		}
	}

	if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
		ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_CFG_OFFSET, ConfigReg);
	}


	InstancePtr->TxBytes = 0;
	InstancePtr->RxBytes = 0;
	InstancePtr->GenFifoEntries = 0;
	InstancePtr->IsBusy = (u32)FALSE;
}

/*****************************************************************************/
/**
 * This is the handler for polling functionality of controller. It reads data
 * from RXFIFO, since when data from the flash device (status data) matched
 * with configured value in poll_cfg, then controller writes the matched data
 * into RXFIFO.
 *
 *
 * @param       InstancePtr is a pointer to the XQspiPsu instance.
 * @param       StatusReg is the Interrupt status Register value.
 *
 * @return	None.
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_PollDataHandler(XQspiPsu *InstancePtr, u32 StatusReg)
{

	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_PollDataHandler\r\n");
#endif

	if ((StatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != (u32)FALSE) {
		/*
		 * Read data from RXFIFO, since when data from the
		 * flash device (status data) matched with configured
		 * value in poll_cfg, then controller writes the
		 * matched data into RXFIFO.
		 */
		(void)XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_RXD_OFFSET);

		InstancePtr->StatusHandler(InstancePtr->StatusRef,
				XST_SPI_POLL_DONE, 0);
	}
	if ((StatusReg & XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK) != (u32)FALSE) {
			InstancePtr->StatusHandler(InstancePtr->StatusRef,
							XST_FLASH_TIMEOUT_ERROR, 0);
	}
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IDR_OFFSET,
			(u32)XQSPIPSU_IER_RXNEMPTY_MASK |
			(u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK);
	InstancePtr->IsBusy = (u32)FALSE;
	if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
			XQspiPsu_SetReadMode(InstancePtr, XQSPIPSU_READMODE_DMA);
	}
	/* De-select slave */
	XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
	XQspiPsu_ManualStartEnable(InstancePtr);
}

/*****************************************************************************/
/**
 *
 * This function performs a transfer on the bus in polled mode. The messages
 * passed are all transferred on the bus between one CS assert and de-assert.
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 * @param	Msg is a pointer to the structure containing transfer data.
 * @param	NumMsg is the number of messages to be transferred.
 *
 * @return
 *		- XST_SUCCESS if successful.
 *		- XST_FAILURE if transfer fails.
 *		- XST_DEVICE_BUSY if a transfer is already in progress.
 *
 * @note	None.
 *
 ******************************************************************************/
s32 XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
				u32 NumMsg)
{
	s32 Index;
	u32 QspiPsuStatusReg;
	u32 IOPending = (u32)FALSE;
	u32 DmaIntrSts;
	s32 Status;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(Msg != NULL);
	Xil_AssertNonvoid(NumMsg > 0U);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	for (Index = 0; Index < (s32)NumMsg; Index++) {
		Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
#ifdef __rtems__
		if (Msg[Index].TxBfrPtr != NULL) {
			rtems_cache_flush_multiple_data_lines(Msg[Index].TxBfrPtr, Msg[Index].ByteCount);
		}
#endif
	}
#ifdef __rtems__
	rtems_cache_flush_multiple_data_lines(Msg, NumMsg * sizeof(*Msg));
#endif

	/*
	 * Check whether there is another transfer in progress.
	 * Not thread-safe
	 */
	if (InstancePtr->IsBusy == (u32)TRUE) {
		Status = (s32)XST_DEVICE_BUSY;
		goto END;
	}
	/* Check for ByteCount upper limit - 2^28 for DMA */
	for (Index = 0; Index < (s32)NumMsg; Index++) {
		if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) &&
				((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) {
			Status = (s32)XST_FAILURE;
			goto END;
		}
	}
	/*
	 * Set the busy flag, which will be cleared when the transfer is
	 * entirely done.
	 */
	InstancePtr->IsBusy = (u32)TRUE;

#if defined  (XCLOCKING)
	Xil_ClockEnable(InstancePtr->Config.RefClk);
#endif
	/* Select slave */
	XQspiPsu_GenFifoEntryCSAssert(InstancePtr);

	/* list */
	Index = 0;
	while (Index < (s32)NumMsg) {
		XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[Index]);
		XQspiPsu_ManualStartEnable(InstancePtr);
		/* Use thresholds here */
		/* If there is more data to be transmitted */
		do {
			QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
						XQSPIPSU_ISR_OFFSET);
			/* Transmit more data if left */
			if (((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != (u32)FALSE) &&
				((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) &&
				(InstancePtr->TxBytes > 0)) {
				XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index],
						(u32)XQSPIPSU_TXD_DEPTH);
			}

			if ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE) {
				if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
					/* Check if DMA RX is complete and update RxBytes */
					DmaIntrSts = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
								XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET);
					if ((DmaIntrSts &
						XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) {
						XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
								XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts);
						/* DMA transfer done, Invalidate Data Cache */
						if (!((Msg[Index].RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) ||
							(Msg[Index].Xfer64bit != (u8)0U)) &&
							(InstancePtr->Config.IsCacheCoherent == 0U)) {
							Xil_DCacheInvalidateRange((INTPTR)Msg[Index].RxBfrPtr,
										(INTPTR)Msg[Index].ByteCount);
						}
						IOPending = XQspiPsu_SetIOMode(InstancePtr, &Msg[Index]);
						InstancePtr->RxBytes = 0;
						if (IOPending == (u32)TRUE) {
							break;
						}
					}
				} else {
					XQspiPsu_IORead(InstancePtr, &Msg[Index], QspiPsuStatusReg);
				}
			}
		} while (((QspiPsuStatusReg &
			XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE) ||
			(InstancePtr->TxBytes != 0) ||
			((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == (u32)FALSE) ||
			(InstancePtr->RxBytes != 0));

		if ((InstancePtr->IsUnaligned != 0) && (IOPending == (u32)FALSE)) {
			InstancePtr->IsUnaligned = 0;
			XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
					(XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) |
							XQSPIPSU_CFG_MODE_EN_DMA_MASK));
			InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
		}
		if (IOPending == (u32)TRUE) {
			IOPending = (u32)FALSE;
		} else {
			Index++;
		}
	}
	/* De-select slave */
	XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
	XQspiPsu_ManualStartEnable(InstancePtr);
	do {
		QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET);
	} while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE);

	/* Clear the busy flag. */
	InstancePtr->IsBusy = (u32)FALSE;

	Status = (s32)XST_SUCCESS;

#if defined  (XCLOCKING)
	Xil_ClockDisable(InstancePtr->Config.RefClk);
#endif
	END:
	return Status;
}

/*****************************************************************************/
/**
 *
 * This function initiates a transfer on the bus and enables interrupts.
 * The transfer is completed by the interrupt handler. The messages passed are
 * all transferred on the bus between one CS assert and de-assert.
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 * @param	Msg is a pointer to the structure containing transfer data.
 * @param	NumMsg is the number of messages to be transferred.
 *
 * @return
 *		- XST_SUCCESS if successful.
 *		- XST_FAILURE if transfer fails.
 *		- XST_DEVICE_BUSY if a transfer is already in progress.
 *
 * @note	None.
 *
 ******************************************************************************/
s32 XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
				u32 NumMsg)
{
	s32 Index;
	s32 Status;

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

	for (Index = 0; Index < (s32)NumMsg; Index++)
#ifdef __rtems__
	{
#endif
		Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
#ifdef __rtems__
		if (Msg[Index].TxBfrPtr != NULL) {
			rtems_cache_flush_multiple_data_lines(Msg[Index].TxBfrPtr, Msg[Index].ByteCount);
		}
	}
	rtems_cache_flush_multiple_data_lines(Msg, NumMsg * sizeof(*Msg));
#endif

	/*
	 * Check whether there is another transfer in progress.
	 * Not thread-safe
	 */
	if (InstancePtr->IsBusy == (u32)TRUE) {
			Status = (s32)XST_DEVICE_BUSY;
			goto END;
	}
#if defined  (XCLOCKING)
	Xil_ClockEnable(InstancePtr->Config.RefClk);
#endif

	if ((Msg[0].Flags & XQSPIPSU_MSG_FLAG_POLL) != (u32)FALSE) {
		InstancePtr->IsBusy = (u32)TRUE;
		XQspiPsu_PollDataConfig(InstancePtr, Msg);
	} else {
		/* Check for ByteCount upper limit - 2^28 for DMA */
		for (Index = 0; Index < (s32)NumMsg; Index++) {
			if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) &&
					((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) {
				Status = (s32)XST_FAILURE;
				goto END;
			}
		}
		/*
		 * Set the busy flag, which will be cleared when the transfer is
		 * entirely done.
		 */
		InstancePtr->IsBusy = (u32)TRUE;

		InstancePtr->Msg = Msg;
		InstancePtr->NumMsg = (s32)NumMsg;
		InstancePtr->MsgCnt = 0;

		/* Select slave */
		XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
		/* This might not work if not manual start */
		/* Put first message in FIFO along with the above slave select */
		XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[0]);
		XQspiPsu_ManualStartEnable(InstancePtr);

		/* Enable interrupts */
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IER_OFFSET,
			(u32)XQSPIPSU_IER_TXNOT_FULL_MASK |
			(u32)XQSPIPSU_IER_TXEMPTY_MASK |
			(u32)XQSPIPSU_IER_RXNEMPTY_MASK |
			(u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
			(u32)XQSPIPSU_IER_RXEMPTY_MASK);

		if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
			XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET,
					XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK);
		}
	}
	Status = (s32)XST_SUCCESS;

	END:
	return Status;
}

/*****************************************************************************/
/**
 *
 * Handles interrupt based transfers by acting on GENFIFO and DMA interurpts.
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 *
 * @return
 *		- XST_SUCCESS if successful.
 *		- XST_FAILURE if transfer fails.
 *
 * @note	None.
 *
 ******************************************************************************/
s32 XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr)
{
	u32 QspiPsuStatusReg, DmaIntrStatusReg = 0;
	XQspiPsu_Msg *Msg;
	s32 NumMsg;
	s32 MsgCnt;
	u8 DeltaMsgCnt = 0;
	u32 TxRxFlag;

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

	Msg = InstancePtr->Msg;
	NumMsg = InstancePtr->NumMsg;
	MsgCnt = InstancePtr->MsgCnt;
	TxRxFlag = Msg[MsgCnt].Flags;

	/* QSPIPSU Intr cleared on read */
	QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET);
	if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
		/* DMA Intr write to clear */
		DmaIntrStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
					XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET);
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET,
					DmaIntrStatusReg);
	}
	if (((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK) != (u32)FALSE)) {
		/* Call status handler to indicate error */
		InstancePtr->StatusHandler(InstancePtr->StatusRef,
				XST_SPI_COMMAND_ERROR, 0);
	}
	/* Fill more data to be txed if required */
	if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) &&
		((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != (u32)FALSE) &&
		(InstancePtr->TxBytes > 0)) {
		XQspiPsu_FillTxFifo(InstancePtr, &Msg[MsgCnt], (u32)XQSPIPSU_TXD_DEPTH);
	}
	/*
	 * Check if the entry is ONLY TX and increase MsgCnt.
	 * This is to allow TX and RX together in one entry - corner case.
	 */
	if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) &&
		((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) != (u32)FALSE) &&
		((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE) &&
		(InstancePtr->TxBytes == 0) &&
		((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) {
		MsgCnt += 1;
		DeltaMsgCnt = 1U;
	}

	if ((MsgCnt < NumMsg) &&
                        ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) {
		if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
			if ((DmaIntrStatusReg &
					XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) {
				/* DMA transfer done, Invalidate Data Cache */
				if (!((Msg[MsgCnt].RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) ||
						(Msg[MsgCnt].Xfer64bit != (u8)0U)) &&
						(InstancePtr->Config.IsCacheCoherent == 0U)) {
					Xil_DCacheInvalidateRange((INTPTR)Msg[MsgCnt].RxBfrPtr, (INTPTR)Msg[MsgCnt].ByteCount);
				}
				if (XQspiPsu_SetIOMode(InstancePtr, &Msg[MsgCnt]) == (u32)TRUE) {
					XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[MsgCnt]);
					XQspiPsu_ManualStartEnable(InstancePtr);
				} else {
					InstancePtr->RxBytes = 0;
					MsgCnt += 1;
					DeltaMsgCnt = 1U;
				}
			}
		} else {
			if (InstancePtr->RxBytes != 0) {
				XQspiPsu_IORead(InstancePtr, &Msg[MsgCnt], QspiPsuStatusReg);
				if (InstancePtr->RxBytes == 0) {
					MsgCnt += 1;
					DeltaMsgCnt = 1U;
				}
			}
		}
	}

	/*
	 * Dummy byte transfer
	 * MsgCnt < NumMsg check is to ensure is it a valid dummy cycle message
	 * If one of the above conditions increased MsgCnt, then
	 * the new message is yet to be placed in the FIFO; hence !DeltaMsgCnt.
	 */
	if ((MsgCnt < NumMsg) && (DeltaMsgCnt == (u8)FALSE) &&
		((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE) &&
		((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE) &&
		((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) == (u32)FALSE) &&
		((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE)) {
		MsgCnt += 1;
		DeltaMsgCnt = 1U;
	}
	InstancePtr->MsgCnt = MsgCnt;
	/*
	 * DeltaMsgCnt is to handle conditions where genfifo empty can be set
	 * while tx is still not empty or rx dma is not yet done.
	 * MsgCnt > NumMsg indicates CS de-assert entry was also executed.
	 */
	if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE) &&
		((DeltaMsgCnt != (u8)FALSE) || (MsgCnt > NumMsg))) {
		if (MsgCnt < NumMsg) {
			if (InstancePtr->IsUnaligned != 0) {
				InstancePtr->IsUnaligned = 0;
				XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
					XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(
					InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) |
					XQSPIPSU_CFG_MODE_EN_DMA_MASK));
				InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
			}
			/* This might not work if not manual start */
			XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[MsgCnt]);
			XQspiPsu_ManualStartEnable(InstancePtr);
		} else if (MsgCnt == NumMsg) {
			/* This is just to keep track of the de-assert entry */
			MsgCnt += 1;
			InstancePtr->MsgCnt = MsgCnt;
			/* De-select slave */
			XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
			XQspiPsu_ManualStartEnable(InstancePtr);
		} else {
			/* Disable interrupts */
			XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IDR_OFFSET,
					(u32)XQSPIPSU_IER_TXNOT_FULL_MASK |
					(u32)XQSPIPSU_IER_TXEMPTY_MASK |
					(u32)XQSPIPSU_IER_RXNEMPTY_MASK |
					(u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK |
					(u32)XQSPIPSU_IER_RXEMPTY_MASK);
			if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
				XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
					XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET,
					XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK);
			}
			/* Clear the busy flag. */
			InstancePtr->IsBusy = (u32)FALSE;
#if defined  (XCLOCKING)
			Xil_ClockDisable(InstancePtr->Config.RefClk);
#endif
			/* Call status handler to indicate completion */
			InstancePtr->StatusHandler(InstancePtr->StatusRef,
						XST_SPI_TRANSFER_DONE, 0);
		}
	}
	if ((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) != (u32)FALSE) {
		XQspiPsu_PollDataHandler(InstancePtr, QspiPsuStatusReg);
	}
	return (s32)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.
 *
 * <pre>
 *
 * 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 QSPIPSU device lost data. Data was received
 *				but the receive data register/FIFO was full.
 *
 * </pre>
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 * @param	CallBackRef is the upper layer callback reference passed back
 *		when the callback function is invoked.
 * @param	FuncPointer 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 XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef,
				XQspiPsu_StatusHandler FuncPointer)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(FuncPointer != NULL);
	Xil_AssertVoid(CallBackRef != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	InstancePtr->StatusHandler = FuncPointer;
	InstancePtr->StatusRef = CallBackRef;
}

/*****************************************************************************/
/**
 * @brief
 * This API enables/ disables Write Protect pin on the flash parts.
 *
 * @param	InstancePtr is a pointer to the QSPIPSU driver component to use.
 *
 * @param	Toggle is a value of the GPIO pin
 *
 * @return	None
 *
 * @note	By default WP pin as per the QSPI controller is driven High
 *		which means no write protection. Calling this function once
 *		will enable the protection.
 *
 ******************************************************************************/
void XQspiPsu_WriteProtectToggle(const XQspiPsu *InstancePtr, u32 Toggle)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	/* For Single and Stacked flash configuration with x1 or x2 mode*/
	if (InstancePtr->Config.ConnectionMode ==
		XQSPIPSU_CONNECTION_MODE_SINGLE) {
		/* Select slave */
		XQspiPsu_GenFifoEntryCSAssert(InstancePtr);

		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_GPIO_OFFSET, Toggle);

	} else {
#ifdef DEBUG
		xil_printf("Dual Parallel/Stacked configuration ");
		xil_printf("is not supported by this API\r\n");
#endif
	}
}

/*****************************************************************************/
/**
*
* This function start a DMA transfer.
*
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 * @param	Msg is a pointer to the structure containing transfer data.
 * @param	NumMsg is the number of messages to be transferred.
 *
 * @return
 *		- XST_SUCCESS if successful.
 *		- XST_FAILURE if ByteCount is greater than
 *		  XQSPIPSU_DMA_BYTES_MAX.
 *		- XST_DEVICE_BUSY if a transfer is already in progress.
 *
 * @note	None.
 *
*
******************************************************************************/
s32 XQspiPsu_StartDmaTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
				u32 NumMsg)
{
	s32 Index;
	u32 QspiPsuStatusReg = 0;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(Msg != NULL);
	Xil_AssertNonvoid(NumMsg > 0U);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	for (Index = 0; Index < (s32)NumMsg; Index++) {
		Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
	}

	/*
	 * Check whether there is another transfer in progress.
	 * Not thread-safe
	 */
	if (InstancePtr->IsBusy == (u32)TRUE) {
		return (s32)XST_DEVICE_BUSY;
	}

	/* Check for ByteCount upper limit - 2^28 for DMA */
	for (Index = 0; Index < (s32)NumMsg; Index++) {
		if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) &&
		    ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) {
			return (s32)XST_FAILURE;
		}
	}

	/*
	 * Set the busy flag, which will be cleared when the transfer is
	 * entirely done.
	 */
	InstancePtr->IsBusy = (u32)TRUE;

	/* Select slave */
	XQspiPsu_GenFifoEntryCSAssert(InstancePtr);
	/* list */
	Index = 0;
	while (Index < (s32)NumMsg) {
		InstancePtr->Msg = &Msg[Index];
		XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[Index]);
		if (InstancePtr->IsManualstart == (u32)TRUE) {
#ifdef DEBUG
			xil_printf("\nManual Start\r\n");
#endif
			XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
					  XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
					  XQSPIPSU_CFG_OFFSET) |
					  XQSPIPSU_CFG_START_GEN_FIFO_MASK);
		}
		do {
			if((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) &&
			   ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) {
				break;
			}
			QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET);

		} while (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE) ||
			(InstancePtr->TxBytes != 0) ||
			((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == (u32)FALSE));

		if(InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) {
			XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
					  XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(
					  InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) |
					  XQSPIPSU_CFG_MODE_EN_DMA_MASK));
			InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA;
		}
		Index++;
	}
	return (s32)XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function check for DMA transfer complete.
*
* @param	InstancePtr is a pointer to the XQspiPsu instance.
*
* @return
*		- XST_SUCCESS if DMA transfer complete.
*		- XST_FAILURE if DMA transfer is not completed.
*
* @note		None.
*
******************************************************************************/
s32 XQspiPsu_CheckDmaDone(XQspiPsu *InstancePtr)
{
	u32 QspiPsuStatusReg;
	u32 DmaIntrSts;

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

	DmaIntrSts = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET);
	if ((DmaIntrSts & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK)	!= (u32)FALSE) {
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts);
		/* DMA transfer done, Invalidate Data Cache */
		if (!((InstancePtr->Msg->RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) ||
		    (InstancePtr->Msg->Xfer64bit != (u8)0U)) &&
		    (InstancePtr->Config.IsCacheCoherent == 0U)) {
			Xil_DCacheInvalidateRange((INTPTR)InstancePtr->Msg->RxBfrPtr, (INTPTR)InstancePtr->RxBytes);
		}
		/* De-select slave */
		XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr);
		if (InstancePtr->IsManualstart == (u8)TRUE) {
#ifdef DEBUG
			xil_printf("\nManual Start\r\n");
#endif
			XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
					  XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) |
					  XQSPIPSU_CFG_START_GEN_FIFO_MASK);
		}
		do {
			QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET);
		} while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE);

		/* Clear the busy flag. */
		InstancePtr->IsBusy = (u32)FALSE;

		return (s32)XST_SUCCESS;
	}
	else {
		return (s32)XST_FAILURE;
	}

}
/** @} */