/******************************************************************************
* Copyright (C) 2020 - 2022 Xilinx, Inc.  All rights reserved.
* Copyright (c) 2022 - 2025 Advanced Micro Devices, Inc. All Rights Reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/


/*****************************************************************************/
/**
 *
 * @file xqspipsu_hw.c
 * @addtogroup qspipsu_api QSPIPSU APIs
 * @{
 *
 * The xqspipsu_hw.c contains functions to reads RXFifo, writes TXFifo and setup
 * RX DMA operation used by xqspipsu_control.c and xqspipsu_lowlevel.c files.
 *
 * <pre>
 * MODIFICATION HISTORY:
 *
 * Ver   Who Date     Changes
 * ----- --- -------- -----------------------------------------------
 * 1.11   akm  03/09/20 First release
 *         mn  03/30/20 Add xil_smc.h include for Xil_Smc calls
 * 1.13   akm  01/04/21 Fix MISRA-C violations.
 * 1.15   akm  10/21/21 Fix MISRA-C violations.
 * 1.15   akm  11/16/21 Typecast function parameter with appropriate
 * 			data type.
 * 1.15   akm  11/30/21 Fix compilation warnings reported with -Wundef flag
 * 1.15   akm  03/03/22 Enable tapdelay settings for applications on
 * 			 Microblaze platform.
 * 1.22   sb   10/24/25 Added cache invalidate when EL1_NONSECURE is not defined.
 *
 * </pre>
 ******************************************************************************/

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

#include "xqspipsu.h"
#include "xqspipsu_control.h"
#if defined (__aarch64__)
#include "xil_smc.h"
#endif
/************************** Constant Definitions *****************************/

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

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

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

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

/*****************************************************************************/

/*****************************************************************************/
/**
 *
 * Fills the TX FIFO as long as there is room in the FIFO or the bytes required
 * to be transmitted.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 * @param	Size Number of bytes to be transmitted.
 *
 * @return	None
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, u32 Size)
{
	u32 Count = 0;
	u32 Data = 0U;

	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(Msg != NULL);
	Xil_AssertVoid(Size != 0U);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_FillTxFifo\r\n");
#endif
	while ((InstancePtr->TxBytes > 0) && (Count < Size)) {
		if (InstancePtr->TxBytes >= 4) {
			(void)Xil_MemCpy((u8 *)&Data, Msg->TxBfrPtr, 4);
			Msg->TxBfrPtr += 4;
			InstancePtr->TxBytes -= 4;
			Count += 4U;
		} else {
			(void)Xil_MemCpy((u8 *)&Data, Msg->TxBfrPtr,
				(u32)InstancePtr->TxBytes);
			Msg->TxBfrPtr += InstancePtr->TxBytes;
			Count += (u32)InstancePtr->TxBytes;
			InstancePtr->TxBytes = 0;
		}
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_TXD_OFFSET, Data);
#ifdef DEBUG
	xil_printf("\nData is %08x\r\n", Data);
#endif

	}
	if (InstancePtr->TxBytes < 0) {
		InstancePtr->TxBytes = 0;
	}
}

/*****************************************************************************/
/**
 *
 * Checks the TX buffer in the message and setup the
 * TX FIFO as required.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 *
 * @return	None
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_TXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(Msg != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_TXSetup\r\n");
#endif
	InstancePtr->TxBytes = (s32)Msg->ByteCount;
	InstancePtr->SendBufferPtr = Msg->TxBfrPtr;

	XQspiPsu_FillTxFifo(InstancePtr, Msg, (u32)XQSPIPSU_TXD_DEPTH);
}

/*****************************************************************************/
/**
 *
 * Sets up the RX DMA operation.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 *
 * @return	None
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_SetupRxDma(const XQspiPsu *InstancePtr,
					XQspiPsu_Msg *Msg)
{
	s32 Remainder;
	s32 DmaRxBytes;
	UINTPTR AddrTemp;

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

	AddrTemp = ((UINTPTR)(Msg->RxBfrPtr) & XQSPIPSU_QSPIDMA_DST_ADDR_MASK);
	/* Check for RXBfrPtr to be word aligned */
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET, (u32)AddrTemp);

#if defined(__aarch64__) || defined(__arch64__)
	AddrTemp = ((UINTPTR)(Msg->RxBfrPtr) >> 32U);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, (u32)AddrTemp &
			XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK);
