summaryrefslogtreecommitdiffstats
path: root/bsps
diff options
context:
space:
mode:
Diffstat (limited to 'bsps')
-rw-r--r--bsps/include/dev/nand/xnandpsu.h581
-rw-r--r--bsps/include/dev/nand/xnandpsu_bbm.h180
-rw-r--r--bsps/include/dev/nand/xnandpsu_hw.h483
-rw-r--r--bsps/include/dev/nand/xnandpsu_onfi.h316
-rw-r--r--bsps/shared/dev/nand/VERSION20
-rw-r--r--bsps/shared/dev/nand/xnandpsu.c2922
-rw-r--r--bsps/shared/dev/nand/xnandpsu_bbm.c912
-rw-r--r--bsps/shared/dev/nand/xnandpsu_g.c47
-rw-r--r--bsps/shared/dev/nand/xnandpsu_onfi.c91
-rw-r--r--bsps/shared/dev/nand/xnandpsu_sinit.c70
10 files changed, 5622 insertions, 0 deletions
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@xilinx.com>
+AuthorDate: Wed Apr 6 23:24:38 2022 -0600
+Commit: Siva Addepalli <sivaprasad.addepalli@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@xilinx.com>
+
+ Acked-by : Meena Paleti <meena.paleti@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;
+}
+/** @} */