[PATCH v2 2/2] bsps: Import Xilinx NAND driver

Kinsey Moore kinsey.moore at oarcorp.com
Thu Dec 22 18:56:12 UTC 2022


This adds Xilinx's driver for the Xilinx NAND controller embedded in the
ZynqMP SoC. Within that device alone, it is possible to access this
peripheral from MicroBlaze, ARMv7, and ARMv8 cores. This has been added
to the hardware ZynqMP BSPs since QEMU does not support emulation of
this peripheral. This driver supports polled operation only. The
imported files are and should be able to remain unmodified. Import
information is kept in bsps/shared/dev/nand/VERSION.
---
 bsps/include/dev/nand/xnandpsu.h              |  581 ++++
 bsps/include/dev/nand/xnandpsu_bbm.h          |  180 +
 bsps/include/dev/nand/xnandpsu_hw.h           |  483 +++
 bsps/include/dev/nand/xnandpsu_onfi.h         |  316 ++
 bsps/shared/dev/nand/VERSION                  |   20 +
 bsps/shared/dev/nand/xnandpsu.c               | 2922 +++++++++++++++++
 bsps/shared/dev/nand/xnandpsu_bbm.c           |  912 +++++
 bsps/shared/dev/nand/xnandpsu_g.c             |   47 +
 bsps/shared/dev/nand/xnandpsu_onfi.c          |   91 +
 bsps/shared/dev/nand/xnandpsu_sinit.c         |   70 +
 .../bsps/aarch64/xilinx-zynqmp/grp_zu3eg.yml  |    2 +
 spec/build/bsps/objnandpsu.yml                |   33 +
 spec/build/bsps/optnandpsu0baseaddress.yml    |   18 +
 spec/build/bsps/optnandpsunuminstances.yml    |   18 +
 14 files changed, 5693 insertions(+)
 create mode 100644 bsps/include/dev/nand/xnandpsu.h
 create mode 100644 bsps/include/dev/nand/xnandpsu_bbm.h
 create mode 100644 bsps/include/dev/nand/xnandpsu_hw.h
 create mode 100644 bsps/include/dev/nand/xnandpsu_onfi.h
 create mode 100644 bsps/shared/dev/nand/VERSION
 create mode 100644 bsps/shared/dev/nand/xnandpsu.c
 create mode 100644 bsps/shared/dev/nand/xnandpsu_bbm.c
 create mode 100644 bsps/shared/dev/nand/xnandpsu_g.c
 create mode 100644 bsps/shared/dev/nand/xnandpsu_onfi.c
 create mode 100644 bsps/shared/dev/nand/xnandpsu_sinit.c
 create mode 100644 spec/build/bsps/objnandpsu.yml
 create mode 100644 spec/build/bsps/optnandpsu0baseaddress.yml
 create mode 100644 spec/build/bsps/optnandpsunuminstances.yml