#else
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, 0U);
#endif

	Remainder = InstancePtr->RxBytes % 4;
	DmaRxBytes = InstancePtr->RxBytes;
	if (Remainder != 0) {
		/* This is done to make Dma bytes aligned */
		DmaRxBytes = InstancePtr->RxBytes - Remainder;
		Msg->ByteCount = (u32)DmaRxBytes;
	}
#if defined(EL1_NONSECURE) && (EL1_NONSECURE==1U)
	if (InstancePtr->Config.IsCacheCoherent == 0U) {
		Xil_DCacheInvalidateRange((INTPTR)Msg->RxBfrPtr, (INTPTR)Msg->ByteCount);
	}
#else
	Xil_DCacheInvalidateRange((INTPTR)Msg->RxBfrPtr, (INTPTR)Msg->ByteCount);
#endif
	/* Write no. of words to DMA DST SIZE */
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes);
}

/*****************************************************************************/
/**
 *
 * Sets up the RX DMA operation on a 32-bit Machine
 * For 64-bit DMA transfers.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 *
 * @return	None
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_Setup64BRxDma(const XQspiPsu *InstancePtr,
					XQspiPsu_Msg *Msg)
{
	s32 Remainder;
	s32 DmaRxBytes;
	u64 AddrTemp;

	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(Msg != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_Setup64BRxDma\r\n");
#endif
	AddrTemp = Msg->RxAddr64bit & XQSPIPSU_QSPIDMA_DST_ADDR_MASK;

	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET, (u32)AddrTemp);

	AddrTemp = (Msg->RxAddr64bit >> 32);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, (u32)AddrTemp &
			XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK);

	Remainder = InstancePtr->RxBytes % 4;
	DmaRxBytes = InstancePtr->RxBytes;
	if (Remainder != 0) {
		/* This is done to make Dma bytes aligned */
		DmaRxBytes = InstancePtr->RxBytes - Remainder;
		Msg->ByteCount = (u32)DmaRxBytes;
	}

	/* Write no. of words to DMA DST SIZE */
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes);

}

/*****************************************************************************/
/**
 *
 * Reads remaining bytes after the completion of a DMA transfer
 * using I/O mode.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 *
 * @return
 *		- XST_SUCCESS if successful.
 *		- XST_FAILURE if transfer fails.
 *		- XST_DEVICE_BUSY if a transfer is already in progress.
 *
 * @note	None.
 *
 ******************************************************************************/
u32 XQspiPsu_SetIOMode(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg)
{
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(Msg != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_DMARXComplete\r\n");
#endif

	/* Read remaining bytes using IO mode */
	if ((InstancePtr->RxBytes % 4) != 0) {
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,	XQSPIPSU_CFG_OFFSET,
				(XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) &
						~XQSPIPSU_CFG_MODE_EN_MASK));
		InstancePtr->ReadMode =	XQSPIPSU_READMODE_IO;
		Msg->ByteCount = (u32)InstancePtr->RxBytes % 4U;
		Msg->RxBfrPtr += (InstancePtr->RxBytes - (InstancePtr->RxBytes % 4));
		InstancePtr->IsUnaligned = 1;
		return (u32) TRUE;
	}
	return (u32) FALSE;
}

/*****************************************************************************/
/**
 *
 * Checks the RX buffers in the message and setup the
 * RX DMA as required.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 *
 * @return	None
 *
 *
 ******************************************************************************/
void XQspiPsu_RXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(Msg != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_RXSetup\r\n");
#endif
	InstancePtr->RxBytes = (s32)Msg->ByteCount;

	if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) {
		if ((Msg->RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) ||
			(Msg->Xfer64bit != (u8)0U)) {
			XQspiPsu_Setup64BRxDma(InstancePtr, Msg);
		} else {
			XQspiPsu_SetupRxDma(InstancePtr, Msg);
		}
	}
}

/*****************************************************************************/
/**
 *
 * Checks the TX/RX buffers in the message and setups up the
 * GENFIFO entries, TX FIFO, or RX DMA as required.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 * @param	GenFifoEntry Pointer to the variable in which GENFIFO mask
 *		is returned to calling function
 *
 * @return	None
 *
 *
 ******************************************************************************/