diff --git a/bsps/include/dev/nand/xnandpsu.h b/bsps/include/dev/nand/xnandpsu.h
new file mode 100644
index 0000000000..3625299fb2
--- /dev/null
+++ b/bsps/include/dev/nand/xnandpsu.h
@@ -0,0 +1,581 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu.h
+* @addtogroup nandpsu_v1_10
+* @{
+* @details
+*
+* This file implements a driver to support Arasan NAND controller
+* present in Zynq Ultrascale Mp.
+*
+* <b>Driver Initialization</b>
+*
+* The function call XNandPsu_CfgInitialize() should be called by the application
+* before any other function in the driver. The initialization function takes
+* device specific data (like device id, instance id, and base address) and
+* initializes the XNandPsu instance with the device specific data.
+*
+* <b>Device Geometry</b>
+*
+* NAND flash device is memory device and it is segmented into areas called
+* Logical Unit(s) (LUN) and further in to blocks and pages. A NAND flash device
+* can have multiple LUN. LUN is sequential raw of multiple blocks of the same
+* size. A block is the smallest erasable unit of data within the Flash array of
+* a LUN. The size of each block is based on a power of 2. There is no
+* restriction on the number of blocks within the LUN. A block contains a number
+* of pages. A page is the smallest addressable unit for read and program
+* operations. The arrangement of LUN, blocks, and pages is referred to by this
+* module as the part's geometry.
+*
+* The cells within the part can be programmed from a logic 1 to a logic 0
+* and not the other way around. To change a cell back to a logic 1, the
+* entire block containing that cell must be erased. When a block is erased
+* all bytes contain the value 0xFF. The number of times a block can be
+* erased is finite. Eventually the block will wear out and will no longer
+* be capable of erasure. As of this writing, the typical flash block can
+* be erased 100,000 or more times.
+*
+* The jobs done by this driver typically are:
+*	- 8-bit operational mode
+*	- Read, Write, and Erase operation
+*
+* <b>Write Operation</b>
+*
+* The write call can be used to write a minimum of one byte and a maximum
+* entire flash. If the address offset specified to write is out of flash or if
+* the number of bytes specified from the offset exceed flash boundaries
+* an error is reported back to the user. The write is blocking in nature in that
+* the control is returned back to user only after the write operation is
+* completed successfully or an error is reported.
+*
+* <b>Read Operation</b>
+*
+* The read call can be used to read a minimum of one byte and maximum of
+* entire flash. If the address offset specified to read is out of flash or if
+* the number of bytes specified from the offset exceed flash boundaries
+* an error is reported back to the user. The read is blocking in nature in that
+* the control is returned back to user only after the read operation is
+* completed successfully or an error is reported.
+*
+* <b>Erase Operation</b>
+*
+* The erase operations are provided to erase a Block in the Flash memory. The
+* erase call is blocking in nature in that the control is returned back to user
+* only after the erase operation is completed successfully or an error is
+* reported.
+*
+* @note		Driver has been renamed to nandpsu after change in
+*		naming convention.
+*
+* This driver is intended to be RTOS and processor independent. It works with
+* physical addresses only. Any needs for dynamic memory management, threads,
+* mutual exclusion, virtual memory, cache control, or HW write protection
+* management must be satisfied by the layer above this driver.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* 2.0   sb     01/12/2015  Removed Null checks for Buffer passed
+*			   as parameter to Read API's
+*			   - XNandPsu_Read()
+*			   - XNandPsu_ReadPage
+*			   Modified
+*			   - XNandPsu_SetFeature()
+*			   - XNandPsu_GetFeature()
+*			   and made them public.
+*			   Removed Failure Return for BCF Error check in
+*			   XNandPsu_ReadPage() and added BCH_Error counter
+*			   in the instance pointer structure.
+* 			   Added XNandPsu_Prepare_Cmd API
+*			   Replaced
+*			   - XNandPsu_IntrStsEnable
+*			   - XNandPsu_IntrStsClear
+*			   - XNandPsu_IntrClear
+*			   - XNandPsu_SetProgramReg
+*			   with XNandPsu_WriteReg call
+*			   Modified xnandpsu.c file API's with above changes.
+* 			   Corrected the program command for Set Feature API.
+*			   Modified
+*			   - XNandPsu_OnfiReadStatus
+*			   - XNandPsu_GetFeature
+*			   - XNandPsu_SetFeature
+*			   to add support for DDR mode.
+*			   Changed Convention for SLC/MLC
+*			   SLC --> HAMMING
+*			   MLC --> BCH
+*			   SlcMlc --> IsBCH
+*			   Added support for writing BBT signature and version
+*			   in page section by enabling XNANDPSU_BBT_NO_OOB.
+*			   Removed extra DMA mode initialization from
+*			   the XNandPsu_CfgInitialize API.
+*			   Modified
+*			   - XNandPsu_SetEccAddrSize
+*			   ECC address now is calculated based upon the
+*			   size of spare area
+*			   Modified Block Erase API, removed clearing of
+*			   packet register before erase.
+*			   Clearing Data Interface Register before
+*			   XNandPsu_OnfiReset call.
+*			   Modified XNandPsu_ChangeTimingMode API supporting
+*			   SDR and NVDDR interface for timing modes 0 to 5.
+*			   Modified Bbt Signature and Version Offset value for
+*			   Oob and No-Oob region.
+* 1.0   kpc    17/06/2015  Increased the timeout for complete event to avoid
+*			   timeout errors for erase operation on slower devices.
+* 1.1   mi     09/16/16 Removed compilation warnings with extra compiler flags.
+* 1.1	nsk    11/07/16    Change memcpy to Xil_MemCpy, CR#960462
+* 1.2   nsk    01/19/17    Fix for the failure of reading nand first redundant
+*                          parameter page. CR#966603
+*       ms     02/12/17    Fix for the compilation warning in _g.c file.
+*       ms     03/17/17    Added readme.txt file in examples folder for doxygen
+*                          generation.
+*       ms     04/10/17    Modified Comment lines in nandpsu_example.c to
+*                          follow doxygen rules.
+* 1.2	nsk    08/08/17    Added support to import example in SDK
+* 1.4	nsk    04/10/18    Added ICCARM compiler support. CR#997552.
+* 1.5   mus    11/08/18    Updated BBT signature array size  in
+*                          XNandPsu_BbtDesc structure to fix the compilation
+*                          warnings.
+# 1.6	sd     06/02/20    Added Clock support
+* 1.6	sd     20/03/20    Added compilation flag
+* 1.8   sg     03/18/21    Added validation check for parameter page.
+* 1.9   akm    07/15/21    Initialize NandInstPtr with Data Interface & Timing mode info.
+* 1.10  akm    10/20/21    Fix gcc warnings.
+* 1.10  akm    12/21/21    Validate input parameters before use.
+* 1.10  akm    01/05/22    Remove assert checks form static and internal APIs.
+*
+* </pre>
+*
+******************************************************************************/
+
+#ifndef XNANDPSU_H		/* prevent circular inclusions */
+#define XNANDPSU_H		/* by using protection macros */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************** Include Files *********************************/
+#include "xil_types.h"
+#include <string.h>
+#include "xstatus.h"
+#include "xil_assert.h"
+#include "xnandpsu_hw.h"
+#include "xnandpsu_onfi.h"
+#include "xil_cache.h"
+#if defined  (XCLOCKING)
+#include "xil_clocking.h"
+#endif
+/************************** Constant Definitions *****************************/
+
+#define XNANDPSU_DEBUG
+
+#define XNANDPSU_MAX_TARGETS		1U	/**< ce_n0, ce_n1 */
+#define XNANDPSU_MAX_PKT_SIZE		0x7FFU	/**< Max packet size */
+#define XNANDPSU_MAX_PKT_COUNT		0xFFFU	/**< Max packet count */
+
+#define XNANDPSU_PAGE_SIZE_512		512U	/**< 512 bytes page */
+#define XNANDPSU_PAGE_SIZE_2K		2048U	/**< 2K bytes page */
+#define XNANDPSU_PAGE_SIZE_4K		4096U	/**< 4K bytes page */
+#define XNANDPSU_PAGE_SIZE_8K		8192U	/**< 8K bytes page */
+#define XNANDPSU_PAGE_SIZE_16K		16384U	/**< 16K bytes page */
+#define XNANDPSU_PAGE_SIZE_1K_16BIT	1024U	/**< 16-bit 2K bytes page */
+#define XNANDPSU_MAX_PAGE_SIZE		16384U	/**< Max page size supported */
+
+#define XNANDPSU_HAMMING		0x1U	/**< Hamming Flash */
+#define XNANDPSU_BCH			0x2U	/**< BCH Flash */
+
+#define XNANDPSU_MAX_BLOCKS		16384U	/**< Max number of Blocks */
+#define XNANDPSU_MAX_SPARE_SIZE		0x800U	/**< Max spare bytes of a NAND
+						  flash page of 16K */
+#define XNANDPSU_MAX_LUNS		8U	/**< Max number of LUNs */
+#define XNANDPSU_MAX_PAGES_PER_BLOCK	512U 	/**< Max number pages per block */
+
+#define XNANDPSU_INTR_POLL_TIMEOUT	0xF000000U
+
+#define XNANDPSU_SDR_CLK		((u16)100U * (u16)1000U * (u16)1000U)
+#define XNANDPSU_NVDDR_CLK_0		((u16)20U * (u16)1000U * (u16)1000U)
+#define XNANDPSU_NVDDR_CLK_1		((u16)33U * (u16)1000U * (u16)1000U)
+#define XNANDPSU_NVDDR_CLK_2		((u16)50U * (u16)1000U * (u16)1000U)
+#define XNANDPSU_NVDDR_CLK_3		((u16)66U * (u16)1000U * (u16)1000U)
+#define XNANDPSU_NVDDR_CLK_4		((u16)83U * (u16)1000U * (u16)1000U)
+#define XNANDPSU_NVDDR_CLK_5		((u16)100U * (u16)1000U * (u16)1000U)
+
+#define XNANDPSU_MAX_TIMING_MODE	5
+/**
+ * The XNandPsu_Config structure contains configuration information for NAND
+ * controller.
+ */
+typedef struct {
+	u16 DeviceId;		/**< Instance ID of NAND flash controller */
+	u32 BaseAddress;	/**< Base address of NAND flash controller */
+	u8 IsCacheCoherent;	/**< Describes whether Cache Coherent or not */
+#if defined  (XCLOCKING)
+	u32 RefClk;		/**< Input clocks */
+#endif
+} XNandPsu_Config;
+
+/**
+ * The XNandPsu_DataInterface enum contains flash operating mode.
+ */
+typedef enum {
+	XNANDPSU_SDR = 0U,		/**< Single Data Rate */
+	XNANDPSU_NVDDR			/**< Double Data Rate */
+} XNandPsu_DataInterface;
+
+/**
+ * XNandPsu_TimingMode enum contains timing modes.
+ */
+typedef enum {
+	XNANDPSU_SDR0 = 0U,
+	XNANDPSU_SDR1,
+	XNANDPSU_SDR2,
+	XNANDPSU_SDR3,
+	XNANDPSU_SDR4,
+	XNANDPSU_SDR5,
+	XNANDPSU_NVDDR0,
+	XNANDPSU_NVDDR1,
+	XNANDPSU_NVDDR2,
+	XNANDPSU_NVDDR3,
+	XNANDPSU_NVDDR4,
+	XNANDPSU_NVDDR5
+} XNandPsu_TimingMode;
+
+/**
+ * The XNandPsu_SWMode enum contains the driver operating mode.
+ */
+typedef enum {
+	XNANDPSU_POLLING = 0,		/**< Polling */
+	XNANDPSU_INTERRUPT		/**< Interrupt */
+} XNandPsu_SWMode;
+
+/**
+ * The XNandPsu_DmaMode enum contains the controller MDMA mode.
+ */
+typedef enum {
+	XNANDPSU_PIO = 0,		/**< PIO Mode */
+	XNANDPSU_SDMA,			/**< SDMA Mode */
+	XNANDPSU_MDMA			/**< MDMA Mode */
+} XNandPsu_DmaMode;
+
+/**
+ * The XNandPsu_EccMode enum contains ECC functionality.
+ */
+typedef enum {
+	XNANDPSU_NONE = 0,
+	XNANDPSU_HWECC,
+	XNANDPSU_EZNAND,
+	XNANDPSU_ONDIE
+} XNandPsu_EccMode;
+
+/**
+ * Bad block table descriptor
+ */
+typedef struct {
+	u32 PageOffset[XNANDPSU_MAX_TARGETS];
+				/**< Page offset where BBT resides */
+	u32 SigOffset;		/**< Signature offset in Spare area */
+	u32 VerOffset;		/**< Offset of BBT version */
+	u32 SigLength;		/**< Length of the signature */
+	u32 MaxBlocks;		/**< Max blocks to search for BBT */
+	char Signature[5];	/**< BBT signature */
+	u8 Version[XNANDPSU_MAX_TARGETS];
+				/**< BBT version */
+	u32 Valid;		/**< BBT descriptor is valid or not */
+} XNandPsu_BbtDesc;
+
+/**
+ * Bad block pattern
+ */
+typedef struct {
+	u32 Options;		/**< Options to search the bad block pattern */
+	u32 Offset;		/**< Offset to search for specified pattern */
+	u32 Length;		/**< Number of bytes to check the pattern */
+	u8 Pattern[2];		/**< Pattern format to search for */
+} XNandPsu_BadBlockPattern;
+
+/**
+ * The XNandPsu_Geometry structure contains the ONFI geometry information.
+ */
+typedef struct {
+	/* Parameter page information */
+	u32 BytesPerPage;	/**< Number of bytes per page */
+	u16 SpareBytesPerPage;	/**< Number of spare bytes per page */
+	u32 PagesPerBlock;	/**< Number of pages per block */
+	u32 BlocksPerLun;	/**< Number of blocks per LUN */
+	u8 NumLuns;		/**< Number of LUN's */
+	u8 RowAddrCycles;	/**< Row address cycles */
+	u8 ColAddrCycles;	/**< Column address cycles */
+	u8 NumBitsPerCell;	/**< Number of bits per cell (Hamming/BCH) */
+	u8 NumBitsECC;		/**< Number of bits ECC correctability */
+	u32 EccCodeWordSize;	/**< ECC codeword size */
+	/* Driver specific information */
+	u32 BlockSize;		/**< Block size */
+	u32 NumTargetPages;	/**< Total number of pages in a Target */
+	u32 NumTargetBlocks;	/**< Total number of blocks in a Target */
+	u64 TargetSize;		/**< Target size in bytes */
+	u8 NumTargets;		/**< Number of targets present */
+	u32 NumPages;		/**< Total number of pages */
+	u32 NumBlocks;		/**< Total number of blocks */
+	u64 DeviceSize;		/**< Total flash size in bytes */
+} XNandPsu_Geometry;
+
+/**
+ * The XNandPsu_Features structure contains the ONFI features information.
+ */
+typedef struct {
+	u32 NvDdr;
+	u32 EzNand;
+	u32 OnDie;
+	u32 ExtPrmPage;
+} XNandPsu_Features;
+
+/**
+ * The XNandPsu_EccMatrix structure contains ECC features information.
+ */
+typedef struct {
+	u16 PageSize;
+	u16 CodeWordSize;
+	u8 NumEccBits;
+	u8 IsBCH;
+	u16 EccAddr;
+	u16 EccSize;
+} XNandPsu_EccMatrix;
+
+/**
+ * The XNandPsu_EccCfg structure contains ECC configuration.
+ */
+typedef struct {
+	u16 EccAddr;
+	u16 EccSize;
+	u16 CodeWordSize;
+	u8 NumEccBits;
+	u8 IsBCH;
+} XNandPsu_EccCfg;
+
+/**
+ * The XNandPsu structure contains the driver instance data. The user is
+ * required to allocate a variable of this type for the NAND controller.
+ * A pointer to a variable of this type is then passed to the driver API
+ * functions.
+ */
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+#endif
+typedef struct {
+	u32 IsReady;		/**< Device is initialized and ready */
+	XNandPsu_Config Config;
+	u32 Ecc_Stat_PerPage_flips;	/**< Ecc Correctable Error Counter for Current Page */
+	u32 Ecc_Stats_total_flips;     /**< Total Ecc Errors Corrected */
+	XNandPsu_DataInterface DataInterface;
+	XNandPsu_TimingMode TimingMode;
+	XNandPsu_SWMode Mode;		/**< Driver operating mode */
+	XNandPsu_DmaMode DmaMode;	/**< MDMA mode enabled/disabled */
+	XNandPsu_EccMode EccMode;	/**< ECC Mode */
+	XNandPsu_EccCfg EccCfg;		/**< ECC configuration */
+	XNandPsu_Geometry Geometry;	/**< Flash geometry */
+	XNandPsu_Features Features;	/**< ONFI features */
+#ifdef __ICCARM__
+	u8 PartialDataBuf[XNANDPSU_MAX_PAGE_SIZE];	/**< Partial read/write buffer */
+#pragma pack(pop)
+#else
+	u8 PartialDataBuf[XNANDPSU_MAX_PAGE_SIZE] __attribute__ ((aligned(64)));
+#endif
+	/* Bad block table definitions */
+	XNandPsu_BbtDesc BbtDesc;	/**< Bad block table descriptor */
+	XNandPsu_BbtDesc BbtMirrorDesc;	/**< Mirror BBT descriptor */
+	XNandPsu_BadBlockPattern BbPattern;	/**< Bad block pattern to
+						  search */
+	u8 Bbt[XNANDPSU_MAX_BLOCKS >> 2];	/**< Bad block table array */
+} XNandPsu;
+
+/******************* Macro Definitions (Inline Functions) *******************/
+
+/*****************************************************************************/
+/**
+ * This macro sets the bitmask in the register.
+ *
+ * @param	InstancePtr is a pointer to the XNandPsu instance of the
+ *		controller.
+ * @param	RegOffset is the register offset.
+ * @param	BitMask is the bitmask.
+ *
+ * @note	C-style signature:
+ *		void XNandPsu_SetBits(XNandPsu *InstancePtr, u32 RegOffset,
+ *							u32 BitMask)
+ *
+ *****************************************************************************/
+#define XNandPsu_SetBits(InstancePtr, RegOffset, BitMask)		\
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,		\
+		(RegOffset),						\
+	((u32)(XNandPsu_ReadReg((InstancePtr)->Config.BaseAddress,	\
+		(RegOffset)) | (BitMask))))
+
+/*****************************************************************************/
+/**
+ * This macro clears the bitmask in the register.
+ *
+ * @param	InstancePtr is a pointer to the XNandPsu instance of the
+ *		controller.
+ * @param	RegOffset is the register offset.
+ * @param	BitMask is the bitmask.
+ *
+ * @note	C-style signature:
+ *		void XNandPsu_ClrBits(XNandPsu *InstancePtr, u32 RegOffset,
+ *							u32 BitMask)
+ *
+ *****************************************************************************/
+#define XNandPsu_ClrBits(InstancePtr, RegOffset, BitMask)		\
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,		\
+		(RegOffset),						\
+	((u32)(XNandPsu_ReadReg((InstancePtr)->Config.BaseAddress,	\
+		(RegOffset)) & ~(BitMask))))
+
+/*****************************************************************************/
+/**
+ * This macro clears and updates the bitmask in the register.
+ *
+ * @param	InstancePtr is a pointer to the XNandPsu instance of the
+ *		controller.
+ * @param	RegOffset is the register offset.
+ * @param	Mask is the bitmask.
+ * @param	Value is the register value to write.
+ *
+ * @note	C-style signature:
+ *		void XNandPsu_ReadModifyWrite(XNandPsu *InstancePtr,
+ *					u32 RegOffset, u32 Mask, u32 Val)
+ *
+ *****************************************************************************/
+#define XNandPsu_ReadModifyWrite(InstancePtr, RegOffset, Mask, Value)	\
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,		\
+		(RegOffset),						\
+	((u32)((u32)(XNandPsu_ReadReg((InstancePtr)->Config.BaseAddress,\
+		(u32)(RegOffset)) & (u32)(~(Mask))) | (u32)(Value))))
+
+/*****************************************************************************/
+/**
+ * This macro enables bitmask in Interrupt Signal Enable register.
+ *
+ * @param	InstancePtr is a pointer to the XNandPsu instance of the
+ *		controller.
+ * @param	Mask is the bitmask.
+ *
+ * @note	C-style signature:
+ *		void XNandPsu_IntrSigEnable(XNandPsu *InstancePtr, u32 Mask)
+ *
+ *****************************************************************************/
+#define XNandPsu_IntrSigEnable(InstancePtr, Mask)			\
+		XNandPsu_SetBits((InstancePtr),				\
+			XNANDPSU_INTR_SIG_EN_OFFSET,			\
+			(Mask))
+
+/*****************************************************************************/
+/**
+ * This macro clears bitmask in Interrupt Signal Enable register.
+ *
+ * @param	InstancePtr is a pointer to the XNandPsu instance of the
+ *		controller.
+ * @param	Mask is the bitmask.
+ *
+ * @note	C-style signature:
+ *		void XNandPsu_IntrSigClear(XNandPsu *InstancePtr, u32 Mask)
+ *
+ *****************************************************************************/
+#define XNandPsu_IntrSigClear(InstancePtr, Mask)			\
+		XNandPsu_ClrBits((InstancePtr),				\
+			XNANDPSU_INTR_SIG_EN_OFFSET,			\
+			(Mask))
+
+/*****************************************************************************/
+/**
+ * This macro enables bitmask in Interrupt Status Enable register.
+ *
+ * @param	InstancePtr is a pointer to the XNandPsu instance of the
+ *		controller.
+ * @param	Mask is the bitmask.
+ *
+ * @note	C-style signature:
+ *		void XNandPsu_IntrStsEnable(XNandPsu *InstancePtr, u32 Mask)
+ *
+ *****************************************************************************/
+#define XNandPsu_IntrStsEnable(InstancePtr, Mask)			\
+		XNandPsu_SetBits((InstancePtr),				\
+			XNANDPSU_INTR_STS_EN_OFFSET,			\
+			(Mask))
+
+/*****************************************************************************/
+/**
+ * This macro checks for the ONFI ID.
+ *
+ * @param	Buff is the buffer holding ONFI ID
+ *
+ * @note	none.
+ *
+ *****************************************************************************/
+#define IS_ONFI(Buff)					\
+	((Buff)[0] == (u8)'O') && ((Buff)[1] == (u8)'N') &&	\
+	((Buff)[2] == (u8)'F') && ((Buff)[3] == (u8)'I')
+
+/************************** Function Prototypes *****************************/
+
+s32 XNandPsu_CfgInitialize(XNandPsu *InstancePtr, XNandPsu_Config *ConfigPtr,
+				u32 EffectiveAddr);
+
+s32 XNandPsu_Erase(XNandPsu *InstancePtr, u64 Offset, u64 Length);
+
+s32 XNandPsu_Write(XNandPsu *InstancePtr, u64 Offset, u64 Length,
+							u8 *SrcBuf);
+
+s32 XNandPsu_Read(XNandPsu *InstancePtr, u64 Offset, u64 Length,
+							u8 *DestBuf);
+
+s32 XNandPsu_EraseBlock(XNandPsu *InstancePtr, u32 Target, u32 Block);
+
+s32 XNandPsu_WriteSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf);
+
+s32 XNandPsu_ReadSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf);
+
+s32 XNandPsu_ChangeTimingMode(XNandPsu *InstancePtr,
+				XNandPsu_DataInterface NewIntf,
+				XNandPsu_TimingMode NewMode);
+
+s32 XNandPsu_GetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
+								u8 *Buf);
+
+s32 XNandPsu_SetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
+								u8 *Buf);
+
+s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr);
+
+s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block);
+
+void XNandPsu_EnableDmaMode(XNandPsu *InstancePtr);
+
+void XNandPsu_DisableDmaMode(XNandPsu *InstancePtr);
+
+void XNandPsu_EnableEccMode(XNandPsu *InstancePtr);
+
+void XNandPsu_DisableEccMode(XNandPsu *InstancePtr);
+
+void XNandPsu_Prepare_Cmd(XNandPsu *InstancePtr, u8 Cmd1, u8 Cmd2, u8 EccState,
+			u8 DmaMode, u8 AddrCycles);
+
+/* XNandPsu_LookupConfig in xnandpsu_sinit.c */
+XNandPsu_Config *XNandPsu_LookupConfig(u16 DevID);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XNANDPSU_H end of protection macro */
+/** @} */
diff --git a/bsps/include/dev/nand/xnandpsu_bbm.h b/bsps/include/dev/nand/xnandpsu_bbm.h
new file mode 100644
index 0000000000..4d4fafffa3
--- /dev/null
+++ b/bsps/include/dev/nand/xnandpsu_bbm.h
@@ -0,0 +1,180 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu_bbm.h
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* This file implements the Bad Block Management(BBM) functionality. This is
+* similar to the Bad Block Management which is a part of the MTD subsystem in
+* Linux.  The factory marked bad blocks are scanned initially and a Bad Block
+* Table(BBT) is created in the memory.  This table is also written to the flash
+* so that upon reboot, the BBT is read back from the flash and loaded into the
+* memory instead of scanning every time. The Bad Block Table(BBT) is written
+* into one of the the last four blocks in the flash memory. The last four
+* blocks are marked as Reserved so that user can't erase/program those blocks.
+*
+* There are two bad block tables, a primary table and a mirror table. The
+* tables are versioned and incrementing version number is used to detect and
+* recover from interrupted updates. Each table is stored in a separate block,
+* beginning in the first page of that block. Only two blocks would be necessary
+* in the absence of bad blocks within the last four; the range of four provides
+* a little slack in case one or two of those blocks is bad. These blocks are
+* marked as reserved and cannot be programmed by the user. A NAND Flash device
+* with 3 or more factory bad blocks in the last 4 cannot be used. The bad block
+* table signature is written into the spare data area of the pages containing
+* bad block table so that upon rebooting the bad block table signature is
+* searched and the bad block table is loaded into RAM. The signature is "Bbt0"
+* for primary Bad Block Table and "1tbB" for Mirror Bad Block Table. The
+* version offset follows the signature offset in the spare data area. The
+* version number increments on every update to the bad block table and the
+* version wraps at 0xff.
+*
+* Each block in the Bad Block Table(BBT) is represented by 2 bits.
+* The two bits are encoded as follows in RAM BBT.
+* 0'b00 -> Good Block
+* 0'b01 -> Block is bad due to wear
+* 0'b10 -> Reserved block
+* 0'b11 -> Factory marked bad block
+*
+* While writing to the flash the two bits are encoded as follows.
+* 0'b00 -> Factory marked bad block
+* 0'b01 -> Reserved block
+* 0'b10 -> Block is bad due to wear
+* 0'b11 -> Good Block
+*
+* The user can check for the validity of the block using the API
+* XNandPsu_IsBlockBad and take the action based on the return value. Also user
+* can update the bad block table using XNandPsu_MarkBlockBad API.
+*
+* @note		None
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date        Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* 2.0   sb     01/12/2015  Added support for writing BBT signature and version
+*			   in page section by enabling XNANDPSU_BBT_NO_OOB.
+*			   Modified Bbt Signature and Version Offset value for
+*			   Oob and No-Oob region.
+* </pre>
+*
+******************************************************************************/
+#ifndef XNANDPSU_BBM_H		/* prevent circular inclusions */
+#define XNANDPSU_BBM_H		/* by using protection macros */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************** Include Files *********************************/
+#include "xnandpsu.h"
+
+/************************** Constant Definitions *****************************/
+/* Block definitions for RAM based Bad Block Table (BBT) */
+#define XNANDPSU_BLOCK_GOOD			0x0U	/**< Block is good */
+#define XNANDPSU_BLOCK_BAD			0x1U	/**< Block is bad */
+#define XNANDPSU_BLOCK_RESERVED			0x2U	/**< Reserved block */
+#define XNANDPSU_BLOCK_FACTORY_BAD		0x3U	/**< Factory marked bad
+							  block */
+/* Block definitions for FLASH based Bad Block Table (BBT) */
+#define XNANDPSU_FLASH_BLOCK_GOOD		0x3U	/**< Block is good */
+#define XNANDPSU_FLASH_BLOCK_BAD		0x2U	/**< Block is bad */
+#define XNANDPSU_FLASH_BLOCK_RESERVED		0x1U	/**< Reserved block */
+#define XNANDPSU_FLASH_BLOCK_FAC_BAD	0x0U	/**< Factory marked bad
+							  block */
+
+#define XNANDPSU_BBT_SCAN_2ND_PAGE		0x00000001U	/**< Scan the
+								  second page
+								  for bad block
+								  information
+								  */
+#define XNANDPSU_BBT_DESC_PAGE_OFFSET		0U	/**< Page offset of Bad
+							  Block Table Desc */
+#define XNANDPSU_BBT_DESC_SIG_OFFSET		8U	/**< Bad Block Table
+							  signature offset */
+#define XNANDPSU_BBT_DESC_VER_OFFSET		12U	/**< Bad block Table
+							  version offset */
+#define XNANDPSU_NO_OOB_BBT_DESC_SIG_OFFSET	0U	/**< Bad Block Table
+							  signature offset in
+							  page memory */
+#define XNANDPSU_NO_OOB_BBT_DESC_VER_OFFSET	4U	/**< Bad block Table
+							  version offset in
+							  page memory */
+#define XNANDPSU_BBT_DESC_SIG_LEN		4U	/**< Bad block Table
+							  signature length */
+#define XNANDPSU_BBT_DESC_MAX_BLOCKS		64U	/**< Bad block Table
+							  max blocks */
+
+#define XNANDPSU_BBT_BLOCK_SHIFT		2U	/**< Block shift value
+							  for a block in BBT */
+#define XNANDPSU_BBT_ENTRY_NUM_BLOCKS		4U	/**< Num of blocks in
+							  one BBT entry */
+#define XNANDPSU_BB_PTRN_OFF_SML_PAGE	5U	/**< Bad block pattern
+							  offset in a page */
+#define XNANDPSU_BB_PTRN_LEN_SML_PAGE	1U	/**< Bad block pattern
+							  length */
+#define XNANDPSU_BB_PTRN_OFF_LARGE_PAGE	0U	/**< Bad block pattern
+							  offset in a large
+							  page */
+#define XNANDPSU_BB_PTRN_LEN_LARGE_PAGE	2U	/**< Bad block pattern
+							  length */
+#define XNANDPSU_BB_PATTERN			0xFFU	/**< Bad block pattern
+							  to search in a page
+							  */
+#define XNANDPSU_BLOCK_TYPE_MASK		0x03U	/**< Block type mask */
+#define XNANDPSU_BLOCK_SHIFT_MASK		0x06U	/**< Block shift mask
+							  for a Bad Block Table
+							  entry byte */
+
+#define XNANDPSU_ONDIE_SIG_OFFSET		0x4U
+#define XNANDPSU_ONDIE_VER_OFFSET		0x14U
+
+#define XNANDPSU_BBT_VERSION_LENGTH	1U
+#define XNANDPSU_BBT_SIG_LENGTH		4U
+
+#define XNANDPSU_BBT_BUF_LENGTH		((XNANDPSU_MAX_BLOCKS >> 		\
+					 XNANDPSU_BBT_BLOCK_SHIFT) +	\
+					(XNANDPSU_BBT_DESC_SIG_OFFSET +	\
+					 XNANDPSU_BBT_SIG_LENGTH +	\
+					 XNANDPSU_BBT_VERSION_LENGTH))
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/****************************************************************************/
+/**
+*
+* This macro returns the Block shift value corresponding to a Block.
+*
+* @param        Block is the block number.
+*
+* @return       Block shift value
+*
+* @note         None.
+*
+*****************************************************************************/
+#define XNandPsu_BbtBlockShift(Block) \
+			(u8)(((Block) * 2U) & XNANDPSU_BLOCK_SHIFT_MASK)
+
+/************************** Variable Definitions *****************************/
+
+/************************** Function Prototypes ******************************/
+
+void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr);
+
+s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of protection macro */
+/** @} */
diff --git a/bsps/include/dev/nand/xnandpsu_hw.h b/bsps/include/dev/nand/xnandpsu_hw.h
new file mode 100644
index 0000000000..47e6c8fddc
--- /dev/null
+++ b/bsps/include/dev/nand/xnandpsu_hw.h
@@ -0,0 +1,483 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu_hw.h
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* This file contains identifiers and low-level macros/functions for the Arasan
+* NAND flash controller driver.
+*
+* See xnandpsu.h for more information.
+*
+* @note		None
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date        Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First Release
+* 2.0   sb     11/04/2014  Changed XNANDPSU_ECC_SLC_MLC_MASK to
+*			   XNANDPSU_ECC_HAMMING_BCH_MASK.
+* 1.7	akm    09/03/20    Updated the Makefile to support parallel make
+* 			   execution.
+* </pre>
+*
+******************************************************************************/
+
+#ifndef XNANDPSU_HW_H		/* prevent circular inclusions */
+#define XNANDPSU_HW_H		/* by using protection macros */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************** Include Files *********************************/
+#include "xil_io.h"
+
+/************************** Constant Definitions *****************************/
+
+/************************** Register Offset Definitions **********************/
+
+#define XNANDPSU_PKT_OFFSET		0x00U	/**< Packet Register */
+#define XNANDPSU_MEM_ADDR1_OFFSET	0x04U	/**< Memory Address
+						  Register 1 */
+#define XNANDPSU_MEM_ADDR2_OFFSET	0x08U	/**< Memory Address
+						  Register 2 */
+#define XNANDPSU_CMD_OFFSET		0x0CU	/**< Command Register */
+#define XNANDPSU_PROG_OFFSET		0x10U	/**< Program Register */
+#define XNANDPSU_INTR_STS_EN_OFFSET	0x14U	/**< Interrupt Status
+						     Enable Register */
+#define XNANDPSU_INTR_SIG_EN_OFFSET	0x18U	/**< Interrupt Signal
+						     Enable Register */
+#define XNANDPSU_INTR_STS_OFFSET	0x1CU	/**< Interrupt Status
+						  Register */
+#define XNANDPSU_READY_BUSY_OFFSET	0x20U	/**< Ready/Busy status
+						  Register */
+#define XNANDPSU_FLASH_STS_OFFSET	0x28U	/**< Flash Status Register */
+#define XNANDPSU_TIMING_OFFSET		0x2CU	/**< Timing Register */
+#define XNANDPSU_BUF_DATA_PORT_OFFSET	0x30U	/**< Buffer Data Port
+						  Register */
+#define XNANDPSU_ECC_OFFSET		0x34U	/**< ECC Register */
+#define XNANDPSU_ECC_ERR_CNT_OFFSET	0x38U	/**< ECC Error Count
+						  Register */
+#define XNANDPSU_ECC_SPR_CMD_OFFSET	0x3CU	/**< ECC Spare Command
+						     Register */
+#define XNANDPSU_ECC_CNT_1BIT_OFFSET	0x40U	/**< Error Count 1bit
+						  Register */
+#define XNANDPSU_ECC_CNT_2BIT_OFFSET	0x44U	/**< Error Count 2bit
+						  Register */
+#define XNANDPSU_ECC_CNT_3BIT_OFFSET	0x48U	/**< Error Count 3bit
+						  Register */
+#define XNANDPSU_ECC_CNT_4BIT_OFFSET	0x4CU	/**< Error Count 4bit
+						  Register */
+#define XNANDPSU_CPU_REL_OFFSET		0x58U	/**< CPU Release Register */
+#define XNANDPSU_ECC_CNT_5BIT_OFFSET	0x5CU	/**< Error Count 5bit
+						  Register */
+#define XNANDPSU_ECC_CNT_6BIT_OFFSET	0x60U	/**< Error Count 6bit
+						  Register */
+#define XNANDPSU_ECC_CNT_7BIT_OFFSET	0x64U	/**< Error Count 7bit
+						  Register */
+#define XNANDPSU_ECC_CNT_8BIT_OFFSET	0x68U	/**< Error Count 8bit
+						  Register */
+#define XNANDPSU_DATA_INTF_OFFSET	0x6CU	/**< Data Interface Register */
+#define XNANDPSU_DMA_SYS_ADDR0_OFFSET	0x50U	/**< DMA System Address 0
+						  Register */
+#define XNANDPSU_DMA_SYS_ADDR1_OFFSET	0x24U	/**< DMA System Address 1
+						  Register */
+#define XNANDPSU_DMA_BUF_BND_OFFSET	0x54U	/**< DMA Buffer Boundary
+						  Register */
+#define XNANDPSU_SLV_DMA_CONF_OFFSET	0x80U	/**< Slave DMA Configuration
+						  Register */
+
+/** @name Packet Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_PKT_PKT_SIZE_MASK		0x000007FFU /**< Packet Size */
+#define XNANDPSU_PKT_PKT_CNT_MASK		0x00FFF000U /**< Packet Count*/
+#define XNANDPSU_PKT_PKT_CNT_SHIFT		12U /**< Packet Count Shift */
+/* @} */
+
+/** @name Memory Address Register 1 bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_MEM_ADDR1_COL_ADDR_MASK	0x0000FFFFU /**< Column Address
+							     Mask */
+#define XNANDPSU_MEM_ADDR1_PG_ADDR_MASK		0xFFFF0000U /**< Page, Block
+							     Address Mask */
+#define XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT	16U /**< Page Shift */
+/* @} */
+
+/** @name Memory Address Register 2 bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK	0x000000FFU /**< Memory Address
+								*/
+#define XNANDPSU_MEM_ADDR2_BUS_WIDTH_MASK	0x01000000U /**< Bus Width */
+#define XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_MASK	0x0E000000U /**< BCH Mode
+							     Value */
+#define XNANDPSU_MEM_ADDR2_MODE_MASK		0x30000000U /**< Flash
+							     Connection Mode */
+#define XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK	0xC0000000U /**< Chip Select */
+#define XNANDPSU_MEM_ADDR2_CHIP_SEL_SHIFT	30U	/**< Chip select
+							shift */
+#define XNANDPSU_MEM_ADDR2_BUS_WIDTH_SHIFT	24U	/**< Bus width shift */
+#define XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_SHIFT	25U
+/* @} */
+
+/** @name Command Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_CMD_CMD1_MASK			0x000000FFU /**< 1st Cycle
+							     Command */
+#define XNANDPSU_CMD_CMD2_MASK			0x0000FF00U /**< 2nd Cycle
+							     Command */
+#define XNANDPSU_CMD_PG_SIZE_MASK		0x03800000U /**< Page Size */
+#define XNANDPSU_CMD_DMA_EN_MASK		0x0C000000U /**< DMA Enable
+							     Mode */
+#define XNANDPSU_CMD_ADDR_CYCLES_MASK		0x70000000U /**< Number of
+							     Address Cycles */
+#define XNANDPSU_CMD_ECC_ON_MASK		0x80000000U /**< ECC ON/OFF */
+#define XNANDPSU_CMD_CMD2_SHIFT			8U /**< 2nd Cycle Command
+						    Shift */
+#define XNANDPSU_CMD_PG_SIZE_SHIFT		23U /**< Page Size Shift */
+#define XNANDPSU_CMD_DMA_EN_SHIFT		26U /**< DMA Enable Shift */
+#define XNANDPSU_CMD_ADDR_CYCLES_SHIFT		28U /**< Number of Address
+						     Cycles Shift */
+#define XNANDPSU_CMD_ECC_ON_SHIFT		31U /**< ECC ON/OFF */
+/* @} */
+
+/** @name Program Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_PROG_RD_MASK			0x00000001U /**< Read */
+#define XNANDPSU_PROG_MUL_DIE_MASK		0x00000002U /**< Multi Die */
+#define XNANDPSU_PROG_BLK_ERASE_MASK		0x00000004U /**< Block Erase */
+#define XNANDPSU_PROG_RD_STS_MASK		0x00000008U /**< Read Status */
+#define XNANDPSU_PROG_PG_PROG_MASK		0x00000010U /**< Page Program */
+#define XNANDPSU_PROG_MUL_DIE_RD_MASK		0x00000020U /**< Multi Die Rd */
+#define XNANDPSU_PROG_RD_ID_MASK		0x00000040U /**< Read ID */
+#define XNANDPSU_PROG_RD_PRM_PG_MASK		0x00000080U /**< Read Param
+							     Page */
+#define XNANDPSU_PROG_RST_MASK			0x00000100U /**< Reset */
+#define XNANDPSU_PROG_GET_FEATURES_MASK		0x00000200U /**< Get Features */
+#define XNANDPSU_PROG_SET_FEATURES_MASK		0x00000400U /**< Set Features */
+#define XNANDPSU_PROG_RD_UNQ_ID_MASK		0x00000800U /**< Read Unique
+							     ID */
+#define XNANDPSU_PROG_RD_STS_ENH_MASK		0x00001000U /**< Read Status
+							     Enhanced */
+#define XNANDPSU_PROG_RD_INTRLVD_MASK		0x00002000U /**< Read
+							     Interleaved */
+#define XNANDPSU_PROG_CHNG_RD_COL_ENH_MASK	0x00004000U /**< Change Read
+								Column
+								Enhanced */
+#define XNANDPSU_PROG_COPY_BACK_INTRLVD_MASK	0x00008000U /**< Copy Back
+								Interleaved */
+#define XNANDPSU_PROG_RD_CACHE_START_MASK	0x00010000U /**< Read Cache
+							     Start */
+#define XNANDPSU_PROG_RD_CACHE_SEQ_MASK		0x00020000U /**< Read Cache
+							     Sequential */
+#define XNANDPSU_PROG_RD_CACHE_RAND_MASK	0x00040000U /**< Read Cache
+								Random */
+#define XNANDPSU_PROG_RD_CACHE_END_MASK		0x00080000U /**< Read Cache
+							     End */
+#define XNANDPSU_PROG_SMALL_DATA_MOVE_MASK	0x00100000U /**< Small Data
+							     Move */
+#define XNANDPSU_PROG_CHNG_ROW_ADDR_MASK	0x00200000U /**< Change Row
+								Address */
+#define XNANDPSU_PROG_CHNG_ROW_ADDR_END_MASK	0x00400000U /**< Change Row
+								Address End */
+#define XNANDPSU_PROG_RST_LUN_MASK		0x00800000U /**< Reset LUN */
+#define XNANDPSU_PROG_PGM_PG_CLR_MASK		0x01000000U /**< Enhanced
+							     Program Page
+							     Register Clear */
+#define XNANDPSU_PROG_VOL_SEL_MASK		0x02000000U /**< Volume Select */
+#define XNANDPSU_PROG_ODT_CONF_MASK		0x04000000U /**< ODT Configure */
+/* @} */
+
+/** @name Interrupt Status Enable Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK	0x00000001U /**< Buffer
+								     Write Ready
+								     Status
+								     Enable */
+#define XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK	0x00000002U /**< Buffer
+								     Read Ready
+								     Status
+								     Enable */
+#define XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK	0x00000004U /**< Transfer
+								     Complete
+								     Status
+								     Enable */
+#define XNANDPSU_INTR_STS_EN_MUL_BIT_ERR_STS_EN_MASK	0x00000008U /**< Multi
+								     Bit Error
+								     Status
+								     Enable */
+#define XNANDPSU_INTR_STS_EN_ERR_INTR_STS_EN_MASK	0x00000010U /**< Single
+								     Bit Error
+								     Status
+								     Enable,
+								     BCH Detect
+								     Error
+								     Status
+								     Enable */
+#define XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK	0x00000040U /**< DMA
+								     Status
+								     Enable */
+#define XNANDPSU_INTR_STS_EN_ERR_AHB_STS_EN_MASK	0x00000080U /**< Error
+								     AHB Status
+								     Enable */
+/* @} */
+
+/** @name Interrupt Signal Enable Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_INTR_SIG_EN_BUFF_WR_RDY_STS_EN_MASK	0x00000001U /**< Buffer
+								     Write Ready
+								     Signal
+								     Enable */
+#define XNANDPSU_INTR_SIG_EN_BUFF_RD_RDY_STS_EN_MASK	0x00000002U /**< Buffer
+								     Read Ready
+								     Signal
+								     Enable */
+#define XNANDPSU_INTR_SIG_EN_TRANS_COMP_STS_EN_MASK	0x00000004U /**< Transfer
+								     Complete
+								     Signal
+								     Enable */
+#define XNANDPSU_INTR_SIG_EN_MUL_BIT_ERR_STS_EN_MASK	0x00000008U /**< Multi
+								     Bit Error
+								     Signal
+								     Enable */
+#define XNANDPSU_INTR_SIG_EN_ERR_INTR_STS_EN_MASK	0x00000010U /**< Single
+								     Bit Error
+								     Signal
+								     Enable,
+								     BCH Detect
+								     Error
+								     Signal
+								     Enable */
+#define XNANDPSU_INTR_SIG_EN_DMA_INT_STS_EN_MASK	0x00000040U /**< DMA
+								     Signal
+								     Enable */
+#define XNANDPSU_INTR_SIG_EN_ERR_AHB_STS_EN_MASK	0x00000080U /**< Error
+								     AHB Signal
+								     Enable */
+/* @} */
+
+/** @name Interrupt Status Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK	0x00000001U /**< Buffer
+								     Write
+								     Ready */
+#define XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK	0x00000002U /**< Buffer
+								     Read
+								     Ready */
+#define XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK	0x00000004U /**< Transfer
+								     Complete */
+#define XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK	0x00000008U /**< Multi
+								    Bit Error */
+#define XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK		0x00000010U /**< Single
+								     Bit Error,
+								     BCH Detect
+								     Error */
+#define XNANDPSU_INTR_STS_DMA_INT_STS_EN_MASK		0x00000040U /**< DMA
+								     Interrupt
+								     */
+#define XNANDPSU_INTR_STS_ERR_AHB_STS_EN_MASK		0x00000080U /**< Error
+								     AHB */
+/* @} */
+
+/** @name Interrupt bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_INTR_BUFF_WR_RDY_STS_EN_MASK	0x00000001U /**< Buffer Write
+								Ready Status
+								Enable */
+#define XNANDPSU_INTR_BUFF_RD_RDY_STS_EN_MASK	0x00000002U /**< Buffer Read
+								Ready Status
+								Enable */
+#define XNANDPSU_INTR_TRANS_COMP_STS_EN_MASK	0x00000004U /**< Transfer
+								Complete Status
+								Enable */
+#define XNANDPSU_INTR_MUL_BIT_ERR_STS_EN_MASK	0x00000008U /**< Multi Bit Error
+								Status Enable */
+#define XNANDPSU_INTR_ERR_INTR_STS_EN_MASK	0x00000010U /**< Single Bit Error
+								Status Enable,
+								BCH Detect Error
+								Status Enable */
+#define XNANDPSU_INTR_DMA_INT_STS_EN_MASK	0x00000040U /**< DMA Status
+								Enable */
+#define XNANDPSU_INTR_ERR_AHB_STS_EN_MASK	0x00000080U /**< Error AHB Status
+								Enable */
+/* @} */
+
+/** @name ID2 Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_ID2_DEVICE_ID2_MASK		0x000000FFU /**< MSB Device ID */
+/* @} */
+
+/** @name Flash Status Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_FLASH_STS_FLASH_STS_MASK	0x0000FFFFU /**< Flash Status
+							     Value */
+/* @} */
+
+/** @name Timing Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_TIMING_TCCS_TIME_MASK		0x00000003U /**< Change column
+							     setup time */
+#define XNANDPSU_TIMING_SLOW_FAST_TCAD_MASK	0x00000004U /**< Slow/Fast device
+							     */
+#define XNANDPSU_TIMING_DQS_BUFF_SEL_MASK	0x00000078U /**< Write/Read data
+							     transaction value
+							     */
+#define XNANDPSU_TIMING_TADL_TIME_MASK		0x00007F80U /**< Address latch
+							     enable to Data
+							     loading time */
+/* @} */
+
+/** @name ECC Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_ECC_ADDR_MASK			0x0000FFFFU /**< ECC address */
+#define XNANDPSU_ECC_SIZE_MASK			0x01FF0000U /**< ECC size */
+#define XNANDPSU_ECC_HAMMING_BCH_MASK		0x02000000U /**< Hamming/BCH
+							     support */
+/* @} */
+
+/** @name ECC Error Count Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_ECC_ERR_CNT_PKT_BND_ERR_CNT_MASK	0x000000FFU /**< Packet
+								     bound error
+								     count */
+#define XNANDPSU_ECC_ERR_CNT_PG_BND_ERR_CNT_MASK	0x0000FF00U /**< Page
+								     bound error
+								     count */
+/* @} */
+
+/** @name ECC Spare Command Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_ECC_SPR_CMD_SPR_CMD_MASK		0x000000FFU /**< ECC
+								     spare
+								     command */
+#define XNANDPSU_ECC_SPR_CMD_ECC_ADDR_CYCLES_MASK	0x70000000U /**< Number
+								     of ECC/
+								     spare
+								     address
+								     cycles */
+/* @} */
+
+/** @name Data Interface Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_DATA_INTF_SDR_MASK		0x00000007U /**< SDR mode */
+#define XNANDPSU_DATA_INTF_NVDDR_MASK		0x00000038U /**< NVDDR mode */
+#define XNANDPSU_DATA_INTF_NVDDR2_MASK		0x000001C0U /**< NVDDR2 mode */
+#define XNANDPSU_DATA_INTF_DATA_INTF_MASK	0x00000600U /**< Data
+							     Interface */
+#define XNANDPSU_DATA_INTF_NVDDR_SHIFT		3U /**< NVDDR mode shift */
+#define XNANDPSU_DATA_INTF_DATA_INTF_SHIFT	9U /**< Data Interface Shift */
+/* @} */
+
+/** @name DMA Buffer Boundary Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_DMA_BUF_BND_BND_MASK		0x00000007U /**< DMA buffer
+							     boundary */
+#define XNANDPSU_DMA_BUF_BND_4K			0x0U
+#define XNANDPSU_DMA_BUF_BND_8K			0x1U
+#define XNANDPSU_DMA_BUF_BND_16K		0x2U
+#define XNANDPSU_DMA_BUF_BND_32K		0x3U
+#define XNANDPSU_DMA_BUF_BND_64K		0x4U
+#define XNANDPSU_DMA_BUF_BND_128K		0x5U
+#define XNANDPSU_DMA_BUF_BND_256K		0x6U
+#define XNANDPSU_DMA_BUF_BND_512K		0x7U
+/* @} */
+
+/** @name Slave DMA Configuration Register bit definitions and masks
+ *  @{
+ */
+#define XNANDPSU_SLV_DMA_CONF_SDMA_TX_RX_MASK		0x00000001U /**< Slave
+								     DMA
+								     Transfer
+								     Direction
+								     */
+#define XNANDPSU_SLV_DMA_CONF_DMA_TRANS_CNT_MASK	0x001FFFFEU /**< Slave
+								     DMA
+								     Transfer
+								     Count */
+#define XNANDPSU_SLV_DMA_CONF_DMA_BURST_SIZE_MASK	0x00E00000U /**< Slave
+								     DMA
+								     Burst
+								     Size */
+#define XNANDPSU_SLV_DMA_CONF_DMA_TMOUT_CNT_VAL_MASK	0x0F000000U /**< DMA
+								     Timeout
+								     Counter
+								     Value */
+#define XNANDPSU_SLV_DMA_CONF_SDMA_EN_MASK		0x10000000U /**< Slave
+								     DMA
+								     Enable */
+/* @} */
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/****************************************************************************/
+/**
+*
+* This macro reads the given register.
+*
+* @param	BaseAddress is the base address of controller registers.
+* @param	RegOffset is the register offset to be read.
+*
+* @return	The 32-bit value of the register.
+*
+* @note		C-style signature:
+*		u32 XNandPsu_ReadReg(u32 BaseAddress, u32 RegOffset)
+*
+*****************************************************************************/
+#define XNandPsu_ReadReg(BaseAddress, RegOffset)			\
+			Xil_In32((BaseAddress) + (RegOffset))
+
+/****************************************************************************/
+/**
+*
+* This macro writes the given register.
+*
+* @param	BaseAddress is the the base address of controller registers.
+* @param	RegOffset is the register offset to be written.
+* @param	Data is the the 32-bit value to write to the register.
+*
+* @return	None.
+*
+* @note		C-style signature:
+*		void XNandPsu_WriteReg(u32 BaseAddress, u32 RegOffset, u32 Data)
+*
+******************************************************************************/
+#define XNandPsu_WriteReg(BaseAddress, RegOffset, Data)			\
+			Xil_Out32(((BaseAddress) + (RegOffset)), (Data))
+
+/************************** Function Prototypes ******************************/
+
+/************************** Variable Definitions *****************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XNANDPSU_HW_H end of protection macro */
+/** @} */
diff --git a/bsps/include/dev/nand/xnandpsu_onfi.h b/bsps/include/dev/nand/xnandpsu_onfi.h
new file mode 100644
index 0000000000..7523ff48ea
--- /dev/null
+++ b/bsps/include/dev/nand/xnandpsu_onfi.h
@@ -0,0 +1,316 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu_onfi.h
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* This file defines all the ONFI 3.1 specific commands and values.
+*
+* @note		None
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* 1.4	nsk    04/10/2018  Added ICCARM compiler support.
+* </pre>
+*
+******************************************************************************/
+#ifndef XNANDPSU_ONFI_H		/* prevent circular inclusions */
+#define XNANDPSU_ONFI_H		/* by using protection macros */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************** Include Files *********************************/
+#include "xil_types.h"
+
+/************************** Constant Definitions *****************************/
+/* Standard ONFI 3.1 Commands */
+/* ONFI 3.1 Mandatory Commands */
+#define ONFI_CMD_RD1			0x00U	/**< Read (1st cycle) */
+#define ONFI_CMD_RD2			0x30U	/**< Read (2nd cycle) */
+#define ONFI_CMD_CHNG_RD_COL1		0x05U	/**< Change Read Column
+						  (1st cycle) */
+#define ONFI_CMD_CHNG_RD_COL2		0xE0U	/**< Change Read Column
+						  (2nd cycle) */
+#define ONFI_CMD_BLK_ERASE1		0x60U	/**< Block Erase (1st cycle) */
+#define ONFI_CMD_BLK_ERASE2		0xD0U	/**< Block Erase (2nd cycle) */
+#define ONFI_CMD_RD_STS			0x70U	/**< Read Status */
+#define ONFI_CMD_PG_PROG1		0x80U	/**< Page Program(1st cycle) */
+#define ONFI_CMD_PG_PROG2		0x10U	/**< Page Program(2nd cycle) */
+#define ONFI_CMD_CHNG_WR_COL		0x85U	/**< Change Write Column */
+#define ONFI_CMD_RD_ID			0x90U	/**< Read ID */
+#define ONFI_CMD_RD_PRM_PG		0xECU	/**< Read Parameter Page */
+#define ONFI_CMD_RST			0xFFU	/**< Reset */
+/* ONFI 3.1 Optional Commands */
+#define ONFI_CMD_MUL_RD1		0x00U	/**< Multiplane Read
+						  (1st cycle) */
+#define ONFI_CMD_MUL_RD2		0x32U	/**< Multiplane Read
+						  (2nd cycle) */
+#define ONFI_CMD_CPBK_RD1		0x00U	/**< Copyback Read
+						  (1st cycle) */
+#define ONFI_CMD_CPBK_RD2		0x35U	/**< Copyback Read
+						  (2nd cycle) */
+#define ONFI_CMD_CHNG_RD_COL_ENHCD1	0x06U	/**< Change Read Column
+						  Enhanced (1st cycle) */
+#define ONFI_CMD_CHNG_RD_COL_ENHCD2	0xE0U	/**< Change Read Column
+						  Enhanced (2nd cycle) */
+#define ONFI_CMD_RD_CACHE_RND1		0x00U	/**< Read Cache Random
+						  (1st cycle) */
+#define ONFI_CMD_RD_CACHE_RND2		0x31U	/**< Read Cache Random
+						  (2nd cycle) */
+#define ONFI_CMD_RD_CACHE_SEQ		0x31U	/**< Read Cache Sequential */
+#define ONFI_CMD_RD_CACHE_END		0x3FU	/**< Read Cache End */
+#define ONFI_CMD_MUL_BLK_ERASE1		0x60U	/**< Multiplane Block Erase
+						  (1st cycle) */
+#define ONFI_CMD_MUL_BLK_ERASE2		0xD1U	/**< Multiplane Block Erase
+						  (2nd cycle) */
+#define ONFI_CMD_RD_STS_ENHCD		0x78U	/**< Read Status Enhanced */
+#define ONFI_CMD_BLK_ERASE_INTRLVD2	0xD1U	/**< Block Erase Interleaved
+						  (2nd cycle) */
+#define ONFI_CMD_MUL_PG_PROG1		0x80U	/**< Multiplane Page Program
+						  (1st cycle) */
+#define ONFI_CMD_MUL_PG_PROG2		0x11U	/**< Multiplane Page Program
+						  (2nd cycle) */
+#define ONFI_CMD_PG_CACHE_PROG1		0x80U	/**< Page Cache Program
+						  (1st cycle) */
+#define ONFI_CMD_PG_CACHE_PROG2		0x15U	/**< Page Cache Program
+						  (2nd cycle) */
+#define ONFI_CMD_CPBK_PROG1		0x85U	/**< Copyback Program
+						  (1st cycle) */
+#define ONFI_CMD_CPBK_PROG2		0x10U	/**< Copyback Program
+						  (2nd cycle) */
+#define ONFI_CMD_MUL_CPBK_PROG1		0x85U	/**< Multiplane Copyback
+						  Program (1st cycle) */
+#define ONFI_CMD_MUL_CPBK_PROG2		0x10U	/**< Multiplane Copyback
+						  Program (2nd cycle) */
+#define ONFI_CMD_SMALL_DATA_MV1		0x85U	/**< Small Data Move
+						  (1st cycle) */
+#define ONFI_CMD_SMALL_DATA_MV2		0x10U	/**< Small Data Move
+						  (2nd cycle) */
+#define ONFI_CMD_CHNG_ROW_ADDR		0x85U	/**< Change Row Address */
+#define ONFI_CMD_VOL_SEL		0xE1U	/**< Volume Select */
+#define ONFI_CMD_ODT_CONF		0xE2U	/**< ODT Configure */
+#define ONFI_CMD_RD_UNIQID		0xEDU	/**< Read Unique ID */
+#define ONFI_CMD_GET_FEATURES		0xEEU	/**< Get Features */
+#define ONFI_CMD_SET_FEATURES		0xEFU	/**< Set Features */
+#define ONFI_CMD_LUN_GET_FEATURES	0xD4U	/**< LUN Get Features */
+#define ONFI_CMD_LUN_SET_FEATURES	0xD5U	/**< LUN Set Features */
+#define ONFI_CMD_RST_LUN		0xFAU	/**< Reset LUN */
+#define ONFI_CMD_SYN_RST		0xFCU	/**< Synchronous Reset */
+
+/* ONFI Status Register bit offsets */
+#define ONFI_STS_FAIL			0x01U	/**< FAIL */
+#define ONFI_STS_FAILC			0x02U	/**< FAILC */
+#define ONFI_STS_CSP			0x08U	/**< CSP */
+#define ONFI_STS_VSP			0x10U	/**< VSP */
+#define ONFI_STS_ARDY			0x20U	/**< ARDY */
+#define ONFI_STS_RDY			0x40U	/**< RDY */
+#define ONFI_STS_WP			0x80U	/**< WP_n */
+
+/* ONFI constants */
+#define ONFI_CRC_LEN			254U	/**< ONFI CRC Buf Length */
+#define ONFI_PRM_PG_LEN			256U	/**< Parameter Page Length */
+#define ONFI_MND_PRM_PGS		3U	/**< Number of mandatory
+						  parameter pages */
+#define ONFI_SIG_LEN			4U	/**< Signature Length */
+#define ONFI_CMD_INVALID		0x00U	/**< Invalid Command */
+
+#define ONFI_READ_ID_LEN		4U	/**< ONFI ID length */
+#define ONFI_READ_ID_ADDR		0x20U	/**< ONFI Read ID Address */
+#define ONFI_READ_ID_ADDR_CYCLES	1U	/**< ONFI Read ID Address
+						  cycles */
+
+#define ONFI_PRM_PG_ADDR_CYCLES		1U	/**< ONFI Read Parameter page
+						  address cycles */
+
+/**
+ * This enum defines the ONFI 3.1 commands.
+ */
+enum OnfiCommandList {
+	READ=0,				/**< Read */
+	MULTIPLANE_READ,		/**< Multiplane Read */
+	COPYBACK_READ,			/**< Copyback Read */
+	CHANGE_READ_COLUMN,		/**< Change Read Column */
+	CHANGE_READ_COLUMN_ENHANCED,	/**< Change Read Column Enhanced */
+	READ_CACHE_RANDOM,		/**< Read Cache Random */
+	READ_CACHE_SEQUENTIAL,		/**< Read Cache Sequential */
+	READ_CACHE_END,			/**< Read Cache End */
+	BLOCK_ERASE,			/**< Block Erase */
+	MULTIPLANE_BLOCK_ERASE,		/**< Multiplane Block Erase */
+	READ_STATUS,			/**< Read Status */
+	READ_STATUS_ENHANCED,		/**< Read Status Enhanced */
+	PAGE_PROGRAM,			/**< Page Program */
+	MULTIPLANE_PAGE_PROGRAM,	/**< Multiplane Page Program */
+	PAGE_CACHE_PROGRAM,		/**< Page Cache Program */
+	COPYBACK_PROGRAM,		/**< Copyback Program */
+	MULTIPLANE_COPYBACK_PROGRAM,	/**< Multiplance Copyback Program */
+	SMALL_DATA_MOVE,		/**< Small Data Move */
+	CHANGE_WRITE_COLUMN,		/**< Change Write Column */
+	CHANGE_ROW_ADDR,		/**< Change Row Address */
+	READ_ID,			/**< Read ID */
+	VOLUME_SELECT,			/**< Volume Select */
+	ODT_CONFIGURE,			/**< ODT Configure */
+	READ_PARAM_PAGE,		/**< Read Parameter Page */
+	READ_UNIQUE_ID,			/**< Read Unique ID */
+	GET_FEATURES,			/**< Get Features */
+	SET_FEATURES,			/**< Set Features */
+	LUN_GET_FEATURES,		/**< LUN Get Features */
+	LUN_SET_FEATURES,		/**< LUN Set Features */
+	RESET_LUN,			/**< Reset LUN */
+	SYN_RESET,			/**< Synchronous Reset */
+	RESET,				/**< Reset */
+	MAX_CMDS			/**< Dummy Command */
+};
+
+/**************************** Type Definitions *******************************/
+/* Parameter page structure of ONFI 3.1 specification. */
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+#endif
+typedef struct {
+	/* Revision information and features block */
+	u8 Signature[4];		/**< Parameter page signature */
+	u16 Revision;			/**< Revision Number */
+	u16 Features;			/**< Features supported */
+	u16 OptionalCmds;		/**< Optional commands supported */
+	u8 JedecJtgPrmAdvCmd;		/**< ONFI JEDEC JTG primary advanced
+					  command support */
+	u8 Reserved0;			/**< Reserved (11) */
+	u16 ExtParamPageLen;		/**< Extended Parameter Page Length */
+	u8 NumOfParamPages;		/**< Number of Parameter Pages */
+	u8 Reserved1[17];		/**< Reserved (15-31) */
+	/* Manufacturer information block */
+	u8 DeviceManufacturer[12];	/**< Device manufacturer */
+	u8 DeviceModel[20];		/**< Device model */
+	u8 JedecManufacturerId;		/**< JEDEC Manufacturer ID */
+	u8 DateCode[2];			/**< Date code */
+	u8 Reserved2[13];		/**< Reserved (67-79) */
+	/* Memory organization block */
+	u32 BytesPerPage;		/**< Number of data bytes per page */
+	u16 SpareBytesPerPage;		/**< Number of spare bytes per page */
+	u32 BytesPerPartialPage;	/**< Number of data bytes per
+					  partial page */
+	u16 SpareBytesPerPartialPage;	/**< Number of spare bytes per
+					  partial page */
+	u32 PagesPerBlock;		/**< Number of pages per block */
+	u32 BlocksPerLun;		/**< Number of blocks per LUN */
+	u8 NumLuns;			/**< Number of LUN's */
+	u8 AddrCycles;			/**< Number of address cycles */
+	u8 BitsPerCell;			/**< Number of bits per cell */
+	u16 MaxBadBlocksPerLun;		/**< Bad blocks maximum per LUN */
+	u16 BlockEndurance;		/**< Block endurance */
+	u8 GuaranteedValidBlock;	/**< Guaranteed valid blocks at
+					  beginning of target */
+	u16 BlockEnduranceGVB;		/**< Block endurance for guaranteed
+					  valid block */
+	u8 ProgramsPerPage;		/**< Number of programs per page */
+	u8 PartialProgAttr;		/**< Partial programming attributes */
+	u8 EccBits;			/**< Number of bits ECC
+					  correctability */
+	u8 PlaneAddrBits;		/**< Number of plane address bits */
+	u8 PlaneOperationAttr;		/**< Multi-plane operation
+					  attributes */
+	u8 EzNandSupport;		/**< EZ NAND support */
+	u8 Reserved3[12];		/**< Reserved (116 - 127) */
+	/* Electrical parameters block */
+	u8 IOPinCapacitance;		/**< I/O pin capacitance, maximum */
+	u16 SDRTimingMode;		/**< SDR Timing mode support */
+	u16 SDRPagecacheTimingMode;	/**< SDR Program cache timing mode */
+	u16 TProg;			/**< Maximum page program time */
+	u16 TBers;			/**< Maximum block erase time */
+	u16 TR;				/**< Maximum page read time */
+	u16 TCcs;			/**< Maximum change column setup
+					  time */
+	u8 NVDDRTimingMode;		/**< NVDDR timing mode support */
+	u8 NVDDR2TimingMode;		/**< NVDDR2 timing mode support */
+	u8 SynFeatures;			/**< NVDDR/NVDDR2 features */
+	u16 ClkInputPinCap;		/**< CLK input pin capacitance */
+	u16 IOPinCap;			/**< I/O pin capacitance */
+	u16 InputPinCap;		/**< Input pin capacitance typical */
+	u8 InputPinCapMax;		/**< Input pin capacitance maximum */
+	u8 DrvStrength;			/**< Driver strength support */
+	u16 TMr;			/**< Maximum multi-plane read time */
+	u16 TAdl;			/**< Program page register clear
+					  enhancement value */
+	u16 TEr;			/**< Typical page read time for
+					  EZ NAND */
+	u8 NVDDR2Features;		/**< NVDDR2 Features */
+	u8 NVDDR2WarmupCycles;		/**< NVDDR2 Warmup Cycles */
+	u8 Reserved4[4];		/**< Reserved (160 - 163) */
+	/* Vendor block */
+	u16 VendorRevisionNum;		/**< Vendor specific revision number */
+	u8 VendorSpecific[88];		/**< Vendor specific */
+	u16 Crc;			/**< Integrity CRC */
+#ifdef __ICCARM__
+} OnfiParamPage;
+#pragma pack(pop)
+#else
+}__attribute__((packed))OnfiParamPage;
+#endif
+
+/* ONFI extended parameter page structure. */
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+#endif
+typedef struct {
+	u16 Crc;
+	u8 Sig[4];
+	u8 Reserved1[10];
+	u8 Section0Type;
+	u8 Section0Len;
+	u8 Section1Type;
+	u8 Section1Len;
+	u8 ResSection[12];
+	u8 SectionData[256];
+#ifdef __ICCARM__
+} OnfiExtPrmPage;
+#pragma pack(pop)
+#else
+}__attribute__((packed))OnfiExtPrmPage;
+#endif
+
+/* Driver extended parameter page information. */
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+#endif
+typedef struct {
+	u8 NumEccBits;
+	u8 CodeWordSize;
+	u16 MaxBadBlocks;
+	u16 BlockEndurance;
+	u16 Reserved;
+#ifdef __ICCARM__
+} OnfiExtEccBlock;
+#pragma pack(pop)
+#else
+}__attribute__((packed))OnfiExtEccBlock;
+#endif
+
+typedef struct {
+	u8 Command1;			/**< Command Cycle 1 */
+	u8 Command2;			/**< Command Cycle 2 */
+} OnfiCmdFormat;
+
+extern const OnfiCmdFormat OnfiCmd[MAX_CMDS];
+
+/************************** Function Prototypes ******************************/
+
+u32 XNandPsu_OnfiParamPageCrc(u8 *ParamBuf, u32 StartOff, u32 Length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XNANDPSU_ONFI_H end of protection macro */
+/** @} */
diff --git a/bsps/shared/dev/nand/VERSION b/bsps/shared/dev/nand/VERSION
new file mode 100644
index 0000000000..c0afe6e031
--- /dev/null
+++ b/bsps/shared/dev/nand/VERSION
@@ -0,0 +1,20 @@
+The information in this file describes the source of files in
+bsps/shared/dev/nand/ and bsps/include/dev/nand/.
+
+Import from:
+
+https://github.com/Xilinx/embeddedsw.git
+
+commit 8a89579489c88ea5acd23d7d439ac928659c26cf
+Author:     msreeram <manikanta.sreeram at xilinx.com>
+AuthorDate: Wed Apr 6 23:24:38 2022 -0600
+Commit:     Siva Addepalli <sivaprasad.addepalli at xilinx.com>
+CommitDate: Fri Apr 8 16:47:15 2022 +0530
+
+    update license file for EmbeddedSW 2022.1 release
+
+    Update license file for EmbeddedSW 2022.1 release
+
+    Signed-off-by: Manikanta Sreeram <msreeram at xilinx.com>
+
+    Acked-by : Meena Paleti <meena.paleti at xilinx.com>
diff --git a/bsps/shared/dev/nand/xnandpsu.c b/bsps/shared/dev/nand/xnandpsu.c
new file mode 100644
index 0000000000..a2e2235906
--- /dev/null
+++ b/bsps/shared/dev/nand/xnandpsu.c
@@ -0,0 +1,2922 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu.c
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* This file contains the implementation of the interface functions for
+* XNandPsu driver. Refer to the header file xnandpsu.h for more detailed
+* information.
+*
+* This module supports for NAND flash memory devices that conform to the
+* "Open NAND Flash Interface" (ONFI) 3.0 Specification. This modules
+* implements basic flash operations like read, write and erase.
+*
+* @note		Driver has been renamed to nandpsu after change in
+*		naming convention.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* 2.0   sb     01/12/2015  Removed Null checks for Buffer passed
+*			   as parameter to Read API's
+*			   - XNandPsu_Read()
+*			   - XNandPsu_ReadPage
+*			   Modified
+*			   - XNandPsu_SetFeature()
+*			   - XNandPsu_GetFeature()
+*			   and made them public.
+*			   Removed Failure Return for BCF Error check in
+*			   XNandPsu_ReadPage() and added BCH_Error counter
+*			   in the instance pointer structure.
+* 			   Added XNandPsu_Prepare_Cmd API
+*			   Replaced
+*			   - XNandPsu_IntrStsEnable
+*			   - XNandPsu_IntrStsClear
+*			   - XNandPsu_IntrClear
+*			   - XNandPsu_SetProgramReg
+*			   with XNandPsu_WriteReg call
+*			   Modified xnandpsu.c file API's with above changes.
+*  			   Corrected the program command for Set Feature API.
+*			   Modified
+*			   - XNandPsu_OnfiReadStatus
+*			   - XNandPsu_GetFeature
+*			   - XNandPsu_SetFeature
+*			   to add support for DDR mode.
+*			   Changed Convention for SLC/MLC
+*			   SLC --> HAMMING
+*			   MLC --> BCH
+*			   SlcMlc --> IsBCH
+*			   Removed extra DMA mode initialization from
+*			   the XNandPsu_CfgInitialize API.
+*			   Modified
+*			   - XNandPsu_SetEccAddrSize
+*			   ECC address now is calculated based upon the
+*			   size of spare area
+*			   Modified Block Erase API, removed clearing of
+*			   packet register before erase.
+*			   Clearing Data Interface Register before
+*			   XNandPsu_OnfiReset call.
+*			   Modified XNandPsu_ChangeTimingMode API supporting
+*			   SDR and NVDDR interface for timing modes 0 to 5.
+*			   Modified Bbt Signature and Version Offset value for
+*			   Oob and No-Oob region.
+* 1.0   kpc    17/6/2015   Added timer based timeout intsead of sw counter.
+* 1.1   mi     09/16/16 Removed compilation warnings with extra compiler flags.
+* 1.1	nsk    11/07/16    Change memcpy to Xil_MemCpy to handle word aligned
+*	                   data access.
+* 1.2	nsk    01/19/17    Fix for the failure of reading nand first redundant
+* 	                   parameter page. CR#966603
+* 1.3	nsk    08/14/17    Added CCI support
+* 1.4	nsk    04/10/18    Added ICCARM compiler support. CR#997552.
+* 1.5   mus    11/05/18 Support 64 bit DMA addresses for Microblaze-X platform.
+* 1.5   mus    11/05/18 Updated XNandPsu_ChangeClockFreq to fix compilation
+*                       warnings.
+* 1.6	sd     06/02/20    Added Clock support
+* 1.6	sd     20/03/20    Added compilation flag
+* 1.8   sg     03/18/21	   Added validation check for parameter page.
+* 1.9   akm    07/15/21    Initialize NandInstPtr with Data Interface & Timing mode info.
+* 1.10  akm    10/20/21    Fix gcc warnings.
+* 1.10  akm    12/21/21    Validate input parameters before use.
+* 1.10  akm    01/05/22    Remove assert checks form static and internal APIs.
+*
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+#include "xnandpsu.h"
+#include "xnandpsu_bbm.h"
+#include "sleep.h"
+#include "xil_mem.h"
+/************************** Constant Definitions *****************************/
+
+static const XNandPsu_EccMatrix EccMatrix[] = {
+	/* 512 byte page */
+	{XNANDPSU_PAGE_SIZE_512, 9U, 1U, XNANDPSU_HAMMING, 0x20DU, 0x3U},
+	{XNANDPSU_PAGE_SIZE_512, 9U, 4U, XNANDPSU_BCH, 0x209U, 0x7U},
+	{XNANDPSU_PAGE_SIZE_512, 9U, 8U, XNANDPSU_BCH, 0x203U, 0xDU},
+	/* 2K byte page */
+	{XNANDPSU_PAGE_SIZE_2K, 9U, 1U, XNANDPSU_HAMMING, 0x834U, 0xCU},
+	{XNANDPSU_PAGE_SIZE_2K, 9U, 4U, XNANDPSU_BCH, 0x826U, 0x1AU},
+	{XNANDPSU_PAGE_SIZE_2K, 9U, 8U, XNANDPSU_BCH, 0x80cU, 0x34U},
+	{XNANDPSU_PAGE_SIZE_2K, 9U, 12U, XNANDPSU_BCH, 0x822U, 0x4EU},
+	{XNANDPSU_PAGE_SIZE_2K, 10U, 24U, XNANDPSU_BCH, 0x81cU, 0x54U},
+	/* 4K byte page */
+	{XNANDPSU_PAGE_SIZE_4K, 9U, 1U, XNANDPSU_HAMMING, 0x1068U, 0x18U},
+	{XNANDPSU_PAGE_SIZE_4K, 9U, 4U, XNANDPSU_BCH, 0x104cU, 0x34U},
+	{XNANDPSU_PAGE_SIZE_4K, 9U, 8U, XNANDPSU_BCH, 0x1018U, 0x68U},
+	{XNANDPSU_PAGE_SIZE_4K, 9U, 12U, XNANDPSU_BCH, 0x1044U, 0x9CU},
+	{XNANDPSU_PAGE_SIZE_4K, 10U, 24U, XNANDPSU_BCH, 0x1038U, 0xA8U},
+	/* 8K byte page */
+	{XNANDPSU_PAGE_SIZE_8K, 9U, 1U, XNANDPSU_HAMMING, 0x20d0U, 0x30U},
+	{XNANDPSU_PAGE_SIZE_8K, 9U, 4U, XNANDPSU_BCH, 0x2098U, 0x68U},
+	{XNANDPSU_PAGE_SIZE_8K, 9U, 8U, XNANDPSU_BCH, 0x2030U, 0xD0U},
+	{XNANDPSU_PAGE_SIZE_8K, 9U, 12U, XNANDPSU_BCH, 0x2088U, 0x138U},
+	{XNANDPSU_PAGE_SIZE_8K, 10U, 24U, XNANDPSU_BCH, 0x2070U, 0x150U},
+	/* 16K byte page */
+	{XNANDPSU_PAGE_SIZE_16K, 9U, 1U, XNANDPSU_HAMMING, 0x4460U, 0x60U},
+	{XNANDPSU_PAGE_SIZE_16K, 9U, 4U, XNANDPSU_BCH, 0x43f0U, 0xD0U},
+	{XNANDPSU_PAGE_SIZE_16K, 9U, 8U, XNANDPSU_BCH, 0x4320U, 0x1A0U},
+	{XNANDPSU_PAGE_SIZE_16K, 9U, 12U, XNANDPSU_BCH, 0x4250U, 0x270U},
+	{XNANDPSU_PAGE_SIZE_16K, 10U, 24U, XNANDPSU_BCH, 0x4220U, 0x2A0U}
+};
+
+/**************************** Type Definitions *******************************/
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+
+static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr);
+
+static s32 XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param);
+
+static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param);
+
+static void XNandPsu_InitDataInterface(XNandPsu *InstancePtr, OnfiParamPage *Param);
+
+static void XNandPsu_InitTimingMode(XNandPsu *InstancePtr, OnfiParamPage *Param);
+
+static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset,
+					u32 Mask, u32 Timeout);
+
+static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize,
+						u32 PktCount);
+
+static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col);
+
+static void XNandPsu_SetPageSize(XNandPsu *InstancePtr);
+
+static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target);
+
+static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target);
+
+static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target,
+							u16 *OnfiStatus);
+
+static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr,
+							u32 IdLen, u8 *Buf);
+
+static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target,
+						u8 *Buf);
+
+static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
+							u32 Col, u8 *Buf);
+
+static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
+							u32 Col, u8 *Buf);
+
+static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr, OnfiParamPage *Param);
+
+static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr);
+
+static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target,
+					u32 Col, u32 PktSize, u32 PktCount,
+					u8 *Buf);
+
+static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target,
+					u32 Col, u32 PktSize, u32 PktCount,
+					u8 *Buf);
+
+static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm);
+
+static s32 XNandPsu_Data_ReadWrite(XNandPsu *InstancePtr, u8* Buf, u32 PktCount,
+				u32 PktSize, u32 Operation, u8 DmaMode);
+
+static s32 XNandPsu_WaitFor_Transfer_Complete(XNandPsu *InstancePtr);
+
+static s32 XNandPsu_Device_Ready(XNandPsu *InstancePtr, u32 Target);
+
+static void XNandPsu_Fifo_Read(XNandPsu *InstancePtr, u8* Buf, u32 Size);
+
+static void XNandPsu_Fifo_Write(XNandPsu *InstancePtr, u8* Buf, u32 Size);
+
+static void XNandPsu_Update_DmaAddr(XNandPsu *InstancePtr, u8* Buf);
+/*****************************************************************************/
+/**
+*
+* This function initializes a specific XNandPsu instance. This function must
+* be called prior to using the NAND flash device to read or write any data.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	ConfigPtr points to XNandPsu device configuration structure.
+* @param	EffectiveAddr is the base address of NAND flash controller.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+* @note		The user needs to first call the XNandPsu_LookupConfig() API
+*		which returns the Configuration structure pointer which is
+*		passed as a parameter to the XNandPsu_CfgInitialize() API.
+*
+******************************************************************************/
+s32 XNandPsu_CfgInitialize(XNandPsu *InstancePtr, XNandPsu_Config *ConfigPtr,
+				u32 EffectiveAddr)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(ConfigPtr != NULL);
+
+	s32 Status = XST_FAILURE;
+
+	/* Initialize InstancePtr Config structure */
+	InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;
+	InstancePtr->Config.BaseAddress = EffectiveAddr;
+	InstancePtr->Config.IsCacheCoherent = ConfigPtr->IsCacheCoherent;
+#if defined  (XCLOCKING)
+	InstancePtr->Config.RefClk = ConfigPtr->RefClk;
+#endif
+	/* Operate in Polling Mode */
+	InstancePtr->Mode = XNANDPSU_POLLING;
+	/* Enable MDMA mode by default */
+	InstancePtr->DmaMode = XNANDPSU_MDMA;
+	InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
+
+	/* Initialize the NAND flash targets */
+	Status = XNandPsu_FlashInit(InstancePtr);
+	if (Status != XST_SUCCESS) {
+#ifdef XNANDPSU_DEBUG
+		xil_printf("%s: Flash init failed\r\n",__func__);
+#endif
+		goto Out;
+	}
+	/* Set ECC mode */
+	if (InstancePtr->Features.EzNand != 0U) {
+		InstancePtr->EccMode = XNANDPSU_EZNAND;
+	} else if (InstancePtr->Features.OnDie != 0U) {
+		InstancePtr->EccMode = XNANDPSU_ONDIE;
+	} else {
+		InstancePtr->EccMode = XNANDPSU_HWECC;
+	}
+
+	/* Initialize Ecc Error flip counters */
+	 InstancePtr->Ecc_Stat_PerPage_flips = 0U;
+	 InstancePtr->Ecc_Stats_total_flips = 0U;
+
+	/*
+	 * Scan for the bad block table(bbt) stored in the flash & load it in
+	 * memory(RAM).  If bbt is not found, create bbt by scanning factory
+	 * marked bad blocks and store it in last good blocks of flash.
+	 */
+	XNandPsu_InitBbtDesc(InstancePtr);
+	Status = XNandPsu_ScanBbt(InstancePtr);
+	if (Status != XST_SUCCESS) {
+#ifdef XNANDPSU_DEBUG
+		xil_printf("%s: BBT scan failed\r\n",__func__);
+#endif
+		goto Out;
+	}
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function initializes the NAND flash and gets the geometry information.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr)
+{
+	u32 Target;
+	u8 Id[ONFI_SIG_LEN] = {0U};
+	OnfiParamPage Param[ONFI_MND_PRM_PGS] = {0U};
+	s32 Status = XST_FAILURE;
+	u32 Index;
+	u32 Crc;
+	u32 PrmPgOff;
+	u32 PrmPgLen;
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+	OnfiExtPrmPage ExtParam = {0U};
+#pragma pack(pop)
+#else
+	OnfiExtPrmPage ExtParam __attribute__ ((aligned(64))) = {0U};
+#endif
+
+	/* Clear Data Interface Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_DATA_INTF_OFFSET, 0U);
+
+	/* Clear DMA Buffer Boundary Register */
+	XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+			XNANDPSU_DMA_BUF_BND_OFFSET, 0U);
+
+	for (Target = 0U; Target < XNANDPSU_MAX_TARGETS; Target++) {
+		/* Reset the Target */
+		Status = XNandPsu_OnfiReset(InstancePtr, Target);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+		/* Read ONFI ID */
+		Status = XNandPsu_OnfiReadId(InstancePtr, Target,
+						ONFI_READ_ID_ADDR,
+						ONFI_SIG_LEN,
+						(u8 *)&Id[0]);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+
+		if (!IS_ONFI(Id)) {
+			if (Target == 0U) {
+#ifdef XNANDPSU_DEBUG
+				xil_printf("%s: ONFI ID doesn't match\r\n",
+								__func__);
+#endif
+				Status = XST_FAILURE;
+				goto Out;
+			}
+		}
+
+		/* Read Parameter Page */
+		Status = XNandPsu_OnfiReadParamPage(InstancePtr,
+						Target, (u8 *)&Param[0]);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+		for(Index = 0U; Index < ONFI_MND_PRM_PGS; Index++){
+			/* Check CRC */
+			Crc = XNandPsu_OnfiParamPageCrc((u8*)&Param[Index], 0U,
+								ONFI_CRC_LEN);
+			if (Crc != Param[Index].Crc) {
+#ifdef XNANDPSU_DEBUG
+				xil_printf("%s: ONFI parameter page (%d) crc check failed\r\n",
+							__func__, Index);
+#endif
+				continue;
+			} else {
+				break;
+			}
+		}
+		if (Index >= ONFI_MND_PRM_PGS) {
+			Status = XST_FAILURE;
+			goto Out;
+		}
+		/* Fill Geometry for the first target */
+		if (Target == 0U) {
+			Status = XNandPsu_InitGeometry(InstancePtr, &Param[Index]);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			XNandPsu_InitDataInterface(InstancePtr, &Param[Index]);
+			XNandPsu_InitTimingMode(InstancePtr, &Param[Index]);
+			XNandPsu_InitFeatures(InstancePtr, &Param[Index]);
+			if ((!InstancePtr->Features.EzNand) != 0U) {
+				Status =XNandPsu_CheckOnDie(InstancePtr,&Param[Index]);
+				if (Status != XST_SUCCESS) {
+					InstancePtr->Features.OnDie = 0U;
+				}
+			}
+			if ((InstancePtr->Geometry.NumBitsECC == 0xFFU) &&
+				(InstancePtr->Features.ExtPrmPage != 0U)) {
+					/* ONFI 3.1 section 5.7.1.6 & 5.7.1.7 */
+				PrmPgLen = (u32)Param[Index].ExtParamPageLen * 16U;
+				PrmPgOff = (u32)((u32)Param[Index].NumOfParamPages *
+						ONFI_PRM_PG_LEN) + (Index * (u32)PrmPgLen);
+
+				Status = XNandPsu_ChangeReadColumn(
+						InstancePtr, Target,
+						PrmPgOff, PrmPgLen, 1U,
+						(u8 *)(void *)&ExtParam);
+				if (Status != XST_SUCCESS) {
+					goto Out;
+				}
+				/* Check CRC */
+				Crc = XNandPsu_OnfiParamPageCrc(
+						(u8 *)&ExtParam,
+						2U, PrmPgLen);
+				if (Crc != ExtParam.Crc) {
+#ifdef XNANDPSU_DEBUG
+	xil_printf("%s: ONFI extended parameter page (%d) crc check failed\r\n",
+							__func__, Index);
+#endif
+					Status = XST_FAILURE;
+					goto Out;
+				}
+				/* Initialize Extended ECC info */
+				Status = XNandPsu_InitExtEcc(
+						InstancePtr,
+						&ExtParam);
+				if (Status != XST_SUCCESS) {
+#ifdef XNANDPSU_DEBUG
+	xil_printf("%s: Init extended ecc failed\r\n",__func__);
+#endif
+					goto Out;
+				}
+			}
+			/* Configure ECC settings */
+			XNandPsu_SetEccAddrSize(InstancePtr);
+		}
+		InstancePtr->Geometry.NumTargets++;
+	}
+	/* Calculate total number of blocks and total size of flash */
+	InstancePtr->Geometry.NumPages = InstancePtr->Geometry.NumTargets *
+					InstancePtr->Geometry.NumTargetPages;
+	InstancePtr->Geometry.NumBlocks = InstancePtr->Geometry.NumTargets *
+					InstancePtr->Geometry.NumTargetBlocks;
+	InstancePtr->Geometry.DeviceSize =
+					(u64)InstancePtr->Geometry.NumTargets *
+					InstancePtr->Geometry.TargetSize;
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function initializes the geometry information from ONFI parameter page.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Param is pointer to the ONFI parameter page.
+*
+* @return
+*               - XST_SUCCESS if successful.
+*               - XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param)
+{
+	s32 Status = XST_FAILURE;
+
+	if (Param->BytesPerPage > XNANDPSU_MAX_PAGE_SIZE) {
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: Invalid Bytes Per Page %d\r\n",
+					__func__, Param->BytesPerPage);
+#endif
+			goto Out;
+	}
+	InstancePtr->Geometry.BytesPerPage = Param->BytesPerPage;
+
+
+	if (Param->SpareBytesPerPage > XNANDPSU_MAX_SPARE_SIZE) {
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: Invalid Spare Bytes Per Page %d\r\n",
+					__func__, Param->SpareBytesPerPage);
+#endif
+			goto Out;
+	}
+	InstancePtr->Geometry.SpareBytesPerPage = Param->SpareBytesPerPage;
+
+	if (Param->PagesPerBlock > XNANDPSU_MAX_PAGES_PER_BLOCK) {
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: Invalid Page Count Per Block %d\r\n",
+					__func__, Param->PagesPerBlock);
+#endif
+			goto Out;
+	}
+	InstancePtr->Geometry.PagesPerBlock = Param->PagesPerBlock;
+
+
+	if (Param->BlocksPerLun > XNANDPSU_MAX_BLOCKS) {
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: Invalid block count per LUN %d\r\n",
+					__func__, Param->BlocksPerLun);
+#endif
+			goto Out;
+	}
+	InstancePtr->Geometry.BlocksPerLun = Param->BlocksPerLun;
+
+	if (Param->NumLuns > XNANDPSU_MAX_LUNS) {
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: Invalid LUN count %d\r\n",
+					__func__, Param->NumLuns);
+#endif
+			goto Out;
+	}
+	InstancePtr->Geometry.NumLuns = Param->NumLuns;
+
+	InstancePtr->Geometry.RowAddrCycles = Param->AddrCycles & 0xFU;
+	InstancePtr->Geometry.ColAddrCycles = (Param->AddrCycles >> 4U) & 0xFU;
+	InstancePtr->Geometry.NumBitsPerCell = Param->BitsPerCell;
+	InstancePtr->Geometry.NumBitsECC = Param->EccBits;
+	InstancePtr->Geometry.BlockSize = (Param->PagesPerBlock *
+						Param->BytesPerPage);
+	InstancePtr->Geometry.NumTargetBlocks = (Param->BlocksPerLun *
+						(u32)Param->NumLuns);
+	InstancePtr->Geometry.NumTargetPages = (Param->BlocksPerLun *
+						(u32)Param->NumLuns *
+						Param->PagesPerBlock);
+	InstancePtr->Geometry.TargetSize = ((u64)Param->BlocksPerLun *
+						(u64)Param->NumLuns *
+						(u64)Param->PagesPerBlock *
+						(u64)Param->BytesPerPage);
+	InstancePtr->Geometry.EccCodeWordSize = 9U; /* 2 power of 9 = 512 */
+	if (InstancePtr->Geometry.NumTargetBlocks > XNANDPSU_MAX_BLOCKS)
+		xil_printf("!!! Device contains more blocks than the max defined blocks in driver\r\n");
+
+#ifdef XNANDPSU_DEBUG
+	xil_printf("Manufacturer: %s\r\n", Param->DeviceManufacturer);
+	xil_printf("Device Model: %s\r\n", Param->DeviceModel);
+	xil_printf("Jedec ID: 0x%x\r\n", Param->JedecManufacturerId);
+	xil_printf("Bytes Per Page: 0x%x\r\n", Param->BytesPerPage);
+	xil_printf("Spare Bytes Per Page: 0x%x\r\n", Param->SpareBytesPerPage);
+	xil_printf("Pages Per Block: 0x%x\r\n", Param->PagesPerBlock);
+	xil_printf("Blocks Per LUN: 0x%x\r\n", Param->BlocksPerLun);
+	xil_printf("Number of LUNs: 0x%x\r\n", Param->NumLuns);
+	xil_printf("Number of bits per cell: 0x%x\r\n", Param->BitsPerCell);
+	xil_printf("Number of ECC bits: 0x%x\r\n", Param->EccBits);
+	xil_printf("Block Size: 0x%x\r\n", InstancePtr->Geometry.BlockSize);
+
+	xil_printf("Number of Target Blocks: 0x%x\r\n",
+					InstancePtr->Geometry.NumTargetBlocks);
+	xil_printf("Number of Target Pages: 0x%x\r\n",
+					InstancePtr->Geometry.NumTargetPages);
+
+#endif
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function initializes the feature list from ONFI parameter page.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Param is pointer to ONFI parameter page buffer.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param)
+{
+	InstancePtr->Features.NvDdr = ((Param->Features & (1U << 5)) != 0U) ?
+								1U : 0U;
+	InstancePtr->Features.EzNand = ((Param->Features & (1U << 9)) != 0U) ?
+								1U : 0U;
+	InstancePtr->Features.ExtPrmPage = ((Param->Features & (1U << 7)) != 0U) ?
+								1U : 0U;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function initializes the Data Interface from ONFI parameter page.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Param is pointer to ONFI parameter page buffer.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_InitDataInterface(XNandPsu *InstancePtr, OnfiParamPage *Param)
+{
+	if (Param->NVDDRTimingMode)
+		InstancePtr->DataInterface = XNANDPSU_NVDDR;
+	else if (Param->SDRTimingMode)
+		InstancePtr->DataInterface = XNANDPSU_SDR;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function initializes the Timing mode from ONFI parameter page.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Param is pointer to ONFI parameter page buffer.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_InitTimingMode(XNandPsu *InstancePtr, OnfiParamPage *Param)
+{
+	s8 Mode;
+	u8 TimingMode =  (u8)(Param->SDRTimingMode);
+
+	if (InstancePtr->DataInterface == XNANDPSU_NVDDR)
+		TimingMode = Param->NVDDRTimingMode;
+
+	for(Mode = XNANDPSU_MAX_TIMING_MODE; Mode >= 0; Mode--) {
+		if (TimingMode & (0x01 << Mode)) {
+			InstancePtr->TimingMode = Mode;
+			break;
+		} else {
+			continue;
+		}
+	}
+}
+
+/*****************************************************************************/
+/**
+*
+* This function checks if the flash supports on-die ECC.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Param is pointer to ONFI parameter page.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr, OnfiParamPage *Param)
+{
+	s32 Status = XST_FAILURE;
+	u8 JedecId[2] = {0U};
+	u8 EccSetFeature[4] = {0x08U, 0x00U, 0x00U, 0x00U};
+	u8 EccGetFeature[4] ={0U};
+
+	/*
+	 * Check if this flash supports On-Die ECC.
+	 * For more information, refer to Micron TN2945.
+	 * Micron Flash: MT29F1G08ABADA, MT29F1G08ABBDA
+	 *		 MT29F1G16ABBDA,
+	 *		 MT29F2G08ABBEA, MT29F2G16ABBEA,
+	 *		 MT29F2G08ABAEA, MT29F2G16ABAEA,
+	 *		 MT29F4G08ABBDA, MT29F4G16ABBDA,
+	 *		 MT29F4G08ABADA, MT29F4G16ABADA,
+	 *		 MT29F8G08ADBDA, MT29F8G16ADBDA,
+	 *		 MT29F8G08ADADA, MT29F8G16ADADA
+	 */
+
+	/* Read JEDEC ID */
+	Status = XNandPsu_OnfiReadId(InstancePtr, 0U, 0x00U, 2U, &JedecId[0]);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	if ((JedecId[0] == 0x2CU) &&
+	/* 1 Gb flash devices */
+	((JedecId[1] == 0xF1U) ||
+	(JedecId[1] == 0xA1U) ||
+	(JedecId[1] == 0xB1U) ||
+	/* 2 Gb flash devices */
+	(JedecId[1] == 0xAAU) ||
+	(JedecId[1] == 0xBAU) ||
+	(JedecId[1] == 0xDAU) ||
+	(JedecId[1] == 0xCAU) ||
+	/* 4 Gb flash devices */
+	(JedecId[1] == 0xACU) ||
+	(JedecId[1] == 0xBCU) ||
+	(JedecId[1] == 0xDCU) ||
+	(JedecId[1] == 0xCCU) ||
+	/* 8 Gb flash devices */
+	(JedecId[1] == 0xA3U) ||
+	(JedecId[1] == 0xB3U) ||
+	(JedecId[1] == 0xD3U) ||
+	(JedecId[1] == 0xC3U))) {
+#ifdef XNANDPSU_DEBUG
+		xil_printf("%s: Ondie flash detected, jedec id 0x%x 0x%x\r\n",
+					__func__, JedecId[0], JedecId[1]);
+#endif
+		/* On-Die Set Feature */
+		Status = XNandPsu_SetFeature(InstancePtr, 0U, 0x90U,
+						&EccSetFeature[0]);
+		if (Status != XST_SUCCESS) {
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: Ondie set_feature failed\r\n",
+								__func__);
+#endif
+			goto Out;
+		}
+		/* Check to see if ECC feature is set */
+		Status = XNandPsu_GetFeature(InstancePtr, 0U, 0x90U,
+						&EccGetFeature[0]);
+		if (Status != XST_SUCCESS) {
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: Ondie get_feature failed\r\n",
+								__func__);
+#endif
+			goto Out;
+		}
+		if ((EccGetFeature[0] & 0x08U) != 0U) {
+			InstancePtr->Features.OnDie = 1U;
+			Status = XST_SUCCESS;
+		}
+	} else {
+		/* On-Die flash not found */
+		Status = XST_FAILURE;
+	}
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function enables DMA mode of controller operation.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+void XNandPsu_EnableDmaMode(XNandPsu *InstancePtr)
+{
+	/* Assert the input arguments. */
+	Xil_AssertVoid(InstancePtr != NULL);
+	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+	InstancePtr->DmaMode = XNANDPSU_MDMA;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function disables DMA mode of driver/controller operation.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+void XNandPsu_DisableDmaMode(XNandPsu *InstancePtr)
+{
+	/* Assert the input arguments. */
+	Xil_AssertVoid(InstancePtr != NULL);
+	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+	InstancePtr->DmaMode = XNANDPSU_PIO;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function enables ECC mode of driver/controller operation.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+void XNandPsu_EnableEccMode(XNandPsu *InstancePtr)
+{
+	/* Assert the input arguments. */
+	Xil_AssertVoid(InstancePtr != NULL);
+	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+	InstancePtr->EccMode = XNANDPSU_HWECC;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function disables ECC mode of driver/controller operation.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+void XNandPsu_DisableEccMode(XNandPsu *InstancePtr)
+{
+	/* Assert the input arguments. */
+	Xil_AssertVoid(InstancePtr != NULL);
+	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+	InstancePtr->EccMode = XNANDPSU_NONE;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function polls for a register bit set status till the timeout.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	RegOffset is the offset of register.
+* @param	Mask is the bitmask.
+* @param	Timeout is the timeout value.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset,
+					u32 Mask, u32 Timeout)
+{
+	s32 Status = XST_FAILURE;
+	volatile u32 RegVal;
+	u32 TimeoutVar = Timeout;
+
+	while (TimeoutVar > 0U) {
+		RegVal = XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
+						RegOffset) & Mask;
+		if (RegVal != 0U) {
+			break;
+		}
+		TimeoutVar--;
+		usleep(1);
+	}
+
+	if (TimeoutVar <= 0U) {
+		Status = XST_FAILURE;
+	} else {
+		Status = XST_SUCCESS;
+	}
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sets packet size and packet count values in packet register.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	PktSize is the packet size.
+* @param	PktCount is the packet count.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize,
+						u32 PktCount)
+{
+	/* Update Packet Register with pkt size and count */
+	XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_PKT_OFFSET,
+				((u32)XNANDPSU_PKT_PKT_SIZE_MASK |
+				(u32)XNANDPSU_PKT_PKT_CNT_MASK),
+				((PktSize & XNANDPSU_PKT_PKT_SIZE_MASK) |
+				((PktCount << XNANDPSU_PKT_PKT_CNT_SHIFT) &
+				XNANDPSU_PKT_PKT_CNT_MASK)));
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sets Page and Column values in the Memory address registers.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Page is the page value.
+* @param	Col is the column value.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col)
+{
+	/* Program Memory Address Register 1 */
+	XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+				XNANDPSU_MEM_ADDR1_OFFSET,
+				(((u32)Col & XNANDPSU_MEM_ADDR1_COL_ADDR_MASK) |
+				((Page << (u32)XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) &
+				XNANDPSU_MEM_ADDR1_PG_ADDR_MASK)));
+	/* Program Memory Address Register 2 */
+	XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET,
+				XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK,
+				((Page >> XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) &
+				XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK));
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sets the size of page in Command Register.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_SetPageSize(XNandPsu *InstancePtr)
+{
+	u32 PageSizeMask = 0;
+	u32 PageSize = InstancePtr->Geometry.BytesPerPage;
+
+	/* Calculate page size mask */
+	switch(PageSize) {
+		case XNANDPSU_PAGE_SIZE_512:
+			PageSizeMask = (0U << XNANDPSU_CMD_PG_SIZE_SHIFT);
+			break;
+		case XNANDPSU_PAGE_SIZE_2K:
+			PageSizeMask = (1U << XNANDPSU_CMD_PG_SIZE_SHIFT);
+			break;
+		case XNANDPSU_PAGE_SIZE_4K:
+			PageSizeMask = (2U << XNANDPSU_CMD_PG_SIZE_SHIFT);
+			break;
+		case XNANDPSU_PAGE_SIZE_8K:
+			PageSizeMask = (3U << XNANDPSU_CMD_PG_SIZE_SHIFT);
+			break;
+		case XNANDPSU_PAGE_SIZE_16K:
+			PageSizeMask = (4U << XNANDPSU_CMD_PG_SIZE_SHIFT);
+			break;
+		case XNANDPSU_PAGE_SIZE_1K_16BIT:
+			PageSizeMask = (5U << XNANDPSU_CMD_PG_SIZE_SHIFT);
+			break;
+		default:
+			/* Not supported */
+			break;
+	}
+	/* Update Command Register */
+	XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_CMD_OFFSET,
+				XNANDPSU_CMD_PG_SIZE_MASK, PageSizeMask);
+}
+
+/*****************************************************************************/
+/**
+*
+* This function setup the Ecc Register.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr)
+{
+	u32 PageSize = InstancePtr->Geometry.BytesPerPage;
+	u32 CodeWordSize = InstancePtr->Geometry.EccCodeWordSize;
+	u32 NumEccBits = InstancePtr->Geometry.NumBitsECC;
+	u32 Index;
+	u32 Found = 0U;
+	u8 BchModeVal;
+
+	for (Index = 0U; Index < (sizeof(EccMatrix)/sizeof(XNandPsu_EccMatrix));
+						Index++) {
+		if ((EccMatrix[Index].PageSize == PageSize) &&
+			(EccMatrix[Index].CodeWordSize >= CodeWordSize)) {
+			if (EccMatrix[Index].NumEccBits >= NumEccBits) {
+				Found = Index;
+				break;
+			}
+			else {
+				Found = Index;
+			}
+		}
+	}
+
+	if (Found != 0U) {
+		if(InstancePtr->Geometry.SpareBytesPerPage < 64U) {
+			InstancePtr->EccCfg.EccAddr = (u16)PageSize;
+		}
+		else {
+			InstancePtr->EccCfg.EccAddr = ((u16)PageSize +
+				(InstancePtr->Geometry.SpareBytesPerPage
+						- EccMatrix[Found].EccSize));
+		}
+		InstancePtr->EccCfg.EccSize = EccMatrix[Found].EccSize;
+		InstancePtr->EccCfg.NumEccBits = EccMatrix[Found].NumEccBits;
+		InstancePtr->EccCfg.CodeWordSize =
+						EccMatrix[Found].CodeWordSize;
+#ifdef XNANDPSU_DEBUG
+		xil_printf("ECC: addr 0x%x size 0x%x numbits %d "
+				   "codesz %d\r\n",
+				   InstancePtr->EccCfg.EccAddr,
+				   InstancePtr->EccCfg.EccSize,
+				   InstancePtr->EccCfg.NumEccBits,
+				   InstancePtr->EccCfg.CodeWordSize);
+#endif
+		if (EccMatrix[Found].IsBCH == XNANDPSU_HAMMING) {
+			InstancePtr->EccCfg.IsBCH = 0U;
+		} else {
+			InstancePtr->EccCfg.IsBCH = 1U;
+		}
+		/* Write ECC register */
+		XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+				(u32)XNANDPSU_ECC_OFFSET,
+				((u32)InstancePtr->EccCfg.EccAddr |
+				((u32)InstancePtr->EccCfg.EccSize << (u32)16) |
+				((u32)InstancePtr->EccCfg.IsBCH << (u32)27)));
+
+		if (EccMatrix[Found].IsBCH == XNANDPSU_BCH) {
+			/* Write memory address register 2 */
+			switch(InstancePtr->EccCfg.NumEccBits) {
+				case 16U:
+					BchModeVal = 0x0U;
+					break;
+				case 12U:
+					BchModeVal = 0x1U;
+					break;
+				case 8U:
+					BchModeVal = 0x2U;
+					break;
+				case 4U:
+					BchModeVal = 0x3U;
+					break;
+				case 24U:
+					BchModeVal = 0x4U;
+					break;
+				default:
+					BchModeVal = 0x0U;
+					break;
+			}
+			XNandPsu_ReadModifyWrite(InstancePtr,
+				XNANDPSU_MEM_ADDR2_OFFSET,
+				XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_MASK,
+				((u32)BchModeVal <<
+				(u32)XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_SHIFT));
+		}
+	}
+}
+
+/*****************************************************************************/
+/**
+*
+* This function setup the Ecc Spare Command Register.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_SetEccSpareCmd(XNandPsu *InstancePtr, u16 SpareCmd,
+								u8 AddrCycles)
+{
+	XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+				(u32)XNANDPSU_ECC_SPR_CMD_OFFSET,
+				(u32)SpareCmd | ((u32)AddrCycles << 28U));
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sets the chip select value in memory address2 register.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target)
+{
+#if defined  (XCLOCKING)
+	Xil_ClockEnable(InstancePtr->Config.RefClk);
+#endif
+	/* Update Memory Address2 register with chip select */
+	XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET,
+			XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK,
+			((Target << XNANDPSU_MEM_ADDR2_CHIP_SEL_SHIFT) &
+			XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK));
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Reset command to the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target)
+{
+	s32 Status = XST_FAILURE;
+
+	/* Enable Transfer Complete Interrupt in Interrupt Status Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_INTR_STS_EN_OFFSET,
+		XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
+	/* Program Command Register */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RST, ONFI_CMD_INVALID, 0U,
+			0U, 0U);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set Reset in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_PROG_OFFSET, XNANDPSU_PROG_RST_MASK);
+
+	/* Poll for Transfer Complete event */
+	Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Read Status command to the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	OnfiStatus is the ONFI status value to return.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target,
+							u16 *OnfiStatus)
+{
+	s32 Status = XST_FAILURE;
+
+	/* Enable Transfer Complete Interrupt in Interrupt Status Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_INTR_STS_EN_OFFSET,
+		XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
+	/* Program Command Register */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_STS, ONFI_CMD_INVALID,
+				0U, 0U, 0U);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Program Packet Size and Packet Count */
+	if(InstancePtr->DataInterface == XNANDPSU_SDR)
+		XNandPsu_SetPktSzCnt(InstancePtr, 1U, 1U);
+	else
+		XNandPsu_SetPktSzCnt(InstancePtr, 2U, 1U);
+
+	/* Set Read Status in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_STS_MASK);
+	/* Poll for Transfer Complete event */
+	Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
+	/* Read Flash Status */
+	*OnfiStatus = (u16) XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
+						XNANDPSU_FLASH_STS_OFFSET);
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Read ID command to the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Buf is the ONFI ID value to return.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr,
+							u32 IdLen, u8 *Buf)
+{
+	s32 Status = XST_FAILURE;
+	u32 Index;
+	u32 Rem;
+	u32 RegVal;
+	u32 RemIdx;
+
+	u32 *BufPtr = (u32 *)(void *)Buf;
+
+	/*
+	 * Enable Buffer Read Ready Interrupt in Interrupt Status Enable
+	 * Register
+	 */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_INTR_STS_EN_OFFSET,
+		XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
+	/* Program Command */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_ID, ONFI_CMD_INVALID, 0U,
+					0U, ONFI_READ_ID_ADDR_CYCLES);
+
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, 0U, IdAddr);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, IdLen, 1U);
+	/* Set Read ID in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_ID_MASK);
+
+	/* Poll for Buffer Read Ready event */
+	Status = XNandPsu_PollRegTimeout(
+		InstancePtr,
+		XNANDPSU_INTR_STS_OFFSET,
+		XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
+		XNANDPSU_INTR_POLL_TIMEOUT);
+	if (Status != XST_SUCCESS) {
+#ifdef XNANDPSU_DEBUG
+		xil_printf("%s: Poll for buf read ready timeout\r\n",
+							__func__);
+#endif
+		goto Out;
+	}
+	/*
+	 * Enable Transfer Complete Interrupt in Interrupt
+	 * Status Enable Register
+	 */
+
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_INTR_STS_EN_OFFSET,
+		XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
+
+	/*
+	 * Clear Buffer Read Ready Interrupt in Interrupt Status
+	 * Register
+	 */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_INTR_STS_OFFSET,
+			XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK);
+	/* Read Packet Data from Data Port Register */
+	for (Index = 0U; Index < (IdLen/4); Index++) {
+		*(BufPtr+Index) = XNandPsu_ReadReg(
+					InstancePtr->Config.BaseAddress,
+					XNANDPSU_BUF_DATA_PORT_OFFSET);
+	}
+	Rem = IdLen % 4;
+	if (Rem != 0U) {
+		RegVal = XNandPsu_ReadReg(
+					InstancePtr->Config.BaseAddress,
+					XNANDPSU_BUF_DATA_PORT_OFFSET);
+		for (RemIdx = 0U; RemIdx < Rem; RemIdx++) {
+			*(Buf + (Index * 4U) + RemIdx) = (u8) (RegVal >>
+						(RemIdx * 8U)) & 0xFFU;
+		}
+	}
+
+	Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
+
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends the ONFI Read Parameter Page command to flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	PrmIndex is the index of parameter page.
+* @param	Buf is the parameter page information to return.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target,
+						u8 *Buf)
+{
+	s32 Status = XST_FAILURE;
+
+	/*
+	 * Enable Buffer Read Ready Interrupt in Interrupt Status Enable
+	 * Register
+	 */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_INTR_STS_EN_OFFSET,
+		XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
+	/* Program Command */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_PRM_PG, ONFI_CMD_INVALID,
+					0U, 0U, ONFI_PRM_PG_ADDR_CYCLES);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, 0U, 0U);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, ONFI_MND_PRM_PGS*ONFI_PRM_PG_LEN, 1U);
+	/* Set Read Parameter Page in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_PRM_PG_MASK);
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, 1U, ONFI_MND_PRM_PGS*ONFI_PRM_PG_LEN, 0, 0);
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function returns the length including bad blocks from a given offset and
+* length.
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+* @param	Offset is the flash data address to read from.
+* @param	Length is number of bytes to read.
+*
+* @return
+*		- Return actual length including bad blocks.
+*
+* @note		None.
+*
+******************************************************************************/
+static s32 XNandPsu_CalculateLength(XNandPsu *InstancePtr, u64 Offset,
+							u64 Length)
+{
+	s32 Status;
+	u32 BlockSize;
+	u32 BlockLen;
+	u32 Block;
+	u64 TempLen = 0;
+	u64 OffsetVar = Offset;
+
+	BlockSize = InstancePtr->Geometry.BlockSize;
+
+	while (TempLen < Length) {
+		Block = (u32)(OffsetVar/BlockSize);
+		BlockLen = BlockSize - (u32)(OffsetVar % BlockSize);
+		if (OffsetVar >= InstancePtr->Geometry.DeviceSize) {
+			Status = XST_FAILURE;
+			goto Out;
+		}
+		/* Check if the block is bad */
+		Status = XNandPsu_IsBlockBad(InstancePtr, Block);
+		if (Status != XST_SUCCESS) {
+			/* Good block */
+			TempLen += BlockLen;
+		}
+		OffsetVar += BlockLen;
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function writes to the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Offset is the starting offset of flash to write.
+* @param	Length is the number of bytes to write.
+* @param	SrcBuf is the source data buffer to write.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_Write(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *SrcBuf)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+	Xil_AssertNonvoid(SrcBuf != NULL);
+	Xil_AssertNonvoid(Length != 0U);
+	Xil_AssertNonvoid((Offset + Length) <=
+				InstancePtr->Geometry.DeviceSize);
+
+	s32 Status = XST_FAILURE;
+	u32 Page;
+	u32 Col;
+	u32 Target;
+	u32 Block;
+	u32 PartialBytes = 0;
+	u32 NumBytes;
+	u32 RemLen;
+	u8 *BufPtr;
+	u8 *SrcBufPtr = (u8 *)SrcBuf;
+	u64 OffsetVar = Offset;
+	u64 LengthVar = Length;
+
+	/*
+	 * Check if write operation exceeds flash size when including
+	 * bad blocks.
+	 */
+	Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	while (LengthVar > 0U) {
+		Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
+		/*
+		 * Skip the bad blocks. Increment the offset by block size.
+		 * For better results, always program the flash starting at
+		 * a block boundary.
+		 */
+		if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) {
+			OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
+			continue;
+		}
+		/* Calculate Page and Column address values */
+		Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage);
+		Col = (u32) (OffsetVar &
+				(InstancePtr->Geometry.BytesPerPage - 1U));
+		PartialBytes = 0U;
+		/*
+		 * Check if partial write.
+		 * If column address is > 0 or Length is < page size
+		 */
+		if ((Col > 0U) ||
+			(LengthVar < InstancePtr->Geometry.BytesPerPage)) {
+			RemLen = InstancePtr->Geometry.BytesPerPage - Col;
+			PartialBytes = (RemLen < (u32)LengthVar) ?
+					RemLen : (u32)LengthVar;
+		}
+
+		Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize);
+		if (Page > InstancePtr->Geometry.NumTargetPages) {
+			Page %= InstancePtr->Geometry.NumTargetPages;
+		}
+
+		/* Check if partial write */
+		if (PartialBytes > 0U) {
+			BufPtr = &InstancePtr->PartialDataBuf[0];
+			(void)memset(BufPtr, 0xFF,
+					InstancePtr->Geometry.BytesPerPage);
+			(void)Xil_MemCpy(BufPtr + Col, SrcBufPtr, PartialBytes);
+
+			NumBytes = PartialBytes;
+		} else {
+			BufPtr = (u8 *)SrcBufPtr;
+			NumBytes = (InstancePtr->Geometry.BytesPerPage <
+					(u32)LengthVar) ?
+					InstancePtr->Geometry.BytesPerPage :
+					(u32)LengthVar;
+		}
+		/* Program page */
+		Status = XNandPsu_ProgramPage(InstancePtr, Target, Page, 0U,
+								BufPtr);
+		if (Status != XST_SUCCESS)
+			goto Out;
+
+		Status = XNandPsu_Device_Ready(InstancePtr, Target);
+		if (Status != XST_SUCCESS)
+			goto Out;
+
+		SrcBufPtr += NumBytes;
+		OffsetVar += NumBytes;
+		LengthVar -= NumBytes;
+	}
+
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function reads from the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Offset is the starting offset of flash to read.
+* @param	Length is the number of bytes to read.
+* @param	DestBuf is the destination data buffer to fill in.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_Read(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *DestBuf)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+	Xil_AssertNonvoid(DestBuf != NULL);
+	Xil_AssertNonvoid(Length != 0U);
+	Xil_AssertNonvoid((Offset + Length) <=
+				InstancePtr->Geometry.DeviceSize);
+
+	s32 Status = XST_FAILURE;
+	u32 Page;
+	u32 Col;
+	u32 Target;
+	u32 Block;
+	u32 PartialBytes = 0U;
+	u32 RemLen;
+	u32 NumBytes;
+	u8 *BufPtr;
+	u8 *DestBufPtr = (u8 *)DestBuf;
+	u64 OffsetVar = Offset;
+	u64 LengthVar = Length;
+
+	/*
+	 * Check if read operation exceeds flash size when including
+	 * bad blocks.
+	 */
+	Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	while (LengthVar > 0U) {
+		Block = (u32)(OffsetVar/InstancePtr->Geometry.BlockSize);
+		/*
+		 * Skip the bad block. Increment the offset by block size.
+		 * The flash programming utility must make sure to start
+		 * writing always at a block boundary and skip blocks if any.
+		 */
+		if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) {
+			OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
+			continue;
+		}
+		/* Calculate Page and Column address values */
+		Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage);
+		Col = (u32) (OffsetVar &
+				(InstancePtr->Geometry.BytesPerPage - 1U));
+		PartialBytes = 0U;
+		/*
+		 * Check if partial write.
+		 * If column address is > 0 or Length is < page size
+		 */
+		if ((Col > 0U) ||
+			(LengthVar < InstancePtr->Geometry.BytesPerPage)) {
+			RemLen = InstancePtr->Geometry.BytesPerPage - Col;
+			PartialBytes = ((u32)RemLen < (u32)LengthVar) ?
+						(u32)RemLen : (u32)LengthVar;
+		}
+
+		Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize);
+		if (Page > InstancePtr->Geometry.NumTargetPages) {
+			Page %= InstancePtr->Geometry.NumTargetPages;
+		}
+		/* Check if partial read */
+		if (PartialBytes > 0U) {
+			BufPtr = &InstancePtr->PartialDataBuf[0];
+			NumBytes = PartialBytes;
+		} else {
+			BufPtr = DestBufPtr;
+			NumBytes = (InstancePtr->Geometry.BytesPerPage <
+					(u32)LengthVar) ?
+					InstancePtr->Geometry.BytesPerPage :
+					(u32)LengthVar;
+		}
+		/* Read page */
+		Status = XNandPsu_ReadPage(InstancePtr, Target, Page, 0U,
+								BufPtr);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+		if (PartialBytes > 0U) {
+			(void)Xil_MemCpy(DestBufPtr, BufPtr + Col, NumBytes);
+		}
+		DestBufPtr += NumBytes;
+		OffsetVar += NumBytes;
+		LengthVar -= NumBytes;
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function erases the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Offset is the starting offset of flash to erase.
+* @param	Length is the number of bytes to erase.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note
+*		The Offset and Length should be aligned to block size boundary
+*		to get better results.
+*
+******************************************************************************/
+s32 XNandPsu_Erase(XNandPsu *InstancePtr, u64 Offset, u64 Length)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+	Xil_AssertNonvoid(Length != 0U);
+	Xil_AssertNonvoid((Offset + Length) <=
+			InstancePtr->Geometry.DeviceSize);
+
+	s32 Status = XST_FAILURE;
+	u32 Target = 0;
+	u32 StartBlock;
+	u32 NumBlocks = 0;
+	u32 Block;
+	u32 AlignOff;
+	u32 EraseLen;
+	u32 BlockRemLen;
+	u64 OffsetVar = Offset;
+	u64 LengthVar = Length;
+
+	/*
+	 * Check if erase operation exceeds flash size when including
+	 * bad blocks.
+	 */
+	Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+	/* Calculate number of blocks to erase */
+	StartBlock = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
+
+	while (LengthVar > 0U) {
+		Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
+		if (XNandPsu_IsBlockBad(InstancePtr, Block) ==
+							XST_SUCCESS) {
+			OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
+			NumBlocks++;
+			continue;
+		}
+
+		AlignOff = (u32)OffsetVar &
+				(InstancePtr->Geometry.BlockSize - (u32)1);
+		if (AlignOff > 0U) {
+			BlockRemLen = InstancePtr->Geometry.BlockSize -
+								AlignOff;
+			EraseLen = (BlockRemLen < (u32)LengthVar) ?
+						BlockRemLen :(u32)LengthVar;
+		} else {
+			EraseLen = (InstancePtr->Geometry.BlockSize <
+						(u32)LengthVar) ?
+					InstancePtr->Geometry.BlockSize:
+						(u32)LengthVar;
+		}
+		NumBlocks++;
+		OffsetVar += EraseLen;
+		LengthVar -= EraseLen;
+	}
+
+	for (Block = StartBlock; Block < (StartBlock + NumBlocks); Block++) {
+		Target = Block/InstancePtr->Geometry.NumTargetBlocks;
+		Block %= InstancePtr->Geometry.NumTargetBlocks;
+		/* Don't erase bad block */
+		if (XNandPsu_IsBlockBad(InstancePtr, Block) ==
+							XST_SUCCESS)
+			continue;
+		/* Block Erase */
+		Status = XNandPsu_EraseBlock(InstancePtr, Target, Block);
+		if (Status != XST_SUCCESS)
+			goto Out;
+
+		Status = XNandPsu_Device_Ready(InstancePtr, Target);
+		if (Status != XST_SUCCESS)
+					goto Out;
+
+				}
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Program Page command to flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Page is the page address value to program.
+* @param	Col is the column address value to program.
+* @param	Buf is the data buffer to program.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
+							u32 Col, u8 *Buf)
+{
+	u32 PktSize;
+	u32 PktCount;
+	s32 Status = XST_FAILURE;
+	u32 IsrValue;
+	u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
+				InstancePtr->Geometry.ColAddrCycles;
+
+	if (InstancePtr->EccCfg.CodeWordSize > 9U) {
+		PktSize = 1024U;
+	} else {
+		PktSize = 512U;
+	}
+	PktCount = InstancePtr->Geometry.BytesPerPage/PktSize;
+
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1, ONFI_CMD_PG_PROG2,
+					1U, 1U, (u8)AddrCycles);
+
+	if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
+		IsrValue = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
+			   XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
+		if (InstancePtr->Config.IsCacheCoherent == 0) {
+			Xil_DCacheFlushRange((INTPTR)(void *)Buf, (PktSize * PktCount));
+		}
+		XNandPsu_Update_DmaAddr(InstancePtr, Buf);
+	} else {
+		IsrValue = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK;
+	}
+
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			   XNANDPSU_INTR_STS_EN_OFFSET, IsrValue);
+	/* Program Page Size */
+	XNandPsu_SetPageSize(InstancePtr);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set ECC */
+	if (InstancePtr->EccMode == XNANDPSU_HWECC) {
+		XNandPsu_SetEccSpareCmd(InstancePtr, ONFI_CMD_CHNG_WR_COL,
+					InstancePtr->Geometry.ColAddrCycles);
+	}
+	/* Set Page Program in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK);
+
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 1);
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Program Page command to flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Page is the page address value to program.
+* @param	Buf is the data buffer to program.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_WriteSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+	Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages);
+	Xil_AssertNonvoid(Buf != NULL);
+
+	u32 PktCount = 1U;
+	u16 PreEccSpareCol = 0U;
+	u16 PreEccSpareWrCnt = 0U;
+	u16 PostEccSpareCol = 0U;
+	u16 PostEccSpareWrCnt = 0U;
+	u32 PostWrite = 0U;
+	OnfiCmdFormat Cmd;
+	s32 Status = XST_FAILURE;
+	u32 RegVal;
+	u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
+				InstancePtr->Geometry.ColAddrCycles;
+	u32 Col = InstancePtr->Geometry.BytesPerPage;
+	u32 Target = Page/InstancePtr->Geometry.NumTargetPages;
+	u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage;
+	u32 *BufPtr = (u32 *)(void *)Buf;
+	u32 PageVar = Page;
+
+	PageVar %= InstancePtr->Geometry.NumTargetPages;
+
+	if (InstancePtr->EccMode == XNANDPSU_HWECC) {
+		/* Calculate ECC free positions before and after ECC code */
+		PreEccSpareCol = 0x0U;
+		PreEccSpareWrCnt = InstancePtr->EccCfg.EccAddr -
+				(u16)InstancePtr->Geometry.BytesPerPage;
+
+		PostEccSpareCol = PreEccSpareWrCnt +
+					InstancePtr->EccCfg.EccSize;
+		PostEccSpareWrCnt = InstancePtr->Geometry.SpareBytesPerPage -
+					PostEccSpareCol;
+
+		PreEccSpareWrCnt = (PreEccSpareWrCnt/4U) * 4U;
+		PostEccSpareWrCnt = (PostEccSpareWrCnt/4U) * 4U;
+
+		if (PreEccSpareWrCnt > 0U) {
+			PktSize = PreEccSpareWrCnt;
+			PktCount = 1U;
+			Col = InstancePtr->Geometry.BytesPerPage +
+							PreEccSpareCol;
+			BufPtr = (u32 *)(void *)Buf;
+			if (PostEccSpareWrCnt > 0U) {
+				PostWrite = 1U;
+			}
+		} else if (PostEccSpareWrCnt > 0U) {
+			PktSize = PostEccSpareWrCnt;
+			PktCount = 1U;
+			Col = InstancePtr->Geometry.BytesPerPage +
+							PostEccSpareCol;
+			BufPtr = (u32 *)(Buf + Col);
+		} else {
+			/* No free spare bytes available for writing */
+			Status = XST_FAILURE;
+			goto Out;
+		}
+	}
+
+	if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
+		RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK;
+		if (InstancePtr->Config.IsCacheCoherent == 0) {
+			Xil_DCacheFlushRange((INTPTR)(void *)BufPtr, (PktSize * PktCount));
+		}
+		XNandPsu_Update_DmaAddr(InstancePtr, (u8 *)BufPtr);
+	} else {
+		RegVal = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK;
+	}
+
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			   XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
+	/* Program Command hack for change write column */
+	if (PostWrite > 0U) {
+		Cmd.Command1 = 0x80U;
+		Cmd.Command2 = 0x00U;
+		XNandPsu_Prepare_Cmd(InstancePtr, Cmd.Command1, Cmd.Command2,
+				0U , 1U, (u8)AddrCycles);
+
+	} else {
+		XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1,
+				ONFI_CMD_PG_PROG2, 0U , 1U, (u8)AddrCycles);
+	}
+	/* Program Page Size */
+	XNandPsu_SetPageSize(InstancePtr);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set Page Program in Program Register */
+	if (PostWrite > 0U) {
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,((u32)XNANDPSU_PROG_PG_PROG_MASK |
+				(u32)XNANDPSU_PROG_CHNG_ROW_ADDR_MASK));
+	} else {
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK);
+	}
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, (u8 *)BufPtr, PktCount,
+					 PktSize, 1, 1);
+
+	if (InstancePtr->EccMode == XNANDPSU_HWECC) {
+		if (PostWrite > 0U) {
+			BufPtr = (u32 *)(Buf + PostEccSpareCol);
+			Status = XNandPsu_ChangeWriteColumn(InstancePtr,
+					Target,
+					PostEccSpareCol, PostEccSpareWrCnt, 1U,
+					(u8 *)(void *)BufPtr);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+		}
+	}
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Read Page command to flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Page is the page address value to read.
+* @param	Col is the column address value to read.
+* @param	Buf is the data buffer to fill in.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
+							u32 Col, u8 *Buf)
+{
+	u32 PktSize;
+	u32 PktCount;
+	s32 Status = XST_FAILURE;
+	u32 RegVal;
+	u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
+				InstancePtr->Geometry.ColAddrCycles;
+
+	if (InstancePtr->EccCfg.CodeWordSize > 9U) {
+		PktSize = 1024U;
+	} else {
+		PktSize = 512U;
+	}
+	PktCount = InstancePtr->Geometry.BytesPerPage/PktSize;
+
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2,
+					1U, 1U, (u8)AddrCycles);
+
+	if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
+		RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
+			 XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
+		if (InstancePtr->Config.IsCacheCoherent == 0) {
+			Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
+		}
+		XNandPsu_Update_DmaAddr(InstancePtr, Buf);
+	} else {
+		RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK;
+	}
+	/* Enable Single bit error and Multi bit error */
+	if (InstancePtr->EccMode == XNANDPSU_HWECC)
+		RegVal |= XNANDPSU_INTR_STS_EN_MUL_BIT_ERR_STS_EN_MASK |
+			 XNANDPSU_INTR_STS_EN_ERR_INTR_STS_EN_MASK;
+
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			   XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
+	/* Program Page Size */
+	XNandPsu_SetPageSize(InstancePtr);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set ECC */
+	if (InstancePtr->EccMode == XNANDPSU_HWECC) {
+		XNandPsu_SetEccSpareCmd(InstancePtr,
+					(ONFI_CMD_CHNG_RD_COL1 |
+					(ONFI_CMD_CHNG_RD_COL2 << (u8)8U)),
+					InstancePtr->Geometry.ColAddrCycles);
+	}
+
+	/* Set Read command in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+				XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1);
+
+	/* Check ECC Errors */
+	if (InstancePtr->EccMode == XNANDPSU_HWECC) {
+		/* Hamming Multi Bit Errors */
+		if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
+				XNANDPSU_INTR_STS_OFFSET) &
+			(u32)XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK) != 0U) {
+
+			XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+				XNANDPSU_INTR_STS_OFFSET,
+				XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK);
+
+#ifdef XNANDPSU_DEBUG
+			xil_printf("%s: ECC Hamming multi bit error\r\n",
+							__func__);
+#endif
+			InstancePtr->Ecc_Stat_PerPage_flips =
+					((XNandPsu_ReadReg(
+					InstancePtr->Config.BaseAddress,
+					XNANDPSU_ECC_ERR_CNT_OFFSET) &
+					0x1FF00U) >> 8U);
+			InstancePtr->Ecc_Stats_total_flips +=
+					InstancePtr->Ecc_Stat_PerPage_flips;
+			Status = XST_FAILURE;
+		}
+		/* Hamming Single Bit or BCH Errors */
+		if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
+				XNANDPSU_INTR_STS_OFFSET) &
+			(u32)XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK) != 0U) {
+
+			XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+					XNANDPSU_INTR_STS_OFFSET,
+					XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK);
+
+			if (InstancePtr->EccCfg.IsBCH == 1U) {
+				InstancePtr->Ecc_Stat_PerPage_flips =
+						((XNandPsu_ReadReg(
+						InstancePtr->Config.BaseAddress,
+						XNANDPSU_ECC_ERR_CNT_OFFSET)&
+						0x1FF00U) >> 8U);
+				InstancePtr->Ecc_Stats_total_flips +=
+					InstancePtr->Ecc_Stat_PerPage_flips;
+				Status = XST_SUCCESS;
+			}
+		}
+	}
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function reads spare bytes from flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Page is the page address value to read.
+* @param	Buf is the data buffer to fill in.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_ReadSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+	Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages);
+	Xil_AssertNonvoid(Buf != NULL);
+
+	u32 PktCount = 1U;
+	s32 Status = XST_FAILURE;
+	u32 RegVal;
+	u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
+				InstancePtr->Geometry.ColAddrCycles;
+	u32 Col = InstancePtr->Geometry.BytesPerPage;
+	u32 Target = Page/InstancePtr->Geometry.NumTargetPages;
+	u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage;
+	u32 PageVar = Page;
+
+	PageVar %= InstancePtr->Geometry.NumTargetPages;
+
+	if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
+		RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK;
+		if (InstancePtr->Config.IsCacheCoherent == 0) {
+			Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
+		}
+		XNandPsu_Update_DmaAddr(InstancePtr, Buf);
+	} else {
+		RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK;
+	}
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			   XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
+	/* Program Command */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2, 0U,
+						1U, (u8)AddrCycles);
+	/* Program Page Size */
+	XNandPsu_SetPageSize(InstancePtr);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set Read command in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+				XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1);
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI block erase command to the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Block is the block to erase.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_EraseBlock(XNandPsu *InstancePtr, u32 Target, u32 Block)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+	Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
+	Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
+
+	s32 Status = XST_FAILURE;
+	u32 Page;
+	u32 ErasePage;
+	u32 EraseCol;
+	u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles;
+
+	Page = Block * InstancePtr->Geometry.PagesPerBlock;
+	ErasePage = (Page >> 16U) & 0xFFFFU;
+	EraseCol = Page & 0xFFFFU;
+
+	/*
+	 * Enable Transfer Complete Interrupt in Interrupt Status Enable
+	 * Register
+	 */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_INTR_STS_EN_OFFSET,
+			XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
+
+	/* Program Command */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_BLK_ERASE1,
+			ONFI_CMD_BLK_ERASE2, 0U , 0U, (u8)AddrCycles);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, ErasePage, (u16)EraseCol);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set Block Erase in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_BLK_ERASE_MASK);
+	/* Poll for Transfer Complete event */
+	Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Get Feature command to flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Feature is the feature selector.
+* @param	Buf is the buffer to fill feature value.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_GetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
+								u8 *Buf)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
+	Xil_AssertNonvoid(Buf != NULL);
+	Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
+
+	s32 Status;
+	u32 PktSize = 4;
+	u32 PktCount = 1;
+
+	if (InstancePtr->DataInterface == XNANDPSU_NVDDR) {
+		PktSize = 8U;
+	}
+
+	/*
+	 * Enable Buffer Read Ready Interrupt in Interrupt Status
+	 * Enable Register
+	 */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_INTR_STS_EN_OFFSET,
+			XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
+	/* Program Command */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_GET_FEATURES,
+				ONFI_CMD_INVALID, 0U, 0U, 1U);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Set Read Parameter Page in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_GET_FEATURES_MASK);
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 0);
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function sends ONFI Set Feature command to flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Feature is the feature selector.
+* @param	Buf is the feature value to send.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_SetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
+								u8 *Buf)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
+	Xil_AssertNonvoid(Buf != NULL);
+	Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
+
+	s32 Status;
+	u32 PktSize = 4U;
+	u32 PktCount = 1U;
+
+	if (InstancePtr->DataInterface == XNANDPSU_NVDDR) {
+		PktSize = 8U;
+	}
+
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_INTR_STS_EN_OFFSET, 0U);
+
+	/*
+	 * Enable Buffer Write Ready Interrupt in Interrupt Status
+	 * Enable Register
+	 */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_INTR_STS_EN_OFFSET,
+			XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
+
+	/* Program Command */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_SET_FEATURES,
+				ONFI_CMD_INVALID, 0U , 0U, 1U);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Set Read Parameter Page in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_SET_FEATURES_MASK);
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 0);
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function changes clock frequency of flash controller.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	ClockFreq is the clock frequency to change.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_ChangeClockFreq(XNandPsu *InstancePtr, u32 ClockFreq)
+{
+	(void) InstancePtr;
+	(void) ClockFreq;
+
+	/* Not implemented */
+}
+/*****************************************************************************/
+/**
+*
+* This function changes the data interface and timing mode.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	NewIntf is the new data interface.
+* @param	NewMode is the new timing mode.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+s32 XNandPsu_ChangeTimingMode(XNandPsu *InstancePtr,
+				XNandPsu_DataInterface NewIntf,
+				XNandPsu_TimingMode NewMode)
+{
+	/* Assert the input arguments. */
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+	s32 Status = XST_SUCCESS;
+	u32 Target;
+	u32 RegVal;
+	u8 Buf[4] = {0U};
+	u32 *Feature = (u32 *)(void *)&Buf[0];
+	u32 SetFeature = 0U;
+	u32 NewModeVar = (u32)NewMode;
+
+	/* Check for valid input arguments */
+	if(((NewIntf != XNANDPSU_SDR) && (NewIntf != XNANDPSU_NVDDR)) ||
+			(NewModeVar > 5U)){
+		Status = XST_FAILURE;
+		goto Out;
+	}
+
+	if(NewIntf == XNANDPSU_NVDDR){
+		NewModeVar = NewModeVar | (u32)0x10;
+	}
+	/* Get current data interface type and timing mode */
+	XNandPsu_DataInterface CurIntf = InstancePtr->DataInterface;
+	XNandPsu_TimingMode CurMode = InstancePtr->TimingMode;
+
+	/* Check if the flash is in same mode */
+	if ((CurIntf == NewIntf) && (CurMode == NewModeVar)) {
+		Status = XST_SUCCESS;
+		goto Out;
+	}
+
+	if ((CurIntf == XNANDPSU_NVDDR) && (NewIntf == XNANDPSU_SDR)) {
+
+		NewModeVar = XNANDPSU_SDR0;
+
+		/* Change the clock frequency */
+		XNandPsu_ChangeClockFreq(InstancePtr, XNANDPSU_SDR_CLK);
+
+		/* Update Data Interface Register */
+		RegVal = ((NewModeVar % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) |
+				((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT);
+		XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+					XNANDPSU_DATA_INTF_OFFSET, RegVal);
+
+		for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
+							Target++) {
+			Status = XNandPsu_OnfiReset(InstancePtr, Target);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+		}
+
+		/* Set Feature */
+		for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
+								Target++) {
+			Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U,
+							(u8 *)(void *)&NewModeVar);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+		}
+
+		InstancePtr->DataInterface = NewIntf;
+		InstancePtr->TimingMode = NewModeVar;
+
+		for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
+								Target++) {
+			Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U,
+								&Buf[0]);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			/* Check if set_feature was successful */
+			if (*Feature != NewModeVar) {
+				Status = XST_FAILURE;
+				goto Out;
+			}
+		}
+
+		goto Out;
+	}
+
+	SetFeature = NewModeVar;
+	if((CurIntf == XNANDPSU_NVDDR) && (NewIntf == XNANDPSU_NVDDR)){
+		SetFeature |= SetFeature << 8U;
+	}
+	/* Set Feature */
+	for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
+							Target++) {
+		Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U,
+						(u8 *)(void *)&SetFeature);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+	}
+
+	InstancePtr->DataInterface = NewIntf;
+	InstancePtr->TimingMode = NewModeVar;
+	/* Update Data Interface Register */
+	RegVal = ((NewMode % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) |
+			((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT);
+	XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+				XNANDPSU_DATA_INTF_OFFSET, RegVal);
+
+	/* Get Feature */
+	for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
+							Target++) {
+		Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U,
+							&Buf[0]);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+
+		/* Check if set_feature was successful */
+		if (*Feature != NewModeVar) {
+			Status = XST_FAILURE;
+			goto Out;
+		}
+	}
+
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function issues change read column and reads the data into buffer
+* specified by user.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Col is the coulmn address.
+* @param	PktSize is the number of bytes to read.
+* @param	PktCount is the number of transactions to read.
+* @param	Buf is the data buffer to fill in.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target,
+					u32 Col, u32 PktSize, u32 PktCount,
+					u8 *Buf)
+{
+	s32 Status = XST_FAILURE;
+	u32 RegVal;
+	u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles;
+
+	if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
+		RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
+			 XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
+		Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
+		XNandPsu_Update_DmaAddr(InstancePtr, Buf);
+	} else {
+		RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK;
+	}
+
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			   XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
+	/* Program Command */
+	XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_CHNG_RD_COL1,
+			ONFI_CMD_CHNG_RD_COL2, 0U , 1U, (u8)AddrCycles);
+	/* Program Page Size */
+	XNandPsu_SetPageSize(InstancePtr);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set Read command in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1);
+
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function issues change read column and reads the data into buffer
+* specified by user.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chip select value.
+* @param	Col is the coulmn address.
+* @param	PktSize is the number of bytes to read.
+* @param	PktCount is the number of transactions to read.
+* @param	Buf is the data buffer to fill in.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target,
+					u32 Col, u32 PktSize, u32 PktCount,
+					u8 *Buf)
+{
+	s32 Status = XST_FAILURE;
+	OnfiCmdFormat OnfiCommand;
+	u32 RegVal;
+	u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles;
+
+	if (PktCount == 0U) {
+		return XST_SUCCESS;
+	}
+
+	if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
+		RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
+			 XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
+		XNandPsu_Update_DmaAddr(InstancePtr, Buf);
+	} else {
+		RegVal = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK;
+	}
+
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			   XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
+	/* Change write column hack */
+	OnfiCommand.Command1 = 0x85U;
+	OnfiCommand.Command2 = 0x10U;
+	XNandPsu_Prepare_Cmd(InstancePtr, OnfiCommand.Command1,
+				OnfiCommand.Command2, 0U , 0U, (u8)AddrCycles);
+
+	/* Program Page Size */
+	XNandPsu_SetPageSize(InstancePtr);
+	/* Program Column, Page, Block address */
+	XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col);
+	/* Program Packet Size and Packet Count */
+	XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
+	/* Program Memory Address Register2 for chip select */
+	XNandPsu_SelectChip(InstancePtr, Target);
+	/* Set Page Program in Program Register */
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_CHNG_ROW_ADDR_END_MASK);
+
+	Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 0);
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function initializes extended parameter page ECC information.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	ExtPrm is the Extended parameter page buffer.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm)
+{
+	s32 Status = XST_FAILURE;
+	u32 Offset = 0U;
+	u32 Found = 0U;
+	OnfiExtEccBlock *EccBlock;
+
+	if (ExtPrm->Section0Type != 0x2U) {
+		Offset += (u32)ExtPrm->Section0Len;
+		if (ExtPrm->Section1Type != 0x2U) {
+#ifdef XNANDPSU_DEBUG
+		xil_printf("%s: Extended ECC section not found\r\n",__func__);
+#endif
+			Status = XST_FAILURE;
+		} else {
+			Found = 1U;
+		}
+	} else {
+		Found = 1U;
+	}
+
+	if (Found != 0U) {
+		EccBlock = (OnfiExtEccBlock *)&ExtPrm->SectionData[Offset];
+		Xil_AssertNonvoid(EccBlock != NULL);
+		if (EccBlock->CodeWordSize == 0U) {
+			Status = XST_FAILURE;
+		} else {
+			InstancePtr->Geometry.NumBitsECC =
+						EccBlock->NumEccBits;
+			InstancePtr->Geometry.EccCodeWordSize =
+						(u32)EccBlock->CodeWordSize;
+			Status = XST_SUCCESS;
+		}
+	}
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function prepares command to be written into command register.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Cmd1 is the first Onfi Command.
+* @param	Cmd2 is the second Onfi Command.
+* @param	EccState is the flag to set Ecc State.
+* @param	DmaMode is the flag to set DMA mode.
+* @param	AddrCycles is the number of Address Cycles.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+void XNandPsu_Prepare_Cmd(XNandPsu *InstancePtr, u8 Cmd1, u8 Cmd2, u8 EccState,
+			u8 DmaMode, u8 AddrCycles)
+{
+	Xil_AssertVoid(InstancePtr != NULL);
+
+	u32 RegValue = 0U;
+
+	RegValue = (u32)Cmd1 | (((u32)Cmd2 << (u32)XNANDPSU_CMD_CMD2_SHIFT) &
+			(u32)XNANDPSU_CMD_CMD2_MASK);
+
+	if ((EccState != 0U) && (InstancePtr->EccMode == XNANDPSU_HWECC)) {
+		RegValue |= 1U << XNANDPSU_CMD_ECC_ON_SHIFT;
+	}
+
+	if ((DmaMode != 0U) && (InstancePtr->DmaMode == XNANDPSU_MDMA)) {
+		RegValue |= XNANDPSU_MDMA << XNANDPSU_CMD_DMA_EN_SHIFT;
+	}
+
+	if (AddrCycles != 0U) {
+		RegValue |= (u32)AddrCycles <<
+				(u32)XNANDPSU_CMD_ADDR_CYCLES_SHIFT;
+	}
+
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_CMD_OFFSET, RegValue);
+}
+
+/*****************************************************************************/
+/**
+*
+* This function Read/Writes data from the nand controller.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Buf is the data buffer.
+* @param	PktCount is the number packet chunks.
+* @param	PktSize is the size of the packet.
+* @param	Operation is 1 for write and 0 for read.
+* @param	DmaMode is 1 for Dma and 0 for PIO.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_Data_ReadWrite(XNandPsu *InstancePtr, u8* Buf, u32 PktCount,
+				u32 PktSize, u32 Operation, u8 DmaMode)
+{
+	u32 BufRwCnt = 0U;
+	s32 Status = XST_FAILURE;
+	u32 Event = XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK;
+
+	if ((DmaMode != 0U) && (InstancePtr->DmaMode == XNANDPSU_MDMA))
+		goto DmaDone;
+
+	if (Operation)
+		Event = XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK;
+
+	while (BufRwCnt < PktCount) {
+		/* Poll for Buffer Write Ready event */
+		Status = XNandPsu_PollRegTimeout(InstancePtr,
+				XNANDPSU_INTR_STS_OFFSET, Event,
+				XNANDPSU_INTR_POLL_TIMEOUT);
+		if (Status != XST_SUCCESS) {
+			xil_printf("%s: Poll for buf write ready timeout\r\n",
+				    __func__);
+			goto Out;
+		}
+
+		/* Increment Buffer Write Interrupt Count */
+		BufRwCnt++;
+
+		if (BufRwCnt == PktCount)
+			XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+				XNANDPSU_INTR_STS_EN_OFFSET,
+				XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
+
+		else
+			XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+				XNANDPSU_INTR_STS_EN_OFFSET, 0U);
+		/*
+	         * Clear Buffer Write Ready Interrupt in Interrupt Status
+		 * Register
+		 */
+		XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_INTR_STS_OFFSET, Event);
+		/* Write Packet Data to Data Port Register */
+		if (Operation)
+			XNandPsu_Fifo_Write(InstancePtr, Buf, PktSize);
+		else
+			XNandPsu_Fifo_Read(InstancePtr, Buf, PktSize);
+
+		Buf += PktSize;
+
+		if (BufRwCnt < PktCount)
+			XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+				XNANDPSU_INTR_STS_EN_OFFSET, Event);
+		else
+			break;
+	}
+
+DmaDone:
+	Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function writes data to the fifo.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Buf is the buffer pointer.
+* @param	Size of the Buffer.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_Fifo_Write(XNandPsu *InstancePtr, u8* Buffer, u32 Size)
+{
+	u32 *BufPtr = (u32 *)(void *)Buffer;
+	u32 Index;
+
+	for (Index = 0U; Index < Size/4U; Index++)
+		XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+				XNANDPSU_BUF_DATA_PORT_OFFSET,
+				BufPtr[Index]);
+}
+
+/*****************************************************************************/
+/**
+*
+* This function reads data from the fifo.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Buf is the buffer pointer.
+* @param	Size of the Buffer.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_Fifo_Read(XNandPsu *InstancePtr, u8* Buf, u32 Size)
+{
+	u32 *BufPtr = (u32 *)(void *)Buf;
+	u32 Index;
+
+	for (Index = 0U; Index < Size/4U; Index++)
+		BufPtr[Index] = XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
+					XNANDPSU_BUF_DATA_PORT_OFFSET);
+}
+
+/*****************************************************************************/
+/**
+*
+* This function configures the given dma address to the controller.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Buf is the buffer pointer.
+*
+* @return
+*		None
+*
+* @note		None
+*
+******************************************************************************/
+static void XNandPsu_Update_DmaAddr(XNandPsu *InstancePtr, u8* Buf)
+{
+#if defined(__aarch64__) || defined(__arch64__)
+		XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+				XNANDPSU_DMA_SYS_ADDR1_OFFSET,
+				(u32) (((INTPTR)Buf >> 32U) & 0xFFFFFFFFU));
+#endif
+		XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
+				XNANDPSU_DMA_SYS_ADDR0_OFFSET,
+				(u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU));
+
+}
+
+/*****************************************************************************/
+/**
+*
+* This function waits for the device ready stataus.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Target is the chipselect value.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		None
+*
+******************************************************************************/
+static s32 XNandPsu_Device_Ready(XNandPsu *InstancePtr, u32 Target)
+{
+	s32 Status = XST_SUCCESS;
+	u16 OnfiStatus = 0U;
+
+	do {
+		Status = XNandPsu_OnfiReadStatus(InstancePtr, Target,
+							&OnfiStatus);
+		if (Status != XST_SUCCESS)
+			goto Out;
+		if ((OnfiStatus & (1U << 6U)) != 0U) {
+			if ((OnfiStatus & (1U << 0U)) != 0U) {
+				Status = XST_FAILURE;
+				goto Out;
+			}
+		}
+	} while (((OnfiStatus >> 6U) & 0x1U) == 0U);
+
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function waits for the  transfer complete event.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if failed.
+*
+* @note		Expects that transfer complete event was set before calling
+* 		this function.
+*
+******************************************************************************/
+static s32 XNandPsu_WaitFor_Transfer_Complete(XNandPsu *InstancePtr)
+{
+s32 Status = XST_FAILURE;
+
+	 /* Poll for Transfer Complete event */
+	Status = XNandPsu_PollRegTimeout(
+			InstancePtr,
+			XNANDPSU_INTR_STS_OFFSET,
+			XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
+			XNANDPSU_INTR_POLL_TIMEOUT);
+	if (Status != XST_SUCCESS) {
+		xil_printf("%s: Poll for xfer complete timeout\r\n", __func__);
+		goto Out;
+	}
+
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+		XNANDPSU_INTR_STS_EN_OFFSET, 0U);
+
+	XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
+			XNANDPSU_INTR_STS_OFFSET,
+			XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
+#if defined  (XCLOCKING)
+	Xil_ClockDisable(InstancePtr->Config.RefClk);
+#endif
+Out:
+	return Status;
+}
+/** @} */
diff --git a/bsps/shared/dev/nand/xnandpsu_bbm.c b/bsps/shared/dev/nand/xnandpsu_bbm.c
new file mode 100644
index 0000000000..c43a2ba62f
--- /dev/null
+++ b/bsps/shared/dev/nand/xnandpsu_bbm.c
@@ -0,0 +1,912 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu_bbm.c
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* This file implements the Bad Block Management (BBM) functionality.
+* See xnandpsu_bbm.h for more details.
+*
+* @note		None
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date        Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* 2.0   sb     01/12/2015  Added support for writing BBT signature and version
+*			   in page section by enabling XNANDPSU_BBT_NO_OOB.
+*			   Modified Bbt Signature and Version Offset value for
+*			   Oob and No-Oob region.
+* 1.1	nsk    11/07/16    Change memcpy to Xil_MemCpy to handle word aligned
+*	                   data access.
+* 1.4	nsk    04/10/18    Added ICCARM compiler support.
+* 1.10	akm    01/05/22    Remove assert checks form static and internal APIs.
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+#include <string.h>	/**< For Xil_MemCpy and memset */
+#include "xil_types.h"
+#include "xnandpsu.h"
+#include "xnandpsu_bbm.h"
+#include "xil_mem.h"
+
+/************************** Constant Definitions *****************************/
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target);
+
+static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
+							u32 Target);
+
+static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target);
+
+static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target);
+
+static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
+				XNandPsu_BbtDesc *MirrorDesc, u32 Target);
+
+static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
+							u32 Target);
+
+static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target);
+
+/************************** Variable Definitions *****************************/
+
+/*****************************************************************************/
+/**
+* This function initializes the Bad Block Table(BBT) descriptors with a
+* predefined pattern for searching Bad Block Table(BBT) in flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		- NONE
+*
+******************************************************************************/
+void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr)
+{
+	u32 Index;
+
+	/* Initialize primary Bad Block Table(BBT) */
+	for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
+		InstancePtr->BbtDesc.PageOffset[Index] =
+						XNANDPSU_BBT_DESC_PAGE_OFFSET;
+	}
+	if (InstancePtr->EccMode == XNANDPSU_ONDIE) {
+		InstancePtr->BbtDesc.SigOffset = XNANDPSU_ONDIE_SIG_OFFSET;
+		InstancePtr->BbtDesc.VerOffset = XNANDPSU_ONDIE_VER_OFFSET;
+	} else {
+		InstancePtr->BbtDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET;
+		InstancePtr->BbtDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET;
+	}
+	InstancePtr->BbtDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN;
+	InstancePtr->BbtDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS;
+	(void)strcpy(&InstancePtr->BbtDesc.Signature[0], "Bbt0");
+	for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
+		InstancePtr->BbtDesc.Version[Index] = 0U;
+	}
+	InstancePtr->BbtDesc.Valid = 0U;
+
+	/* Assuming that the flash device will have at least 4 blocks. */
+	if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
+							BbtDesc.MaxBlocks){
+		InstancePtr->BbtDesc.MaxBlocks = 4U;
+	}
+
+	/* Initialize mirror Bad Block Table(BBT) */
+	for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
+		InstancePtr->BbtMirrorDesc.PageOffset[Index] =
+						XNANDPSU_BBT_DESC_PAGE_OFFSET;
+	}
+	if (InstancePtr->EccMode == XNANDPSU_ONDIE) {
+		InstancePtr->BbtMirrorDesc.SigOffset =
+					XNANDPSU_ONDIE_SIG_OFFSET;
+		InstancePtr->BbtMirrorDesc.VerOffset =
+					XNANDPSU_ONDIE_VER_OFFSET;
+	} else {
+		InstancePtr->BbtMirrorDesc.SigOffset =
+					XNANDPSU_BBT_DESC_SIG_OFFSET;
+		InstancePtr->BbtMirrorDesc.VerOffset =
+					XNANDPSU_BBT_DESC_VER_OFFSET;
+	}
+	InstancePtr->BbtMirrorDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN;
+	InstancePtr->BbtMirrorDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS;
+	(void)strcpy(&InstancePtr->BbtMirrorDesc.Signature[0], "1tbB");
+	for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
+		InstancePtr->BbtMirrorDesc.Version[Index] = 0U;
+	}
+	InstancePtr->BbtMirrorDesc.Valid = 0U;
+
+	/* Assuming that the flash device will have at least 4 blocks. */
+	if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
+						BbtMirrorDesc.MaxBlocks){
+		InstancePtr->BbtMirrorDesc.MaxBlocks = 4U;
+	}
+
+	/* Initialize Bad block search pattern structure */
+	if (InstancePtr->Geometry.BytesPerPage > 512U) {
+		/* For flash page size > 512 bytes */
+		InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE;
+		InstancePtr->BbPattern.Offset =
+			XNANDPSU_BB_PTRN_OFF_LARGE_PAGE;
+		InstancePtr->BbPattern.Length =
+			XNANDPSU_BB_PTRN_LEN_LARGE_PAGE;
+	} else {
+		InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE;
+		InstancePtr->BbPattern.Offset =
+			XNANDPSU_BB_PTRN_OFF_SML_PAGE;
+		InstancePtr->BbPattern.Length =
+			XNANDPSU_BB_PTRN_LEN_SML_PAGE;
+	}
+	for(Index = 0U; Index < XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; Index++) {
+		InstancePtr->BbPattern.Pattern[Index] = XNANDPSU_BB_PATTERN;
+	}
+}
+
+/*****************************************************************************/
+/**
+* This function scans the NAND flash for factory marked bad blocks and creates
+* a RAM based Bad Block Table(BBT).
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		- NONE
+*
+******************************************************************************/
+static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target)
+{
+	u32 BlockIndex;
+	u32 PageIndex;
+	u32 Length;
+	u32 BlockOffset;
+	u8 BlockShift;
+	u32 NumPages;
+	u32 Page;
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+	u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U};
+#pragma pack(pop)
+#else
+	u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
+#endif
+	u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
+	u32 NumBlocks = InstancePtr->Geometry.NumTargetBlocks;
+	s32 Status;
+
+	/* Number of pages to search for bad block pattern */
+	if ((InstancePtr->BbPattern.Options & XNANDPSU_BBT_SCAN_2ND_PAGE) != 0U)
+	{
+		NumPages = 2U;
+	} else {
+		NumPages = 1U;
+	}
+	/* Scan all the blocks for factory marked bad blocks */
+	for(BlockIndex = StartBlock; BlockIndex < (StartBlock + NumBlocks);
+							BlockIndex++) {
+		/* Block offset in Bad Block Table(BBT) entry */
+		BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
+		/* Block shift value in the byte */
+		BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
+		Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock;
+		/* Search for the bad block pattern */
+		for(PageIndex = 0U; PageIndex < NumPages; PageIndex++) {
+			Status = XNandPsu_ReadSpareBytes(InstancePtr,
+					(Page + PageIndex), &Buf[0]);
+
+			if (Status != XST_SUCCESS) {
+				/* Marking as bad block */
+				InstancePtr->Bbt[BlockOffset] |=
+					(u8)(XNANDPSU_BLOCK_FACTORY_BAD <<
+					 BlockShift);
+				break;
+			}
+			/*
+			 * Read the spare bytes to check for bad block
+			 * pattern
+			 */
+			for(Length = 0U; Length <
+				InstancePtr->BbPattern.Length; Length++) {
+				if (Buf[InstancePtr->BbPattern.Offset + Length]
+						!=
+					InstancePtr->BbPattern.Pattern[Length])
+				{
+					/* Bad block found */
+					InstancePtr->Bbt[BlockOffset] |=
+						(u8)
+						(XNANDPSU_BLOCK_FACTORY_BAD <<
+						 BlockShift);
+					break;
+				}
+			}
+		}
+	}
+}
+
+/*****************************************************************************/
+/**
+* This function reads the Bad Block Table(BBT) if present in flash. If not it
+* scans the flash for detecting factory marked bad blocks and creates a bad
+* block table and write the Bad Block Table(BBT) into the flash.
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr)
+{
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
+
+	s32 Status;
+	u32 Index;
+	u32 BbtLen;
+
+	/* Zero the RAM based Bad Block Table(BBT) entries */
+	BbtLen = InstancePtr->Geometry.NumBlocks >>
+					XNANDPSU_BBT_BLOCK_SHIFT;
+	(void)memset(&InstancePtr->Bbt[0], 0, BbtLen);
+
+	for (Index = 0U; Index < InstancePtr->Geometry.NumTargets; Index++) {
+
+		if (XNandPsu_ReadBbt(InstancePtr, Index) != XST_SUCCESS) {
+			/* Create memory based Bad Block Table(BBT) */
+			XNandPsu_CreateBbt(InstancePtr, Index);
+			/* Write the Bad Block Table(BBT) to the flash */
+			Status = XNandPsu_WriteBbt(InstancePtr,
+					&InstancePtr->BbtDesc,
+					&InstancePtr->BbtMirrorDesc, Index);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			/* Write the Mirror Bad Block Table(BBT) to the flash */
+			Status = XNandPsu_WriteBbt(InstancePtr,
+					&InstancePtr->BbtMirrorDesc,
+					&InstancePtr->BbtDesc, Index);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			/*
+			 * Mark the blocks containing Bad Block Table
+			 * (BBT) as Reserved
+			 */
+			Status = XNandPsu_MarkBbt(InstancePtr,
+							&InstancePtr->BbtDesc,
+							Index);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			Status = XNandPsu_MarkBbt(InstancePtr,
+						&InstancePtr->BbtMirrorDesc,
+							Index);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+		}
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+* This function converts the Bad Block Table(BBT) read from the flash to the
+* RAM based Bad Block Table(BBT).
+*
+* @param	InstancePtr is a pointer to the XNandPsu instance.
+* @param	Buf is the buffer which contains BBT read from flash.
+*
+* @return
+*		- NONE.
+*
+******************************************************************************/
+static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target)
+{
+	u32 BlockOffset;
+	u8 BlockShift;
+	u32 Data;
+	u8 BlockType;
+	u32 BlockIndex;
+	u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >>
+					XNANDPSU_BBT_BLOCK_SHIFT;
+	u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
+
+	for(BlockOffset = StartBlock; BlockOffset < (StartBlock + BbtLen);
+						BlockOffset++) {
+		Data = *(Buf + BlockOffset);
+		/* Clear the RAM based Bad Block Table(BBT) contents */
+		InstancePtr->Bbt[BlockOffset] = 0x0U;
+		/* Loop through the every 4 blocks in the bitmap */
+		for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
+				BlockIndex++) {
+			BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
+			BlockType = (u8) ((Data >> BlockShift) &
+				XNANDPSU_BLOCK_TYPE_MASK);
+			switch(BlockType) {
+				case XNANDPSU_FLASH_BLOCK_FAC_BAD:
+					/* Factory bad block */
+					InstancePtr->Bbt[BlockOffset] |=
+						(u8)
+						(XNANDPSU_BLOCK_FACTORY_BAD <<
+						BlockShift);
+					break;
+				case XNANDPSU_FLASH_BLOCK_RESERVED:
+					/* Reserved block */
+					InstancePtr->Bbt[BlockOffset] |=
+						(u8)
+						(XNANDPSU_BLOCK_RESERVED <<
+						BlockShift);
+					break;
+				case XNANDPSU_FLASH_BLOCK_BAD:
+					/* Bad block due to wear */
+					InstancePtr->Bbt[BlockOffset] |=
+						(u8)(XNANDPSU_BLOCK_BAD <<
+						BlockShift);
+					break;
+				default:
+					/* Good block */
+					/* The BBT entry already defaults to
+					 * zero */
+					break;
+			}
+		}
+	}
+}
+
+/*****************************************************************************/
+/**
+* This function searches the Bad Bloock Table(BBT) in flash and loads into the
+* memory based Bad Block Table(BBT).
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target)
+{
+	u64 Offset;
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+	u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U};
+#pragma pack(pop)
+#else
+	u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U};
+#endif
+	s32 Status1;
+	s32 Status2;
+	s32 Status;
+	u32 BufLen;
+
+	XNandPsu_BbtDesc *Desc = &InstancePtr->BbtDesc;
+	XNandPsu_BbtDesc *MirrorDesc = &InstancePtr->BbtMirrorDesc;
+	BufLen = InstancePtr->Geometry.NumBlocks >>
+			XNANDPSU_BBT_BLOCK_SHIFT;
+	/* Search the Bad Block Table(BBT) in flash */
+	Status1 = XNandPsu_SearchBbt(InstancePtr, Desc, Target);
+	Status2 = XNandPsu_SearchBbt(InstancePtr, MirrorDesc, Target);
+	if ((Status1 != XST_SUCCESS) && (Status2 != XST_SUCCESS)) {
+#ifdef XNANDPSU_DEBUG
+		xil_printf("%s: Bad block table not found\r\n",__func__);
+#endif
+		Status = XST_FAILURE;
+		goto Out;
+	}
+#ifdef XNANDPSU_DEBUG
+	xil_printf("%s: Bad block table found\r\n",__func__);
+#endif
+	/* Bad Block Table found */
+	if ((Desc->Valid != 0U) && (MirrorDesc->Valid != 0U)) {
+		/* Valid BBT & Mirror BBT found */
+		if (Desc->Version[Target] > MirrorDesc->Version[Target]) {
+			Offset = (u64)Desc->PageOffset[Target] *
+				(u64)InstancePtr->Geometry.BytesPerPage;
+			Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
+								&Buf[0]);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			/* Convert flash BBT to memory based BBT */
+			XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
+			MirrorDesc->Version[Target] = Desc->Version[Target];
+
+			/* Write the BBT to Mirror BBT location in flash */
+			Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc,
+							Desc, Target);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+		} else if (Desc->Version[Target] <
+						MirrorDesc->Version[Target]) {
+			Offset = (u64)MirrorDesc->PageOffset[Target] *
+				(u64)InstancePtr->Geometry.BytesPerPage;
+			Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
+								&Buf[0]);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			/* Convert flash BBT to memory based BBT */
+			XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
+			Desc->Version[Target] = MirrorDesc->Version[Target];
+
+			/* Write the Mirror BBT to BBT location in flash */
+			Status = XNandPsu_WriteBbt(InstancePtr, Desc,
+							MirrorDesc, Target);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+		} else {
+			/* Both are up-to-date */
+			Offset = (u64)Desc->PageOffset[Target] *
+				(u64)InstancePtr->Geometry.BytesPerPage;
+			Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
+								&Buf[0]);
+			if (Status != XST_SUCCESS) {
+				goto Out;
+			}
+			/* Convert flash BBT to memory based BBT */
+			XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
+		}
+	} else if (Desc->Valid != 0U) {
+		/* Valid Primary BBT found */
+		Offset = (u64)Desc->PageOffset[Target] *
+			(u64)InstancePtr->Geometry.BytesPerPage;
+		Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+		/* Convert flash BBT to memory based BBT */
+		XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
+		MirrorDesc->Version[Target] = Desc->Version[Target];
+
+		/* Write the BBT to Mirror BBT location in flash */
+		Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc,
+								Target);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+	} else {
+		/* Valid Mirror BBT found */
+		Offset = (u64)MirrorDesc->PageOffset[Target] *
+			(u64)InstancePtr->Geometry.BytesPerPage;
+		Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+		/* Convert flash BBT to memory based BBT */
+		XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
+		Desc->Version[Target] = MirrorDesc->Version[Target];
+
+		/* Write the Mirror BBT to BBT location in flash */
+		Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc,
+								Target);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+* This function searches the BBT in flash.
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+* @param	Desc is the BBT descriptor pattern to search.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
+								u32 Target)
+{
+	u32 StartBlock;
+	u32 SigOffset;
+	u32 VerOffset;
+	u32 MaxBlocks;
+	u32 PageOff;
+	u32 SigLength;
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+	u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U};
+#pragma pack(pop)
+#else
+	u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
+#endif
+	u32 Block;
+	u32 Offset;
+	s32 Status;
+
+	StartBlock = ((Target + (u32)1) *
+				InstancePtr->Geometry.NumTargetBlocks) - (u32)1;
+	SigOffset = Desc->SigOffset;
+	VerOffset = Desc->VerOffset;
+	MaxBlocks = Desc->MaxBlocks;
+	SigLength = Desc->SigLength;
+
+	/* Read the last 4 blocks for Bad Block Table(BBT) signature */
+	for(Block = 0U; Block < MaxBlocks; Block++) {
+		PageOff = (StartBlock - Block) *
+			InstancePtr->Geometry.PagesPerBlock;
+
+			Status = XNandPsu_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]);
+		if (Status != XST_SUCCESS) {
+			continue;
+		}
+		/* Check the Bad Block Table(BBT) signature */
+		for(Offset = 0U; Offset < SigLength; Offset++) {
+			if (Buf[Offset + SigOffset] !=
+				(u8)(Desc->Signature[Offset]))
+			{
+				break; /* Check the next blocks */
+			}
+		}
+		if (Offset >= SigLength) {
+			/* Bad Block Table(BBT) found */
+			Desc->PageOffset[Target] = PageOff;
+			Desc->Version[Target] = Buf[VerOffset];
+			Desc->Valid = 1U;
+
+			Status = XST_SUCCESS;
+			goto Out;
+		}
+	}
+	/* Bad Block Table(BBT) not found */
+	Status = XST_FAILURE;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+* This function writes Bad Block Table(BBT) from RAM to flash.
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+* @param	Desc is the BBT descriptor to be written to flash.
+* @param	MirrorDesc is the mirror BBT descriptor.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
+				XNandPsu_BbtDesc *MirrorDesc, u32 Target)
+{
+	u64 Offset;
+	u32 Block = {0U};
+	u32 EndBlock = ((Target + (u32)1) *
+			InstancePtr->Geometry.NumTargetBlocks) - (u32)1;
+#ifdef __ICCARM__
+#pragma pack(push, 1)
+	u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U};
+	u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE]= {0U};
+#pragma pack(pop)
+#else
+	u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U};
+	u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
+#endif
+
+	u8 Mask[4] = {0x00U, 0x01U, 0x02U, 0x03U};
+	u8 Data;
+	u32 BlockOffset;
+	u8 BlockShift;
+	s32 Status;
+	u32 BlockIndex;
+	u32 Index;
+	u8 BlockType;
+	u32 BbtLen = InstancePtr->Geometry.NumBlocks >>
+						XNANDPSU_BBT_BLOCK_SHIFT;
+	/* Find a valid block to write the Bad Block Table(BBT) */
+	if ((!Desc->Valid) != 0U) {
+		for(Index = 0U; Index < Desc->MaxBlocks; Index++) {
+			Block  = (EndBlock - Index);
+			BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
+			BlockShift = XNandPsu_BbtBlockShift(Block);
+			BlockType = (InstancePtr->Bbt[BlockOffset] >>
+					BlockShift) & XNANDPSU_BLOCK_TYPE_MASK;
+			switch(BlockType)
+			{
+				case XNANDPSU_BLOCK_BAD:
+				case XNANDPSU_BLOCK_FACTORY_BAD:
+					continue;
+				default:
+					/* Good Block */
+					break;
+			}
+			Desc->PageOffset[Target] = Block *
+				InstancePtr->Geometry.PagesPerBlock;
+			if (Desc->PageOffset[Target] !=
+					MirrorDesc->PageOffset[Target]) {
+				/* Free block found */
+				Desc->Valid = 1U;
+				break;
+			}
+		}
+
+
+		/* Block not found for writing Bad Block Table(BBT) */
+		if (Index >= Desc->MaxBlocks) {
+#ifdef XNANDPSU_DEBUG
+		xil_printf("%s: Blocks unavailable for writing BBT\r\n",
+								__func__);
+#endif
+			Status = XST_FAILURE;
+			goto Out;
+		}
+	} else {
+		Block = Desc->PageOffset[Target] /
+					InstancePtr->Geometry.PagesPerBlock;
+	}
+	/* Convert the memory based BBT to flash based table */
+	(void)memset(Buf, 0xff, BbtLen);
+
+	/* Loop through the number of blocks */
+	for(BlockOffset = 0U; BlockOffset < BbtLen; BlockOffset++) {
+		Data = InstancePtr->Bbt[BlockOffset];
+		/* Calculate the bit mask for 4 blocks at a time in loop */
+		for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
+				BlockIndex++) {
+			BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
+			Buf[BlockOffset] &= ~(Mask[Data &
+					XNANDPSU_BLOCK_TYPE_MASK] <<
+					BlockShift);
+			Data >>= XNANDPSU_BBT_BLOCK_SHIFT;
+		}
+	}
+	/* Write the Bad Block Table(BBT) to flash */
+	Status = XNandPsu_EraseBlock(InstancePtr, 0U, Block);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	/* Write the BBT to page offset */
+	Offset = (u64)Desc->PageOffset[Target] *
+			(u64)InstancePtr->Geometry.BytesPerPage;
+	Status = XNandPsu_Write(InstancePtr, Offset, BbtLen, &Buf[0]);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+	/* Write the signature and version in the spare data area */
+	(void)memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage);
+	Status = XNandPsu_ReadSpareBytes(InstancePtr, Desc->PageOffset[Target],
+					 &SpareBuf[0]);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	(void)Xil_MemCpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0],
+							Desc->SigLength);
+	(void)memcpy(SpareBuf + Desc->VerOffset, &Desc->Version[Target], 1U);
+
+	Status = XNandPsu_WriteSpareBytes(InstancePtr,
+				Desc->PageOffset[Target], &SpareBuf[0]);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+* This function updates the primary and mirror Bad Block Table(BBT) in the
+* flash.
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target)
+{
+	s32 Status;
+	u8 Version;
+
+	/* Update the version number */
+	Version = InstancePtr->BbtDesc.Version[Target];
+	InstancePtr->BbtDesc.Version[Target] = (u8)(((u16)Version +
+							(u16)1) % (u16)256U);
+
+	Version = InstancePtr->BbtMirrorDesc.Version[Target];
+	InstancePtr->BbtMirrorDesc.Version[Target] = (u8)(((u16)Version +
+							(u16)1) % (u16)256);
+	/* Update the primary Bad Block Table(BBT) in flash */
+	Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtDesc,
+						&InstancePtr->BbtMirrorDesc,
+						Target);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	/* Update the mirrored Bad Block Table(BBT) in flash */
+	Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc,
+						&InstancePtr->BbtDesc,
+						Target);
+	if (Status != XST_SUCCESS) {
+		goto Out;
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+* This function marks the block containing Bad Block Table as reserved
+* and updates the BBT.
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+* @param	Desc is the BBT descriptor pointer.
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
+								u32 Target)
+{
+	u32 BlockIndex;
+	u32 BlockOffset;
+	u8 BlockShift;
+	u8 OldVal;
+	u8 NewVal;
+	s32 Status;
+	u32 UpdateBbt = 0U;
+	u32 Index;
+
+	/* Mark the last four blocks as Reserved */
+	BlockIndex = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) -
+						Desc->MaxBlocks - (u32)1;
+
+	for(Index = 0U; Index < Desc->MaxBlocks; Index++) {
+
+		BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
+		BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
+		OldVal = InstancePtr->Bbt[BlockOffset];
+		NewVal = (u8) (OldVal | (XNANDPSU_BLOCK_RESERVED <<
+							BlockShift));
+		InstancePtr->Bbt[BlockOffset] = NewVal;
+
+		if (OldVal != NewVal) {
+			UpdateBbt = 1U;
+		}
+		BlockIndex++;
+	}
+
+	/* Update the BBT to flash */
+	if (UpdateBbt != 0U) {
+		Status = XNandPsu_UpdateBbt(InstancePtr, Target);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function checks whether a block is bad or not.
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+*
+* @param	Block is the block number.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block)
+{
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
+	Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
+
+	u8 Data;
+	u8 BlockShift;
+	u8 BlockType;
+	u32 BlockOffset;
+	s32 Status;
+
+	BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
+	BlockShift = XNandPsu_BbtBlockShift(Block);
+	Data = InstancePtr->Bbt[BlockOffset];	/* Block information in BBT */
+	BlockType = (Data >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK;
+
+	if ((BlockType != XNANDPSU_BLOCK_GOOD) &&
+		(BlockType != XNANDPSU_BLOCK_RESERVED)) {
+		Status = XST_SUCCESS;
+	}
+	else {
+		Status = XST_FAILURE;
+	}
+	return Status;
+}
+
+/*****************************************************************************/
+/**
+* This function marks a block as bad in the RAM based Bad Block Table(BBT). It
+* also updates the Bad Block Table(BBT) in the flash.
+*
+* @param	InstancePtr is the pointer to the XNandPsu instance.
+* @param	Block is the block number.
+*
+* @return
+*		- XST_SUCCESS if successful.
+*		- XST_FAILURE if fail.
+*
+******************************************************************************/
+s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block)
+{
+	Xil_AssertNonvoid(InstancePtr != NULL);
+	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
+	Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
+
+	u8 Data;
+	u8 BlockShift;
+	u32 BlockOffset;
+	u8 OldVal;
+	u8 NewVal;
+	s32 Status;
+	u32 Target;
+
+	Target = Block / InstancePtr->Geometry.NumTargetBlocks;
+
+	BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
+	BlockShift = XNandPsu_BbtBlockShift(Block);
+	Data = InstancePtr->Bbt[BlockOffset];	/* Block information in BBT */
+
+	/* Mark the block as bad in the RAM based Bad Block Table */
+	OldVal = Data;
+	Data &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift);
+	Data |= (XNANDPSU_BLOCK_BAD << BlockShift);
+	NewVal = Data;
+	InstancePtr->Bbt[BlockOffset] = Data;
+
+	/* Update the Bad Block Table(BBT) in flash */
+	if (OldVal != NewVal) {
+		Status = XNandPsu_UpdateBbt(InstancePtr, Target);
+		if (Status != XST_SUCCESS) {
+			goto Out;
+		}
+	}
+
+	Status = XST_SUCCESS;
+Out:
+	return Status;
+}
+/** @} */
diff --git a/bsps/shared/dev/nand/xnandpsu_g.c b/bsps/shared/dev/nand/xnandpsu_g.c
new file mode 100644
index 0000000000..2fb2a2a26e
--- /dev/null
+++ b/bsps/shared/dev/nand/xnandpsu_g.c
@@ -0,0 +1,47 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu_g.c
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* This file contains a configuration table where each entry is a configuration
+* structure for an XNandPsu device in the system.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* 1.0   nm     06/02/2014  Changed the copyright to new copyright
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files ********************************/
+#include "xparameters.h"
+#include "xnandpsu.h"
+/************************** Constant Definitions ****************************/
+
+/**************************** Type Definitions ******************************/
+
+/***************** Macros (Inline Functions) Definitions ********************/
+
+/************************** Variable Definitions ****************************/
+
+/**
+ * Each XNandPsu device in the system has an entry in this table.
+ */
+XNandPsu_Config XNandPsu_ConfigTable[] = {
+	{
+		0U,
+		(u32)XPAR_XNANDPSU_0_BASEADDR
+	}
+};
+/** @} */
diff --git a/bsps/shared/dev/nand/xnandpsu_onfi.c b/bsps/shared/dev/nand/xnandpsu_onfi.c
new file mode 100644
index 0000000000..cd230f247f
--- /dev/null
+++ b/bsps/shared/dev/nand/xnandpsu_onfi.c
@@ -0,0 +1,91 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu_onfi.c
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* This file contains the implementation of ONFI specific functions.
+*
+* @note		None
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+#include "xnandpsu_onfi.h"
+#include "xnandpsu.h"
+
+/************************** Constant Definitions *****************************/
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+/**
+*
+* This function calculates ONFI parameter page CRC.
+*
+* @param	ParamBuf is a pointer to the ONFI parameter page buffer.
+* @param	StartOff is the starting offset in buffer to calculate CRC.
+* @param	Length is the number of bytes for which CRC is calculated.
+*
+* @return
+*		CRC value.
+* @note
+*		None.
+*
+******************************************************************************/
+u32 XNandPsu_OnfiParamPageCrc(u8 *ParamBuf, u32 StartOff, u32 Length)
+{
+	const u32 CrcInit = 0x4F4EU;
+	const u32 Order = 16U;
+	const u32 Polynom = 0x8005U;
+	u32 i, j, c, Bit;
+	u32 Crc = CrcInit;
+	u32 DataIn;
+	u32 DataByteCount = 0U;
+	u32 CrcMask, CrcHighBit;
+
+	CrcMask = ((u32)(((u32)1 << (Order - (u32)1)) -(u32)1) << (u32)1) | (u32)1;
+	CrcHighBit = (u32)((u32)1 << (Order - (u32)1));
+	/*
+	 * CRC covers the data bytes between byte 0 and byte 253
+	 * (ONFI 1.0, section 5.4.1.36)
+	 */
+	for(i = StartOff; i < Length; i++) {
+		DataIn = *(ParamBuf + i);
+		c = (u32)DataIn;
+		DataByteCount++;
+		j = 0x80U;
+		while(j != 0U) {
+			Bit = Crc & CrcHighBit;
+			Crc <<= 1U;
+			if ((c & j) != 0U) {
+				Bit ^= CrcHighBit;
+			}
+			if (Bit != 0U) {
+				Crc ^= Polynom;
+			}
+			j >>= 1U;
+		}
+		Crc &= CrcMask;
+	}
+	return Crc;
+}
+/** @} */
diff --git a/bsps/shared/dev/nand/xnandpsu_sinit.c b/bsps/shared/dev/nand/xnandpsu_sinit.c
new file mode 100644
index 0000000000..dd6b14ef10
--- /dev/null
+++ b/bsps/shared/dev/nand/xnandpsu_sinit.c
@@ -0,0 +1,70 @@
+/******************************************************************************
+* Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+*
+* @file xnandpsu_sinit.c
+* @addtogroup nandpsu_v1_10
+* @{
+*
+* The implementation of the XNandPsu driver's static initialization
+* functionality.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.0   nm     05/06/2014  First release
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files ********************************/
+#include "xstatus.h"
+#include "xparameters.h"
+#include "xnandpsu.h"
+/************************** Constant Definitions ****************************/
+
+/**************************** Type Definitions ******************************/
+
+/***************** Macros (Inline Functions) Definitions ********************/
+
+/************************** Variable Definitions ****************************/
+
+extern XNandPsu_Config XNandPsu_ConfigTable[];
+
+/************************** Function Prototypes *****************************/
+
+/****************************************************************************/
+/**
+*
+* Looks up the controller configuration based on the unique controller ID. A
+* table contains the configuration info for each controller in the system.
+*
+* @param	DevID is the ID of the controller to look up the
+*		configuration for.
+*
+* @return
+*		A pointer to the configuration found or NULL if the specified
+*		controller ID was not found.
+*
+******************************************************************************/
+XNandPsu_Config *XNandPsu_LookupConfig(u16 DevID)
+{
+	XNandPsu_Config *CfgPtr = NULL;
+	u32 Index;
+
+	for (Index = 0U; Index < (u32)XPAR_XNANDPSU_NUM_INSTANCES; Index++) {
+		if (XNandPsu_ConfigTable[Index].DeviceId == DevID) {
+			CfgPtr = &XNandPsu_ConfigTable[Index];
+			break;
+		}
+	}
+
+	return (XNandPsu_Config *)CfgPtr;
+}
+/** @} */
diff --git a/spec/build/bsps/aarch64/xilinx-zynqmp/grp_zu3eg.yml b/spec/build/bsps/aarch64/xilinx-zynqmp/grp_zu3eg.yml
index 30cddaa0bb..41a5c9c596 100644
--- a/spec/build/bsps/aarch64/xilinx-zynqmp/grp_zu3eg.yml
+++ b/spec/build/bsps/aarch64/xilinx-zynqmp/grp_zu3eg.yml
@@ -10,6 +10,8 @@ includes: []
 install: []
 ldflags: []
 links:
+- role: build-dependency
+  uid: ../../objnandpsu
 - role: build-dependency
   uid: grp
 - role: build-dependency
diff --git a/spec/build/bsps/objnandpsu.yml b/spec/build/bsps/objnandpsu.yml
new file mode 100644
index 0000000000..60dc8f67cc
--- /dev/null
+++ b/spec/build/bsps/objnandpsu.yml
@@ -0,0 +1,33 @@
+SPDX-License-Identifier: CC-BY-SA-5.0 OR BSD-2-Clause
+build-type: objects
+cflags: []
+copyrights:
+- Copyright (C) 2022 On-Line Applications Research (OAR)
+cppflags: []
+cxxflags: []
+enabled-by: true
+includes:
+- bsps/include/dev/nand/
+- bsps/include/xil/
+- bsps/include/xil/${XIL_SUPPORT_PATH}/
+install:
+- destination: ${BSP_INCLUDEDIR}
+  source:
+  - bsps/include/dev/nand/xnandpsu_bbm.h
+  - bsps/include/dev/nand/xnandpsu.h
+  - bsps/include/dev/nand/xnandpsu_hw.h
+  - bsps/include/dev/nand/xnandpsu_onfi.h
+links:
+- role: build-dependency
+  uid: objxilinxsupport
+- role: build-dependency
+  uid: optnandpsu0baseaddress
+- role: build-dependency
+  uid: optnandpsunuminstances
+source:
+- bsps/shared/dev/nand/xnandpsu_bbm.c
+- bsps/shared/dev/nand/xnandpsu.c
+- bsps/shared/dev/nand/xnandpsu_g.c
+- bsps/shared/dev/nand/xnandpsu_onfi.c
+- bsps/shared/dev/nand/xnandpsu_sinit.c
+type: build
diff --git a/spec/build/bsps/optnandpsu0baseaddress.yml b/spec/build/bsps/optnandpsu0baseaddress.yml
new file mode 100644
index 0000000000..34668a39de
--- /dev/null
+++ b/spec/build/bsps/optnandpsu0baseaddress.yml
@@ -0,0 +1,18 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-integer: null
+- assert-uint32: null
+- env-assign: null
+- format-and-define: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
+default: 0xFF100000
+default-by-variant: []
+description: |
+  base address of NAND PSU 0
+enabled-by: true
+format: '{:#010x}'
+links: []
+name: XPAR_XNANDPSU_0_BASEADDR
+type: build
\ No newline at end of file
diff --git a/spec/build/bsps/optnandpsunuminstances.yml b/spec/build/bsps/optnandpsunuminstances.yml
new file mode 100644
index 0000000000..4d8cfa6b05
--- /dev/null
+++ b/spec/build/bsps/optnandpsunuminstances.yml
@@ -0,0 +1,18 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-integer: null
+- assert-uint32: null
+- env-assign: null
+- format-and-define: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
+default: 1
+default-by-variant: []
+description: |
+  Number of nand instances
+enabled-by: true
+format: '{:#010x}'
+links: []
+name: XPAR_XNANDPSU_NUM_INSTANCES
+type: build
\ No newline at end of file
-- 
2.30.2



More information about the devel mailing list