void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
					u32 *GenFifoEntry)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(Msg != NULL);
	Xil_AssertVoid(GenFifoEntry != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_TXRXSetup\r\n");
#endif
	/* Transmit */
	if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) &&
			((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) {

		*GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
		*GenFifoEntry |= XQSPIPSU_GENFIFO_TX;
		/* Discard RX data */
		*GenFifoEntry &= ~XQSPIPSU_GENFIFO_RX;

		/* Setup data to be TXed */
		XQspiPsu_TXSetup(InstancePtr, Msg);

		InstancePtr->RecvBufferPtr = NULL;
		InstancePtr->RxBytes = 0;
	}
	/*Receive*/
	if (((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE) &&
			((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE)) {

		/* TX auto fill */
		*GenFifoEntry &= ~XQSPIPSU_GENFIFO_TX;
		/* Setup RX */
		*GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
		*GenFifoEntry |= XQSPIPSU_GENFIFO_RX;

		/* Setup DMA for data to be RXed */
		XQspiPsu_RXSetup(InstancePtr, Msg);

		InstancePtr->SendBufferPtr = NULL;
		InstancePtr->TxBytes = 0;
	}
	/* If only dummy is requested as a separate entry */
	if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE) &&
			((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) {

		*GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
		*GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX);
		InstancePtr->TxBytes = 0;
		InstancePtr->RxBytes = 0;
		InstancePtr->SendBufferPtr = NULL;
		InstancePtr->RecvBufferPtr = NULL;
	}
	/* Dummy and cmd sent by upper layer to received data */
	if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) &&
			((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) {
		*GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER;
		*GenFifoEntry |= (XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX);

		/* Setup data to be TXed */
		XQspiPsu_TXSetup(InstancePtr, Msg);
		/* Setup DMA for data to be RXed */
		XQspiPsu_RXSetup(InstancePtr, Msg);
	}
}
/*****************************************************************************/
/**
 *
 * Writes the data length to GENFIFO entries to be
 * transmitted or received.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 * @param	GenFifoEntry Pointer to the variable in which GENFIFO mask is returned to the calling function.
 *
 * @return
 *		- XST_SUCCESS if successful.
 *		- XST_FAILURE if transfer fails.
 *		- XST_DEVICE_BUSY if a transfer is already in progress.
 *
 *
 ******************************************************************************/
void XQspiPsu_GenFifoEntryDataLen(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
		u32 *GenFifoEntry)
{
	u32 TempCount;
	u32 ImmData;

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

	if (Msg->ByteCount <= XQSPIPSU_GENFIFO_IMM_DATA_MASK) {
		*GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK;
		*GenFifoEntry |= Msg->ByteCount;
	#ifdef DEBUG
	xil_printf("\nFifoEntry=%08x\r\n", *GenFifoEntry);
	#endif
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET,
				*GenFifoEntry);
	} else {
		TempCount = Msg->ByteCount;
		u32 Exponent = 8;	/* 2^8 = 256 */
		ImmData = TempCount & 0xFFU;
		/* Exponent entries */
		*GenFifoEntry |= XQSPIPSU_GENFIFO_EXP;
		while (TempCount != 0U) {
			if ((TempCount & XQSPIPSU_GENFIFO_EXP_START) != (u32)FALSE) {
				*GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK;
				*GenFifoEntry |= Exponent;
	#ifdef DEBUG
				xil_printf("\nFifoEntry=%08x\r\n",
					*GenFifoEntry);
	#endif
				XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET,
					*GenFifoEntry);
			}
			TempCount = TempCount >> 1;
			Exponent++;
		}
		/* Immediate entry */
		*GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_EXP;
		if ((ImmData & 0xFFU) != (u32)FALSE) {
			*GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK;
			*GenFifoEntry |= ImmData & 0xFFU;
	#ifdef DEBUG
			xil_printf("\nFifoEntry=%08x\r\n", *GenFifoEntry);
	#endif
			XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET,
					*GenFifoEntry);
		}
	}
}

/*****************************************************************************/
/**
 *
 * Creates Poll configuration register data to write
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 *
 * @param	FlashMsg Pointer to the structure containing transfer data.
 *
 * @return	None
 *
 ******************************************************************************/
u32 XQspiPsu_CreatePollDataConfig(const XQspiPsu *InstancePtr,
		const XQspiPsu_Msg *FlashMsg)
{
	u32 ConfigData = 0;

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

	if ((InstancePtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_UPPER) != (u32)FALSE) {
		ConfigData = (u32)XQSPIPSU_SELECT_FLASH_BUS_LOWER <<
				XQSPIPSU_POLL_CFG_EN_MASK_UPPER_SHIFT;
	}
	if ((InstancePtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_LOWER) != (u32)FALSE) {
		ConfigData |= (u32)XQSPIPSU_SELECT_FLASH_BUS_LOWER <<
				XQSPIPSU_POLL_CFG_EN_MASK_LOWER_SHIFT;
	}
	ConfigData |= (u32)(((u32)FlashMsg->PollBusMask <<
			XQSPIPSU_POLL_CFG_MASK_EN_SHIFT) & XQSPIPSU_POLL_CFG_MASK_EN_MASK);
	ConfigData |= (u32)(((u32)FlashMsg->PollData <<
			XQSPIPSU_POLL_CFG_DATA_VALUE_SHIFT)
			& XQSPIPSU_POLL_CFG_DATA_VALUE_MASK);
	return ConfigData;
}

/*****************************************************************************/
/**
 *
 * Selects SPI mode - x1 or x2 or x4.
 *
 * @param	SpiMode spi or dual or quad.
 * @return	Mask to set desired SPI mode in GENFIFO entry.
 *
 *
 ******************************************************************************/
u32 XQspiPsu_SelectSpiMode(u8 SpiMode)
{
	u32 Mask;

	Xil_AssertNonvoid(SpiMode > 0U);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_SelectSpiMode\r\n");
#endif

	switch (SpiMode) {
	case XQSPIPSU_SELECT_MODE_DUALSPI:
		Mask = XQSPIPSU_GENFIFO_MODE_DUALSPI;
		break;
	case XQSPIPSU_SELECT_MODE_QUADSPI:
		Mask = XQSPIPSU_GENFIFO_MODE_QUADSPI;
		break;
	case XQSPIPSU_SELECT_MODE_SPI:
		Mask = XQSPIPSU_GENFIFO_MODE_SPI;
		break;
	default:
		Mask = XQSPIPSU_GENFIFO_MODE_SPI;
		break;
	}
#ifdef DEBUG
	xil_printf("\nSPIMode is %08x\r\n", SpiMode);
#endif
	return Mask;
}

/*****************************************************************************/
/**
 *
 * Enables and initializes DMA Mode, set little endain, disable poll timeout,
 * clears prescalar bits and reset thresholds.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 *
 * @return	None.
 *
 *
 ******************************************************************************/
void XQspiPsu_SetDefaultConfig(XQspiPsu *InstancePtr)
{
	u32 ConfigReg;

	Xil_AssertVoid(InstancePtr != NULL);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_SetDefaultConfig\r\n");
#endif

	/* Default value to config register */
	ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_CFG_OFFSET);

	/* DMA mode */
	ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
	ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
	/* Manual start */
	ConfigReg |= XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK;
	/* Little endain by default */
	ConfigReg &= ~XQSPIPSU_CFG_ENDIAN_MASK;
	/* Disable poll timeout */
	ConfigReg &= ~XQSPIPSU_CFG_EN_POLL_TO_MASK;
	/* Set hold bit */
	ConfigReg |= XQSPIPSU_CFG_WP_HOLD_MASK;
	/* Clear prescalar by default */
	ConfigReg &= ~(u32)XQSPIPSU_CFG_BAUD_RATE_DIV_MASK;
	/* CPOL CPHA 00 */
	ConfigReg &= ~(u32)XQSPIPSU_CFG_CLK_PHA_MASK;
	ConfigReg &= ~(u32)XQSPIPSU_CFG_CLK_POL_MASK;

	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_CFG_OFFSET, ConfigReg);

	/* Set by default to allow for high frequencies */
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_LPBK_DLY_ADJ_OFFSET,
		XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_LPBK_DLY_ADJ_OFFSET) |
			XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK);

	/* Reset thresholds */
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_TX_THRESHOLD_OFFSET, XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_RX_THRESHOLD_OFFSET, XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_GF_THRESHOLD_OFFSET, XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL);

	/* DMA init */
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET,
			XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL);
}

/*****************************************************************************/
/**
 *
 * Reads the specified number of bytes from RX FIFO
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 * @param	Size Number of bytes to be read.
 *
 * @return	None
 *
 *
 ******************************************************************************/
void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr,	XQspiPsu_Msg *Msg, s32 Size)
{
	s32 Count = 0;
	u32 Data;

	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(Msg != NULL);
	Xil_AssertVoid(Size > 0);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_ReadRxFifo\r\n");
#endif
	while ((InstancePtr->RxBytes != 0) && (Count < Size)) {
		Data = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_RXD_OFFSET);
#ifdef DEBUG
		xil_printf("\nData is %08x\r\n", Data);
#endif
		if (InstancePtr->RxBytes >= 4) {
			(void)Xil_MemCpy(Msg->RxBfrPtr, (u8 *)&Data, 4);
			InstancePtr->RxBytes -= 4;
			Msg->RxBfrPtr += 4;
			Count += 4;
		} else {
			/* Read unaligned bytes (< 4 bytes) */
			(void)Xil_MemCpy(Msg->RxBfrPtr, (u8 *)&Data,
				(u32)InstancePtr->RxBytes);
			Msg->RxBfrPtr += InstancePtr->RxBytes;
			Count += InstancePtr->RxBytes;
			InstancePtr->RxBytes = 0;
		}
	}
}

/*****************************************************************************/
/**
 *
 * Reads data from RXFifo in I/O mode.
 *
 * @param	InstancePtr Pointer to the XQspiPsu instance.
 * @param	Msg Pointer to the structure containing transfer data.
 * @param	StatusReg Interrupt status Register value.
 *
 * @return	None.
 *
 *
 ******************************************************************************/
void XQspiPsu_IORead(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg,
		u32 StatusReg)
{
	s32 RxThr;

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

	if ((StatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != 0U) {
			/*
			 * Check if PIO RX is complete and
			 * update RxBytes
			 */
		RxThr = (s32)XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_RX_THRESHOLD_OFFSET);
		RxThr = RxThr*4;
		XQspiPsu_ReadRxFifo(InstancePtr, Msg, RxThr);

		return;
	}

	if ((StatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) {
		XQspiPsu_ReadRxFifo(InstancePtr, Msg, InstancePtr->RxBytes);
	}
}

#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) || defined (__riscv)
/*****************************************************************************/
/**
*
* Sets the Tapdelay values for the QSPIPSU device driver.The device
* must be idle rather than busy transferring data before setting Tapdelay.
*
* @param	InstancePtr Pointer to the XQspiPsu instance.
* @param	TapdelayBypss Contains the IOU_TAPDLY_BYPASS register value.
* @param	LPBKDelay Contains the GQSPI_LPBK_DLY_ADJ register value.
* @param	Datadelay Contains the QSPI_DATA_DLY_ADJ register value.
*
* @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 TapDelay.
*
* @note
* This function is not thread-safe.
*
******************************************************************************/
s32 XQspipsu_Set_TapDelay(const XQspiPsu *InstancePtr, u32 TapdelayBypass,
						u32 LPBKDelay, u32 Datadelay)
{
	s32 Status;

	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 == (u32)TRUE) {
		Status = (s32)XST_DEVICE_BUSY;
	} else {
#if defined (__aarch64__) && (EL1_NONSECURE == 1) && !defined (versal)
		Xil_Smc(MMIO_WRITE_SMC_FID, (u64)(XPS_SYS_CTRL_BASEADDR +
				IOU_TAPDLY_BYPASS_OFFSET) | ((u64)(0x4) << 32),
				(u64)TapdelayBypass, 0, 0, 0, 0, 0);
#elif defined (versal)
		XQspiPsu_WriteReg(XQSPIPS_BASEADDR, IOU_TAPDLY_BYPASS_OFFSET,
				TapdelayBypass);
#else
		XQspiPsu_WriteReg(XPS_SYS_CTRL_BASEADDR, IOU_TAPDLY_BYPASS_OFFSET,
				TapdelayBypass);
#endif
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_LPBK_DLY_ADJ_OFFSET, LPBKDelay);
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
				XQSPIPSU_DATA_DLY_ADJ_OFFSET, Datadelay);

		Status = (s32)XST_SUCCESS;
	}
	return Status;
}
#endif
/** @} */
