Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:04

0001 /******************************************************************************
0002 * Copyright (C) 2015 - 2022 Xilinx, Inc.  All rights reserved.
0003 * SPDX-License-Identifier: MIT
0004 ******************************************************************************/
0005 
0006 /*****************************************************************************/
0007 /**
0008 *
0009 * @file xnandpsu.c
0010 * @addtogroup Overview
0011 * @{
0012 *
0013 * This file contains the implementation of the interface functions for
0014 * XNandPsu driver. Refer to the header file xnandpsu.h for more detailed
0015 * information.
0016 *
0017 * This module supports for NAND flash memory devices that conform to the
0018 * "Open NAND Flash Interface" (ONFI) 3.0 Specification. This modules
0019 * implements basic flash operations like read, write and erase.
0020 *
0021 * @note     Driver has been renamed to nandpsu after change in
0022 *       naming convention.
0023 *
0024 * <pre>
0025 * MODIFICATION HISTORY:
0026 *
0027 * Ver   Who    Date    Changes
0028 * ----- ----   ----------  -----------------------------------------------
0029 * 1.0   nm     05/06/2014  First release
0030 * 2.0   sb     01/12/2015  Removed Null checks for Buffer passed
0031 *              as parameter to Read API's
0032 *              - XNandPsu_Read()
0033 *              - XNandPsu_ReadPage
0034 *              Modified
0035 *              - XNandPsu_SetFeature()
0036 *              - XNandPsu_GetFeature()
0037 *              and made them public.
0038 *              Removed Failure Return for BCF Error check in
0039 *              XNandPsu_ReadPage() and added BCH_Error counter
0040 *              in the instance pointer structure.
0041 *              Added XNandPsu_Prepare_Cmd API
0042 *              Replaced
0043 *              - XNandPsu_IntrStsEnable
0044 *              - XNandPsu_IntrStsClear
0045 *              - XNandPsu_IntrClear
0046 *              - XNandPsu_SetProgramReg
0047 *              with XNandPsu_WriteReg call
0048 *              Modified xnandpsu.c file API's with above changes.
0049 *              Corrected the program command for Set Feature API.
0050 *              Modified
0051 *              - XNandPsu_OnfiReadStatus
0052 *              - XNandPsu_GetFeature
0053 *              - XNandPsu_SetFeature
0054 *              to add support for DDR mode.
0055 *              Changed Convention for SLC/MLC
0056 *              SLC --> HAMMING
0057 *              MLC --> BCH
0058 *              SlcMlc --> IsBCH
0059 *              Removed extra DMA mode initialization from
0060 *              the XNandPsu_CfgInitialize API.
0061 *              Modified
0062 *              - XNandPsu_SetEccAddrSize
0063 *              ECC address now is calculated based upon the
0064 *              size of spare area
0065 *              Modified Block Erase API, removed clearing of
0066 *              packet register before erase.
0067 *              Clearing Data Interface Register before
0068 *              XNandPsu_OnfiReset call.
0069 *              Modified XNandPsu_ChangeTimingMode API supporting
0070 *              SDR and NVDDR interface for timing modes 0 to 5.
0071 *              Modified Bbt Signature and Version Offset value for
0072 *              Oob and No-Oob region.
0073 * 1.0   kpc    17/6/2015   Added timer based timeout intsead of sw counter.
0074 * 1.1   mi     09/16/16 Removed compilation warnings with extra compiler flags.
0075 * 1.1   nsk    11/07/16    Change memcpy to Xil_MemCpy to handle word aligned
0076 *                      data access.
0077 * 1.2   nsk    01/19/17    Fix for the failure of reading nand first redundant
0078 *                      parameter page. CR#966603
0079 * 1.3   nsk    08/14/17    Added CCI support
0080 * 1.4   nsk    04/10/18    Added ICCARM compiler support. CR#997552.
0081 * 1.5   mus    11/05/18 Support 64 bit DMA addresses for Microblaze-X platform.
0082 * 1.5   mus    11/05/18 Updated XNandPsu_ChangeClockFreq to fix compilation
0083 *                       warnings.
0084 * 1.6   sd     06/02/20    Added Clock support
0085 * 1.6   sd     20/03/20    Added compilation flag
0086 * 1.8   sg     03/18/21    Added validation check for parameter page.
0087 * 1.9   akm    07/15/21    Initialize NandInstPtr with Data Interface & Timing mode info.
0088 * 1.10  akm    10/20/21    Fix gcc warnings.
0089 * 1.10  akm    12/21/21    Validate input parameters before use.
0090 * 1.10  akm    01/05/22    Remove assert checks form static and internal APIs.
0091 * 1.11  akm    03/31/22    Fix unused parameter warning.
0092 * 1.11  akm    03/31/22    Fix misleading-indentation warning.
0093 *
0094 * </pre>
0095 *
0096 ******************************************************************************/
0097 
0098 /***************************** Include Files *********************************/
0099 #include "xnandpsu.h"
0100 #include "xnandpsu_bbm.h"
0101 #ifndef __rtems__
0102 #include "sleep.h"
0103 #include "xil_mem.h"
0104 #endif
0105 /************************** Constant Definitions *****************************/
0106 
0107 static const XNandPsu_EccMatrix EccMatrix[] = {
0108     /* 512 byte page */
0109     {XNANDPSU_PAGE_SIZE_512, 9U, 1U, XNANDPSU_HAMMING, 0x20DU, 0x3U},
0110     {XNANDPSU_PAGE_SIZE_512, 9U, 4U, XNANDPSU_BCH, 0x209U, 0x7U},
0111     {XNANDPSU_PAGE_SIZE_512, 9U, 8U, XNANDPSU_BCH, 0x203U, 0xDU},
0112     /* 2K byte page */
0113     {XNANDPSU_PAGE_SIZE_2K, 9U, 1U, XNANDPSU_HAMMING, 0x834U, 0xCU},
0114     {XNANDPSU_PAGE_SIZE_2K, 9U, 4U, XNANDPSU_BCH, 0x826U, 0x1AU},
0115     {XNANDPSU_PAGE_SIZE_2K, 9U, 8U, XNANDPSU_BCH, 0x80cU, 0x34U},
0116     {XNANDPSU_PAGE_SIZE_2K, 9U, 12U, XNANDPSU_BCH, 0x822U, 0x4EU},
0117     {XNANDPSU_PAGE_SIZE_2K, 10U, 24U, XNANDPSU_BCH, 0x81cU, 0x54U},
0118     /* 4K byte page */
0119     {XNANDPSU_PAGE_SIZE_4K, 9U, 1U, XNANDPSU_HAMMING, 0x1068U, 0x18U},
0120     {XNANDPSU_PAGE_SIZE_4K, 9U, 4U, XNANDPSU_BCH, 0x104cU, 0x34U},
0121     {XNANDPSU_PAGE_SIZE_4K, 9U, 8U, XNANDPSU_BCH, 0x1018U, 0x68U},
0122     {XNANDPSU_PAGE_SIZE_4K, 9U, 12U, XNANDPSU_BCH, 0x1044U, 0x9CU},
0123     {XNANDPSU_PAGE_SIZE_4K, 10U, 24U, XNANDPSU_BCH, 0x1038U, 0xA8U},
0124     /* 8K byte page */
0125     {XNANDPSU_PAGE_SIZE_8K, 9U, 1U, XNANDPSU_HAMMING, 0x20d0U, 0x30U},
0126     {XNANDPSU_PAGE_SIZE_8K, 9U, 4U, XNANDPSU_BCH, 0x2098U, 0x68U},
0127     {XNANDPSU_PAGE_SIZE_8K, 9U, 8U, XNANDPSU_BCH, 0x2030U, 0xD0U},
0128     {XNANDPSU_PAGE_SIZE_8K, 9U, 12U, XNANDPSU_BCH, 0x2088U, 0x138U},
0129     {XNANDPSU_PAGE_SIZE_8K, 10U, 24U, XNANDPSU_BCH, 0x2070U, 0x150U},
0130     /* 16K byte page */
0131     {XNANDPSU_PAGE_SIZE_16K, 9U, 1U, XNANDPSU_HAMMING, 0x4460U, 0x60U},
0132     {XNANDPSU_PAGE_SIZE_16K, 9U, 4U, XNANDPSU_BCH, 0x43f0U, 0xD0U},
0133     {XNANDPSU_PAGE_SIZE_16K, 9U, 8U, XNANDPSU_BCH, 0x4320U, 0x1A0U},
0134     {XNANDPSU_PAGE_SIZE_16K, 9U, 12U, XNANDPSU_BCH, 0x4250U, 0x270U},
0135     {XNANDPSU_PAGE_SIZE_16K, 10U, 24U, XNANDPSU_BCH, 0x4220U, 0x2A0U}
0136 };
0137 
0138 /**************************** Type Definitions *******************************/
0139 /***************** Macros (Inline Functions) Definitions *********************/
0140 
0141 /************************** Function Prototypes ******************************/
0142 
0143 static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr);
0144 
0145 static s32 XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param);
0146 
0147 static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param);
0148 
0149 static void XNandPsu_InitDataInterface(XNandPsu *InstancePtr, OnfiParamPage *Param);
0150 
0151 static void XNandPsu_InitTimingMode(XNandPsu *InstancePtr, OnfiParamPage *Param);
0152 
0153 static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset,
0154                     u32 Mask, u32 Timeout);
0155 
0156 static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize,
0157                         u32 PktCount);
0158 
0159 static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col);
0160 
0161 static void XNandPsu_SetPageSize(XNandPsu *InstancePtr);
0162 
0163 static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target);
0164 
0165 static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target);
0166 
0167 static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target,
0168                             u16 *OnfiStatus);
0169 
0170 static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr,
0171                             u32 IdLen, u8 *Buf);
0172 
0173 static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target,
0174                         u8 *Buf);
0175 
0176 static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
0177                             u32 Col, u8 *Buf);
0178 
0179 static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
0180                             u32 Col, u8 *Buf);
0181 
0182 static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr);
0183 
0184 static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr);
0185 
0186 static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target,
0187                     u32 Col, u32 PktSize, u32 PktCount,
0188                     u8 *Buf);
0189 
0190 static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target,
0191                     u32 Col, u32 PktSize, u32 PktCount,
0192                     u8 *Buf);
0193 
0194 static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm);
0195 
0196 static s32 XNandPsu_Data_ReadWrite(XNandPsu *InstancePtr, u8* Buf, u32 PktCount,
0197                 u32 PktSize, u32 Operation, u8 DmaMode);
0198 
0199 static s32 XNandPsu_WaitFor_Transfer_Complete(XNandPsu *InstancePtr);
0200 
0201 static s32 XNandPsu_Device_Ready(XNandPsu *InstancePtr, u32 Target);
0202 
0203 static void XNandPsu_Fifo_Read(XNandPsu *InstancePtr, u8* Buf, u32 Size);
0204 
0205 static void XNandPsu_Fifo_Write(XNandPsu *InstancePtr, u8* Buf, u32 Size);
0206 
0207 static void XNandPsu_Update_DmaAddr(XNandPsu *InstancePtr, u8* Buf);
0208 /*****************************************************************************/
0209 /**
0210 *
0211 * This function initializes a specific XNandPsu instance. This function must
0212 * be called prior to using the NAND flash device to read or write any data.
0213 *
0214 * @param    InstancePtr is a pointer to the XNandPsu instance.
0215 * @param    ConfigPtr points to XNandPsu device configuration structure.
0216 * @param    EffectiveAddr is the base address of NAND flash controller.
0217 *
0218 * @return
0219 *       - XST_SUCCESS if successful.
0220 *       - XST_FAILURE if fail.
0221 *
0222 * @note     The user needs to first call the XNandPsu_LookupConfig() API
0223 *       which returns the Configuration structure pointer which is
0224 *       passed as a parameter to the XNandPsu_CfgInitialize() API.
0225 *
0226 ******************************************************************************/
0227 s32 XNandPsu_CfgInitialize(XNandPsu *InstancePtr, XNandPsu_Config *ConfigPtr,
0228                 u32 EffectiveAddr)
0229 {
0230     /* Assert the input arguments. */
0231     Xil_AssertNonvoid(InstancePtr != NULL);
0232     Xil_AssertNonvoid(ConfigPtr != NULL);
0233 
0234     s32 Status = XST_FAILURE;
0235 
0236     /* Initialize InstancePtr Config structure */
0237     InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;
0238     InstancePtr->Config.BaseAddress = EffectiveAddr;
0239     InstancePtr->Config.IsCacheCoherent = ConfigPtr->IsCacheCoherent;
0240 #if defined  (XCLOCKING)
0241     InstancePtr->Config.RefClk = ConfigPtr->RefClk;
0242 #endif
0243     /* Operate in Polling Mode */
0244     InstancePtr->Mode = XNANDPSU_POLLING;
0245     /* Enable MDMA mode by default */
0246     InstancePtr->DmaMode = XNANDPSU_MDMA;
0247     InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
0248 
0249 #ifdef __rtems__
0250     /* Set page cache to unavailable */
0251     InstancePtr->PartialDataPageIndex = XNANDPSU_PAGE_CACHE_UNAVAILABLE;
0252 #endif
0253 
0254     /* Initialize the NAND flash targets */
0255     Status = XNandPsu_FlashInit(InstancePtr);
0256     if (Status != XST_SUCCESS) {
0257 #ifdef XNANDPSU_DEBUG
0258         xil_printf("%s: Flash init failed\r\n",__func__);
0259 #endif
0260         goto Out;
0261     }
0262     /* Set ECC mode */
0263     if (InstancePtr->Features.EzNand != 0U) {
0264         InstancePtr->EccMode = XNANDPSU_EZNAND;
0265     } else if (InstancePtr->Features.OnDie != 0U) {
0266         InstancePtr->EccMode = XNANDPSU_ONDIE;
0267     } else {
0268         InstancePtr->EccMode = XNANDPSU_HWECC;
0269     }
0270 
0271     /* Initialize Ecc Error flip counters */
0272      InstancePtr->Ecc_Stat_PerPage_flips = 0U;
0273      InstancePtr->Ecc_Stats_total_flips = 0U;
0274 
0275     /*
0276      * Scan for the bad block table(bbt) stored in the flash & load it in
0277      * memory(RAM).  If bbt is not found, create bbt by scanning factory
0278      * marked bad blocks and store it in last good blocks of flash.
0279      */
0280     XNandPsu_InitBbtDesc(InstancePtr);
0281     Status = XNandPsu_ScanBbt(InstancePtr);
0282     if (Status != XST_SUCCESS) {
0283 #ifdef XNANDPSU_DEBUG
0284         xil_printf("%s: BBT scan failed\r\n",__func__);
0285 #endif
0286         goto Out;
0287     }
0288 
0289 #ifdef __rtems__
0290     /* Set page cache to none */
0291     InstancePtr->PartialDataPageIndex = XNANDPSU_PAGE_CACHE_NONE;
0292 #endif
0293 Out:
0294     return Status;
0295 }
0296 
0297 /*****************************************************************************/
0298 /**
0299 *
0300 * This function initializes the NAND flash and gets the geometry information.
0301 *
0302 * @param    InstancePtr is a pointer to the XNandPsu instance.
0303 *
0304 * @return
0305 *       - XST_SUCCESS if successful.
0306 *       - XST_FAILURE if failed.
0307 *
0308 * @note     None
0309 *
0310 ******************************************************************************/
0311 static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr)
0312 {
0313     u32 Target;
0314     u8 Id[ONFI_SIG_LEN] = {0U};
0315     OnfiParamPage Param[ONFI_MND_PRM_PGS] = {0U};
0316     s32 Status = XST_FAILURE;
0317     u32 Index;
0318     u32 Crc;
0319     u32 PrmPgOff;
0320     u32 PrmPgLen;
0321 #ifdef __ICCARM__
0322 #pragma pack(push, 1)
0323     OnfiExtPrmPage ExtParam = {0U};
0324 #pragma pack(pop)
0325 #else
0326     OnfiExtPrmPage ExtParam __attribute__ ((aligned(64))) = {0U};
0327 #endif
0328 
0329     /* Clear Data Interface Register */
0330     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
0331             XNANDPSU_DATA_INTF_OFFSET, 0U);
0332 
0333     /* Clear DMA Buffer Boundary Register */
0334     XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
0335             XNANDPSU_DMA_BUF_BND_OFFSET, 0U);
0336 
0337     for (Target = 0U; Target < XNANDPSU_MAX_TARGETS; Target++) {
0338         /* Reset the Target */
0339         Status = XNandPsu_OnfiReset(InstancePtr, Target);
0340         if (Status != XST_SUCCESS) {
0341             goto Out;
0342         }
0343         /* Read ONFI ID */
0344         Status = XNandPsu_OnfiReadId(InstancePtr, Target,
0345                         ONFI_READ_ID_ADDR,
0346                         ONFI_SIG_LEN,
0347                         (u8 *)&Id[0]);
0348         if (Status != XST_SUCCESS) {
0349             goto Out;
0350         }
0351 
0352         if (!IS_ONFI(Id)) {
0353             if (Target == 0U) {
0354 #ifdef XNANDPSU_DEBUG
0355                 xil_printf("%s: ONFI ID doesn't match\r\n",
0356                                 __func__);
0357 #endif
0358                 Status = XST_FAILURE;
0359                 goto Out;
0360             }
0361         }
0362 
0363         /* Read Parameter Page */
0364         Status = XNandPsu_OnfiReadParamPage(InstancePtr,
0365                         Target, (u8 *)&Param[0]);
0366         if (Status != XST_SUCCESS) {
0367             goto Out;
0368         }
0369         for(Index = 0U; Index < ONFI_MND_PRM_PGS; Index++){
0370             /* Check CRC */
0371             Crc = XNandPsu_OnfiParamPageCrc((u8*)&Param[Index], 0U,
0372                                 ONFI_CRC_LEN);
0373             if (Crc != Param[Index].Crc) {
0374 #ifdef XNANDPSU_DEBUG
0375                 xil_printf("%s: ONFI parameter page (%d) crc check failed\r\n",
0376                             __func__, Index);
0377 #endif
0378                 continue;
0379             } else {
0380                 break;
0381             }
0382         }
0383         if (Index >= ONFI_MND_PRM_PGS) {
0384             Status = XST_FAILURE;
0385             goto Out;
0386         }
0387         /* Fill Geometry for the first target */
0388         if (Target == 0U) {
0389             Status = XNandPsu_InitGeometry(InstancePtr, &Param[Index]);
0390             if (Status != XST_SUCCESS) {
0391                 goto Out;
0392             }
0393             XNandPsu_InitDataInterface(InstancePtr, &Param[Index]);
0394             XNandPsu_InitTimingMode(InstancePtr, &Param[Index]);
0395             XNandPsu_InitFeatures(InstancePtr, &Param[Index]);
0396             if ((!InstancePtr->Features.EzNand) != 0U) {
0397                 Status =XNandPsu_CheckOnDie(InstancePtr);
0398                 if (Status != XST_SUCCESS) {
0399                     InstancePtr->Features.OnDie = 0U;
0400                 }
0401             }
0402             if ((InstancePtr->Geometry.NumBitsECC == 0xFFU) &&
0403                 (InstancePtr->Features.ExtPrmPage != 0U)) {
0404                     /* ONFI 3.1 section 5.7.1.6 & 5.7.1.7 */
0405                 PrmPgLen = (u32)Param[Index].ExtParamPageLen * 16U;
0406                 PrmPgOff = (u32)((u32)Param[Index].NumOfParamPages *
0407                         ONFI_PRM_PG_LEN) + (Index * (u32)PrmPgLen);
0408 
0409                 Status = XNandPsu_ChangeReadColumn(
0410                         InstancePtr, Target,
0411                         PrmPgOff, PrmPgLen, 1U,
0412                         (u8 *)(void *)&ExtParam);
0413                 if (Status != XST_SUCCESS) {
0414                     goto Out;
0415                 }
0416                 /* Check CRC */
0417                 Crc = XNandPsu_OnfiParamPageCrc(
0418                         (u8 *)&ExtParam,
0419                         2U, PrmPgLen);
0420                 if (Crc != ExtParam.Crc) {
0421 #ifdef XNANDPSU_DEBUG
0422     xil_printf("%s: ONFI extended parameter page (%d) crc check failed\r\n",
0423                             __func__, Index);
0424 #endif
0425                     Status = XST_FAILURE;
0426                     goto Out;
0427                 }
0428                 /* Initialize Extended ECC info */
0429                 Status = XNandPsu_InitExtEcc(
0430                         InstancePtr,
0431                         &ExtParam);
0432                 if (Status != XST_SUCCESS) {
0433 #ifdef XNANDPSU_DEBUG
0434     xil_printf("%s: Init extended ecc failed\r\n",__func__);
0435 #endif
0436                     goto Out;
0437                 }
0438             }
0439             /* Configure ECC settings */
0440             XNandPsu_SetEccAddrSize(InstancePtr);
0441         }
0442         InstancePtr->Geometry.NumTargets++;
0443     }
0444     /* Calculate total number of blocks and total size of flash */
0445     InstancePtr->Geometry.NumPages = InstancePtr->Geometry.NumTargets *
0446                     InstancePtr->Geometry.NumTargetPages;
0447     InstancePtr->Geometry.NumBlocks = InstancePtr->Geometry.NumTargets *
0448                     InstancePtr->Geometry.NumTargetBlocks;
0449     InstancePtr->Geometry.DeviceSize =
0450                     (u64)InstancePtr->Geometry.NumTargets *
0451                     InstancePtr->Geometry.TargetSize;
0452 
0453     Status = XST_SUCCESS;
0454 Out:
0455     return Status;
0456 }
0457 
0458 /*****************************************************************************/
0459 /**
0460 *
0461 * This function initializes the geometry information from ONFI parameter page.
0462 *
0463 * @param    InstancePtr is a pointer to the XNandPsu instance.
0464 * @param    Param is pointer to the ONFI parameter page.
0465 *
0466 * @return
0467 *               - XST_SUCCESS if successful.
0468 *               - XST_FAILURE if failed.
0469 *
0470 * @note     None
0471 *
0472 ******************************************************************************/
0473 static s32 XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param)
0474 {
0475     s32 Status = XST_FAILURE;
0476 
0477     if (Param->BytesPerPage > XNANDPSU_MAX_PAGE_SIZE) {
0478 #ifdef XNANDPSU_DEBUG
0479             xil_printf("%s: Invalid Bytes Per Page %d\r\n",
0480                     __func__, Param->BytesPerPage);
0481 #endif
0482             goto Out;
0483     }
0484     InstancePtr->Geometry.BytesPerPage = Param->BytesPerPage;
0485 
0486 
0487     if (Param->SpareBytesPerPage > XNANDPSU_MAX_SPARE_SIZE) {
0488 #ifdef XNANDPSU_DEBUG
0489             xil_printf("%s: Invalid Spare Bytes Per Page %d\r\n",
0490                     __func__, Param->SpareBytesPerPage);
0491 #endif
0492             goto Out;
0493     }
0494     InstancePtr->Geometry.SpareBytesPerPage = Param->SpareBytesPerPage;
0495 
0496     if (Param->PagesPerBlock > XNANDPSU_MAX_PAGES_PER_BLOCK) {
0497 #ifdef XNANDPSU_DEBUG
0498             xil_printf("%s: Invalid Page Count Per Block %d\r\n",
0499                     __func__, Param->PagesPerBlock);
0500 #endif
0501             goto Out;
0502     }
0503     InstancePtr->Geometry.PagesPerBlock = Param->PagesPerBlock;
0504 
0505 
0506     if (Param->BlocksPerLun > XNANDPSU_MAX_BLOCKS) {
0507 #ifdef XNANDPSU_DEBUG
0508             xil_printf("%s: Invalid block count per LUN %d\r\n",
0509                     __func__, Param->BlocksPerLun);
0510 #endif
0511             goto Out;
0512     }
0513     InstancePtr->Geometry.BlocksPerLun = Param->BlocksPerLun;
0514 
0515     if (Param->NumLuns > XNANDPSU_MAX_LUNS) {
0516 #ifdef XNANDPSU_DEBUG
0517             xil_printf("%s: Invalid LUN count %d\r\n",
0518                     __func__, Param->NumLuns);
0519 #endif
0520             goto Out;
0521     }
0522     InstancePtr->Geometry.NumLuns = Param->NumLuns;
0523 
0524     InstancePtr->Geometry.RowAddrCycles = Param->AddrCycles & 0xFU;
0525     InstancePtr->Geometry.ColAddrCycles = (Param->AddrCycles >> 4U) & 0xFU;
0526     InstancePtr->Geometry.NumBitsPerCell = Param->BitsPerCell;
0527     InstancePtr->Geometry.NumBitsECC = Param->EccBits;
0528     InstancePtr->Geometry.BlockSize = (Param->PagesPerBlock *
0529                         Param->BytesPerPage);
0530     InstancePtr->Geometry.NumTargetBlocks = (Param->BlocksPerLun *
0531                         (u32)Param->NumLuns);
0532     InstancePtr->Geometry.NumTargetPages = (Param->BlocksPerLun *
0533                         (u32)Param->NumLuns *
0534                         Param->PagesPerBlock);
0535     InstancePtr->Geometry.TargetSize = ((u64)Param->BlocksPerLun *
0536                         (u64)Param->NumLuns *
0537                         (u64)Param->PagesPerBlock *
0538                         (u64)Param->BytesPerPage);
0539     InstancePtr->Geometry.EccCodeWordSize = 9U; /* 2 power of 9 = 512 */
0540     if (InstancePtr->Geometry.NumTargetBlocks > XNANDPSU_MAX_BLOCKS)
0541         xil_printf("!!! Device contains more blocks than the max defined blocks in driver\r\n");
0542 
0543 #ifdef XNANDPSU_DEBUG
0544     xil_printf("Manufacturer: %s\r\n", Param->DeviceManufacturer);
0545     xil_printf("Device Model: %s\r\n", Param->DeviceModel);
0546     xil_printf("Jedec ID: 0x%x\r\n", Param->JedecManufacturerId);
0547     xil_printf("Bytes Per Page: 0x%x\r\n", Param->BytesPerPage);
0548     xil_printf("Spare Bytes Per Page: 0x%x\r\n", Param->SpareBytesPerPage);
0549     xil_printf("Pages Per Block: 0x%x\r\n", Param->PagesPerBlock);
0550     xil_printf("Blocks Per LUN: 0x%x\r\n", Param->BlocksPerLun);
0551     xil_printf("Number of LUNs: 0x%x\r\n", Param->NumLuns);
0552     xil_printf("Number of bits per cell: 0x%x\r\n", Param->BitsPerCell);
0553     xil_printf("Number of ECC bits: 0x%x\r\n", Param->EccBits);
0554     xil_printf("Block Size: 0x%x\r\n", InstancePtr->Geometry.BlockSize);
0555 
0556     xil_printf("Number of Target Blocks: 0x%x\r\n",
0557                     InstancePtr->Geometry.NumTargetBlocks);
0558     xil_printf("Number of Target Pages: 0x%x\r\n",
0559                     InstancePtr->Geometry.NumTargetPages);
0560 
0561 #endif
0562     Status = XST_SUCCESS;
0563 Out:
0564     return Status;
0565 }
0566 
0567 /*****************************************************************************/
0568 /**
0569 *
0570 * This function initializes the feature list from ONFI parameter page.
0571 *
0572 * @param    InstancePtr is a pointer to the XNandPsu instance.
0573 * @param    Param is pointer to ONFI parameter page buffer.
0574 *
0575 * @return
0576 *       None
0577 *
0578 * @note     None
0579 *
0580 ******************************************************************************/
0581 static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param)
0582 {
0583     InstancePtr->Features.NvDdr = ((Param->Features & (1U << 5)) != 0U) ?
0584                                 1U : 0U;
0585     InstancePtr->Features.EzNand = ((Param->Features & (1U << 9)) != 0U) ?
0586                                 1U : 0U;
0587     InstancePtr->Features.ExtPrmPage = ((Param->Features & (1U << 7)) != 0U) ?
0588                                 1U : 0U;
0589 }
0590 
0591 /*****************************************************************************/
0592 /**
0593 *
0594 * This function initializes the Data Interface from ONFI parameter page.
0595 *
0596 * @param    InstancePtr is a pointer to the XNandPsu instance.
0597 * @param    Param is pointer to ONFI parameter page buffer.
0598 *
0599 * @return
0600 *       None
0601 *
0602 * @note     None
0603 *
0604 ******************************************************************************/
0605 static void XNandPsu_InitDataInterface(XNandPsu *InstancePtr, OnfiParamPage *Param)
0606 {
0607     if (Param->NVDDRTimingMode)
0608         InstancePtr->DataInterface = XNANDPSU_NVDDR;
0609     else if (Param->SDRTimingMode)
0610         InstancePtr->DataInterface = XNANDPSU_SDR;
0611 }
0612 
0613 /*****************************************************************************/
0614 /**
0615 *
0616 * This function initializes the Timing mode from ONFI parameter page.
0617 *
0618 * @param    InstancePtr is a pointer to the XNandPsu instance.
0619 * @param    Param is pointer to ONFI parameter page buffer.
0620 *
0621 * @return
0622 *       None
0623 *
0624 * @note     None
0625 *
0626 ******************************************************************************/
0627 static void XNandPsu_InitTimingMode(XNandPsu *InstancePtr, OnfiParamPage *Param)
0628 {
0629     s8 Mode;
0630     u8 TimingMode =  (u8)(Param->SDRTimingMode);
0631 
0632     if (InstancePtr->DataInterface == XNANDPSU_NVDDR)
0633         TimingMode = Param->NVDDRTimingMode;
0634 
0635     for(Mode = XNANDPSU_MAX_TIMING_MODE; Mode >= 0; Mode--) {
0636         if (TimingMode & (0x01 << Mode)) {
0637             InstancePtr->TimingMode = Mode;
0638             break;
0639         } else {
0640             continue;
0641         }
0642     }
0643 }
0644 
0645 /*****************************************************************************/
0646 /**
0647 *
0648 * This function checks if the flash supports on-die ECC.
0649 *
0650 * @param    InstancePtr is a pointer to the XNandPsu instance.
0651 * @param    Param is pointer to ONFI parameter page.
0652 *
0653 * @return
0654 *       None
0655 *
0656 * @note     None
0657 *
0658 ******************************************************************************/
0659 static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr)
0660 {
0661     s32 Status = XST_FAILURE;
0662     u8 JedecId[2] = {0U};
0663     u8 EccSetFeature[4] = {0x08U, 0x00U, 0x00U, 0x00U};
0664     u8 EccGetFeature[4] ={0U};
0665 
0666     /*
0667      * Check if this flash supports On-Die ECC.
0668      * For more information, refer to Micron TN2945.
0669      * Micron Flash: MT29F1G08ABADA, MT29F1G08ABBDA
0670      *       MT29F1G16ABBDA,
0671      *       MT29F2G08ABBEA, MT29F2G16ABBEA,
0672      *       MT29F2G08ABAEA, MT29F2G16ABAEA,
0673      *       MT29F4G08ABBDA, MT29F4G16ABBDA,
0674      *       MT29F4G08ABADA, MT29F4G16ABADA,
0675      *       MT29F8G08ADBDA, MT29F8G16ADBDA,
0676      *       MT29F8G08ADADA, MT29F8G16ADADA
0677      */
0678 
0679     /* Read JEDEC ID */
0680     Status = XNandPsu_OnfiReadId(InstancePtr, 0U, 0x00U, 2U, &JedecId[0]);
0681     if (Status != XST_SUCCESS) {
0682         goto Out;
0683     }
0684 
0685     if ((JedecId[0] == 0x2CU) &&
0686     /* 1 Gb flash devices */
0687     ((JedecId[1] == 0xF1U) ||
0688     (JedecId[1] == 0xA1U) ||
0689     (JedecId[1] == 0xB1U) ||
0690     /* 2 Gb flash devices */
0691     (JedecId[1] == 0xAAU) ||
0692     (JedecId[1] == 0xBAU) ||
0693     (JedecId[1] == 0xDAU) ||
0694     (JedecId[1] == 0xCAU) ||
0695     /* 4 Gb flash devices */
0696     (JedecId[1] == 0xACU) ||
0697     (JedecId[1] == 0xBCU) ||
0698     (JedecId[1] == 0xDCU) ||
0699     (JedecId[1] == 0xCCU) ||
0700     /* 8 Gb flash devices */
0701     (JedecId[1] == 0xA3U) ||
0702     (JedecId[1] == 0xB3U) ||
0703     (JedecId[1] == 0xD3U) ||
0704     (JedecId[1] == 0xC3U))) {
0705 #ifdef XNANDPSU_DEBUG
0706         xil_printf("%s: Ondie flash detected, jedec id 0x%x 0x%x\r\n",
0707                     __func__, JedecId[0], JedecId[1]);
0708 #endif
0709         /* On-Die Set Feature */
0710         Status = XNandPsu_SetFeature(InstancePtr, 0U, 0x90U,
0711                         &EccSetFeature[0]);
0712         if (Status != XST_SUCCESS) {
0713 #ifdef XNANDPSU_DEBUG
0714             xil_printf("%s: Ondie set_feature failed\r\n",
0715                                 __func__);
0716 #endif
0717             goto Out;
0718         }
0719         /* Check to see if ECC feature is set */
0720         Status = XNandPsu_GetFeature(InstancePtr, 0U, 0x90U,
0721                         &EccGetFeature[0]);
0722         if (Status != XST_SUCCESS) {
0723 #ifdef XNANDPSU_DEBUG
0724             xil_printf("%s: Ondie get_feature failed\r\n",
0725                                 __func__);
0726 #endif
0727             goto Out;
0728         }
0729         if ((EccGetFeature[0] & 0x08U) != 0U) {
0730             InstancePtr->Features.OnDie = 1U;
0731             Status = XST_SUCCESS;
0732         }
0733     } else {
0734         /* On-Die flash not found */
0735         Status = XST_FAILURE;
0736     }
0737 Out:
0738     return Status;
0739 }
0740 
0741 /*****************************************************************************/
0742 /**
0743 *
0744 * This function enables DMA mode of controller operation.
0745 *
0746 * @param    InstancePtr is a pointer to the XNandPsu instance.
0747 *
0748 * @return
0749 *       None
0750 *
0751 * @note     None
0752 *
0753 ******************************************************************************/
0754 void XNandPsu_EnableDmaMode(XNandPsu *InstancePtr)
0755 {
0756     /* Assert the input arguments. */
0757     Xil_AssertVoid(InstancePtr != NULL);
0758     Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0759 
0760     InstancePtr->DmaMode = XNANDPSU_MDMA;
0761 }
0762 
0763 /*****************************************************************************/
0764 /**
0765 *
0766 * This function disables DMA mode of driver/controller operation.
0767 *
0768 * @param    InstancePtr is a pointer to the XNandPsu instance.
0769 *
0770 * @return
0771 *       None
0772 *
0773 * @note     None
0774 *
0775 ******************************************************************************/
0776 void XNandPsu_DisableDmaMode(XNandPsu *InstancePtr)
0777 {
0778     /* Assert the input arguments. */
0779     Xil_AssertVoid(InstancePtr != NULL);
0780     Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0781 
0782     InstancePtr->DmaMode = XNANDPSU_PIO;
0783 }
0784 
0785 /*****************************************************************************/
0786 /**
0787 *
0788 * This function enables ECC mode of driver/controller operation.
0789 *
0790 * @param    InstancePtr is a pointer to the XNandPsu instance.
0791 *
0792 * @return
0793 *       None
0794 *
0795 * @note     None
0796 *
0797 ******************************************************************************/
0798 void XNandPsu_EnableEccMode(XNandPsu *InstancePtr)
0799 {
0800     /* Assert the input arguments. */
0801     Xil_AssertVoid(InstancePtr != NULL);
0802     Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0803 
0804     InstancePtr->EccMode = XNANDPSU_HWECC;
0805 }
0806 
0807 /*****************************************************************************/
0808 /**
0809 *
0810 * This function disables ECC mode of driver/controller operation.
0811 *
0812 * @param    InstancePtr is a pointer to the XNandPsu instance.
0813 *
0814 * @return
0815 *       None
0816 *
0817 * @note     None
0818 *
0819 ******************************************************************************/
0820 void XNandPsu_DisableEccMode(XNandPsu *InstancePtr)
0821 {
0822     /* Assert the input arguments. */
0823     Xil_AssertVoid(InstancePtr != NULL);
0824     Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0825 
0826     InstancePtr->EccMode = XNANDPSU_NONE;
0827 }
0828 
0829 #ifdef __rtems__
0830 #include <rtems/rtems/clock.h>
0831 static void udelay( void )
0832 {
0833     uint64_t time = rtems_clock_get_uptime_nanoseconds() + 1000;
0834     while (1) {
0835         uint64_t newtime = rtems_clock_get_uptime_nanoseconds();
0836         if (newtime > time) {
0837             break;
0838         }
0839     }
0840 }
0841 #define usleep(x) udelay()
0842 #endif
0843 
0844 /*****************************************************************************/
0845 /**
0846 *
0847 * This function polls for a register bit set status till the timeout.
0848 *
0849 * @param    InstancePtr is a pointer to the XNandPsu instance.
0850 * @param    RegOffset is the offset of register.
0851 * @param    Mask is the bitmask.
0852 * @param    Timeout is the timeout value.
0853 *
0854 * @return
0855 *       - XST_SUCCESS if successful.
0856 *       - XST_FAILURE if failed.
0857 *
0858 * @note     None
0859 *
0860 ******************************************************************************/
0861 static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset,
0862                     u32 Mask, u32 Timeout)
0863 {
0864     s32 Status = XST_FAILURE;
0865     volatile u32 RegVal;
0866     u32 TimeoutVar = Timeout;
0867 
0868     while (TimeoutVar > 0U) {
0869         RegVal = XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
0870                         RegOffset) & Mask;
0871         if (RegVal != 0U) {
0872             break;
0873         }
0874         TimeoutVar--;
0875         usleep(1);
0876     }
0877 
0878     if (TimeoutVar <= 0U) {
0879         Status = XST_FAILURE;
0880     } else {
0881         Status = XST_SUCCESS;
0882     }
0883 
0884     return Status;
0885 }
0886 
0887 /*****************************************************************************/
0888 /**
0889 *
0890 * This function sets packet size and packet count values in packet register.
0891 *
0892 * @param    InstancePtr is a pointer to the XNandPsu instance.
0893 * @param    PktSize is the packet size.
0894 * @param    PktCount is the packet count.
0895 *
0896 * @return
0897 *       None
0898 *
0899 * @note     None
0900 *
0901 ******************************************************************************/
0902 static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize,
0903                         u32 PktCount)
0904 {
0905     /* Update Packet Register with pkt size and count */
0906     XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_PKT_OFFSET,
0907                 ((u32)XNANDPSU_PKT_PKT_SIZE_MASK |
0908                 (u32)XNANDPSU_PKT_PKT_CNT_MASK),
0909                 ((PktSize & XNANDPSU_PKT_PKT_SIZE_MASK) |
0910                 ((PktCount << XNANDPSU_PKT_PKT_CNT_SHIFT) &
0911                 XNANDPSU_PKT_PKT_CNT_MASK)));
0912 }
0913 
0914 /*****************************************************************************/
0915 /**
0916 *
0917 * This function sets Page and Column values in the Memory address registers.
0918 *
0919 * @param    InstancePtr is a pointer to the XNandPsu instance.
0920 * @param    Page is the page value.
0921 * @param    Col is the column value.
0922 *
0923 * @return
0924 *       None
0925 *
0926 * @note     None
0927 *
0928 ******************************************************************************/
0929 static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col)
0930 {
0931     /* Program Memory Address Register 1 */
0932     XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
0933                 XNANDPSU_MEM_ADDR1_OFFSET,
0934                 (((u32)Col & XNANDPSU_MEM_ADDR1_COL_ADDR_MASK) |
0935                 ((Page << (u32)XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) &
0936                 XNANDPSU_MEM_ADDR1_PG_ADDR_MASK)));
0937     /* Program Memory Address Register 2 */
0938     XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET,
0939                 XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK,
0940                 ((Page >> XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) &
0941                 XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK));
0942 }
0943 
0944 /*****************************************************************************/
0945 /**
0946 *
0947 * This function sets the size of page in Command Register.
0948 *
0949 * @param    InstancePtr is a pointer to the XNandPsu instance.
0950 *
0951 * @return
0952 *       None
0953 *
0954 * @note     None
0955 *
0956 ******************************************************************************/
0957 static void XNandPsu_SetPageSize(XNandPsu *InstancePtr)
0958 {
0959     u32 PageSizeMask = 0;
0960     u32 PageSize = InstancePtr->Geometry.BytesPerPage;
0961 
0962     /* Calculate page size mask */
0963     switch(PageSize) {
0964         case XNANDPSU_PAGE_SIZE_512:
0965             PageSizeMask = (0U << XNANDPSU_CMD_PG_SIZE_SHIFT);
0966             break;
0967         case XNANDPSU_PAGE_SIZE_2K:
0968             PageSizeMask = (1U << XNANDPSU_CMD_PG_SIZE_SHIFT);
0969             break;
0970         case XNANDPSU_PAGE_SIZE_4K:
0971             PageSizeMask = (2U << XNANDPSU_CMD_PG_SIZE_SHIFT);
0972             break;
0973         case XNANDPSU_PAGE_SIZE_8K:
0974             PageSizeMask = (3U << XNANDPSU_CMD_PG_SIZE_SHIFT);
0975             break;
0976         case XNANDPSU_PAGE_SIZE_16K:
0977             PageSizeMask = (4U << XNANDPSU_CMD_PG_SIZE_SHIFT);
0978             break;
0979         case XNANDPSU_PAGE_SIZE_1K_16BIT:
0980             PageSizeMask = (5U << XNANDPSU_CMD_PG_SIZE_SHIFT);
0981             break;
0982         default:
0983             /* Not supported */
0984             break;
0985     }
0986     /* Update Command Register */
0987     XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_CMD_OFFSET,
0988                 XNANDPSU_CMD_PG_SIZE_MASK, PageSizeMask);
0989 }
0990 
0991 /*****************************************************************************/
0992 /**
0993 *
0994 * This function setup the Ecc Register.
0995 *
0996 * @param    InstancePtr is a pointer to the XNandPsu instance.
0997 *
0998 * @return
0999 *       None
1000 *
1001 * @note     None
1002 *
1003 ******************************************************************************/
1004 static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr)
1005 {
1006     u32 PageSize = InstancePtr->Geometry.BytesPerPage;
1007     u32 CodeWordSize = InstancePtr->Geometry.EccCodeWordSize;
1008     u32 NumEccBits = InstancePtr->Geometry.NumBitsECC;
1009     u32 Index;
1010     u32 Found = 0U;
1011     u8 BchModeVal;
1012 
1013     for (Index = 0U; Index < (sizeof(EccMatrix)/sizeof(XNandPsu_EccMatrix));
1014                         Index++) {
1015         if ((EccMatrix[Index].PageSize == PageSize) &&
1016             (EccMatrix[Index].CodeWordSize >= CodeWordSize)) {
1017             if (EccMatrix[Index].NumEccBits >= NumEccBits) {
1018                 Found = Index;
1019                 break;
1020             }
1021             else {
1022                 Found = Index;
1023             }
1024         }
1025     }
1026 
1027     if (Found != 0U) {
1028         if(InstancePtr->Geometry.SpareBytesPerPage < 64U) {
1029             InstancePtr->EccCfg.EccAddr = (u16)PageSize;
1030         }
1031         else {
1032             InstancePtr->EccCfg.EccAddr = ((u16)PageSize +
1033                 (InstancePtr->Geometry.SpareBytesPerPage
1034                         - EccMatrix[Found].EccSize));
1035         }
1036         InstancePtr->EccCfg.EccSize = EccMatrix[Found].EccSize;
1037         InstancePtr->EccCfg.NumEccBits = EccMatrix[Found].NumEccBits;
1038         InstancePtr->EccCfg.CodeWordSize =
1039                         EccMatrix[Found].CodeWordSize;
1040 #ifdef XNANDPSU_DEBUG
1041         xil_printf("ECC: addr 0x%x size 0x%x numbits %d "
1042                    "codesz %d\r\n",
1043                    InstancePtr->EccCfg.EccAddr,
1044                    InstancePtr->EccCfg.EccSize,
1045                    InstancePtr->EccCfg.NumEccBits,
1046                    InstancePtr->EccCfg.CodeWordSize);
1047 #endif
1048         if (EccMatrix[Found].IsBCH == XNANDPSU_HAMMING) {
1049             InstancePtr->EccCfg.IsBCH = 0U;
1050         } else {
1051             InstancePtr->EccCfg.IsBCH = 1U;
1052         }
1053         /* Write ECC register */
1054         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
1055                 (u32)XNANDPSU_ECC_OFFSET,
1056                 ((u32)InstancePtr->EccCfg.EccAddr |
1057                 ((u32)InstancePtr->EccCfg.EccSize << (u32)16) |
1058                 ((u32)InstancePtr->EccCfg.IsBCH << (u32)27)));
1059 
1060         if (EccMatrix[Found].IsBCH == XNANDPSU_BCH) {
1061             /* Write memory address register 2 */
1062             switch(InstancePtr->EccCfg.NumEccBits) {
1063                 case 16U:
1064                     BchModeVal = 0x0U;
1065                     break;
1066                 case 12U:
1067                     BchModeVal = 0x1U;
1068                     break;
1069                 case 8U:
1070                     BchModeVal = 0x2U;
1071                     break;
1072                 case 4U:
1073                     BchModeVal = 0x3U;
1074                     break;
1075                 case 24U:
1076                     BchModeVal = 0x4U;
1077                     break;
1078                 default:
1079                     BchModeVal = 0x0U;
1080                     break;
1081             }
1082             XNandPsu_ReadModifyWrite(InstancePtr,
1083                 XNANDPSU_MEM_ADDR2_OFFSET,
1084                 XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_MASK,
1085                 ((u32)BchModeVal <<
1086                 (u32)XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_SHIFT));
1087         }
1088     }
1089 }
1090 
1091 /*****************************************************************************/
1092 /**
1093 *
1094 * This function setup the Ecc Spare Command Register.
1095 *
1096 * @param    InstancePtr is a pointer to the XNandPsu instance.
1097 *
1098 * @return
1099 *       None
1100 *
1101 * @note     None
1102 *
1103 ******************************************************************************/
1104 static void XNandPsu_SetEccSpareCmd(XNandPsu *InstancePtr, u16 SpareCmd,
1105                                 u8 AddrCycles)
1106 {
1107     XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
1108                 (u32)XNANDPSU_ECC_SPR_CMD_OFFSET,
1109                 (u32)SpareCmd | ((u32)AddrCycles << 28U));
1110 }
1111 
1112 /*****************************************************************************/
1113 /**
1114 *
1115 * This function sets the chip select value in memory address2 register.
1116 *
1117 * @param    InstancePtr is a pointer to the XNandPsu instance.
1118 * @param    Target is the chip select value.
1119 *
1120 * @return
1121 *       None
1122 *
1123 * @note     None
1124 *
1125 ******************************************************************************/
1126 static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target)
1127 {
1128 #if defined  (XCLOCKING)
1129     Xil_ClockEnable(InstancePtr->Config.RefClk);
1130 #endif
1131     /* Update Memory Address2 register with chip select */
1132     XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET,
1133             XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK,
1134             ((Target << XNANDPSU_MEM_ADDR2_CHIP_SEL_SHIFT) &
1135             XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK));
1136 }
1137 
1138 /*****************************************************************************/
1139 /**
1140 *
1141 * This function sends ONFI Reset command to the flash.
1142 *
1143 * @param    InstancePtr is a pointer to the XNandPsu instance.
1144 * @param    Target is the chip select value.
1145 *
1146 * @return
1147 *       - XST_SUCCESS if successful.
1148 *       - XST_FAILURE if failed.
1149 *
1150 * @note     None
1151 *
1152 ******************************************************************************/
1153 static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target)
1154 {
1155     s32 Status = XST_FAILURE;
1156 
1157     /* Enable Transfer Complete Interrupt in Interrupt Status Register */
1158     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1159         XNANDPSU_INTR_STS_EN_OFFSET,
1160         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
1161     /* Program Command Register */
1162     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RST, ONFI_CMD_INVALID, 0U,
1163             0U, 0U);
1164     /* Program Memory Address Register2 for chip select */
1165     XNandPsu_SelectChip(InstancePtr, Target);
1166     /* Set Reset in Program Register */
1167     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1168         XNANDPSU_PROG_OFFSET, XNANDPSU_PROG_RST_MASK);
1169 
1170     /* Poll for Transfer Complete event */
1171     Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
1172 
1173     return Status;
1174 }
1175 
1176 /*****************************************************************************/
1177 /**
1178 *
1179 * This function sends ONFI Read Status command to the flash.
1180 *
1181 * @param    InstancePtr is a pointer to the XNandPsu instance.
1182 * @param    Target is the chip select value.
1183 * @param    OnfiStatus is the ONFI status value to return.
1184 *
1185 * @return
1186 *       - XST_SUCCESS if successful.
1187 *       - XST_FAILURE if failed.
1188 *
1189 * @note     None
1190 *
1191 ******************************************************************************/
1192 static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target,
1193                             u16 *OnfiStatus)
1194 {
1195     s32 Status = XST_FAILURE;
1196 
1197     /* Enable Transfer Complete Interrupt in Interrupt Status Register */
1198     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1199         XNANDPSU_INTR_STS_EN_OFFSET,
1200         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
1201     /* Program Command Register */
1202     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_STS, ONFI_CMD_INVALID,
1203                 0U, 0U, 0U);
1204     /* Program Memory Address Register2 for chip select */
1205     XNandPsu_SelectChip(InstancePtr, Target);
1206     /* Program Packet Size and Packet Count */
1207     if(InstancePtr->DataInterface == XNANDPSU_SDR)
1208         XNandPsu_SetPktSzCnt(InstancePtr, 1U, 1U);
1209     else
1210         XNandPsu_SetPktSzCnt(InstancePtr, 2U, 1U);
1211 
1212     /* Set Read Status in Program Register */
1213     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1214             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_STS_MASK);
1215     /* Poll for Transfer Complete event */
1216     Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
1217     /* Read Flash Status */
1218     *OnfiStatus = (u16) XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
1219                         XNANDPSU_FLASH_STS_OFFSET);
1220 
1221     return Status;
1222 }
1223 
1224 /*****************************************************************************/
1225 /**
1226 *
1227 * This function sends ONFI Read ID command to the flash.
1228 *
1229 * @param    InstancePtr is a pointer to the XNandPsu instance.
1230 * @param    Target is the chip select value.
1231 * @param    Buf is the ONFI ID value to return.
1232 *
1233 * @return
1234 *       - XST_SUCCESS if successful.
1235 *       - XST_FAILURE if failed.
1236 *
1237 * @note     None
1238 *
1239 ******************************************************************************/
1240 static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr,
1241                             u32 IdLen, u8 *Buf)
1242 {
1243     s32 Status = XST_FAILURE;
1244     u32 Index;
1245     u32 Rem;
1246     u32 RegVal;
1247     u32 RemIdx;
1248 
1249     u32 *BufPtr = (u32 *)(void *)Buf;
1250 
1251     /*
1252      * Enable Buffer Read Ready Interrupt in Interrupt Status Enable
1253      * Register
1254      */
1255     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1256         XNANDPSU_INTR_STS_EN_OFFSET,
1257         XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
1258     /* Program Command */
1259     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_ID, ONFI_CMD_INVALID, 0U,
1260                     0U, ONFI_READ_ID_ADDR_CYCLES);
1261 
1262     /* Program Column, Page, Block address */
1263     XNandPsu_SetPageColAddr(InstancePtr, 0U, IdAddr);
1264     /* Program Memory Address Register2 for chip select */
1265     XNandPsu_SelectChip(InstancePtr, Target);
1266     /* Program Packet Size and Packet Count */
1267     XNandPsu_SetPktSzCnt(InstancePtr, IdLen, 1U);
1268     /* Set Read ID in Program Register */
1269     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1270             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_ID_MASK);
1271 
1272     /* Poll for Buffer Read Ready event */
1273     Status = XNandPsu_PollRegTimeout(
1274         InstancePtr,
1275         XNANDPSU_INTR_STS_OFFSET,
1276         XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
1277         XNANDPSU_INTR_POLL_TIMEOUT);
1278     if (Status != XST_SUCCESS) {
1279 #ifdef XNANDPSU_DEBUG
1280         xil_printf("%s: Poll for buf read ready timeout\r\n",
1281                             __func__);
1282 #endif
1283         goto Out;
1284     }
1285     /*
1286      * Enable Transfer Complete Interrupt in Interrupt
1287      * Status Enable Register
1288      */
1289 
1290         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1291         XNANDPSU_INTR_STS_EN_OFFSET,
1292         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
1293 
1294     /*
1295      * Clear Buffer Read Ready Interrupt in Interrupt Status
1296      * Register
1297      */
1298     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1299             XNANDPSU_INTR_STS_OFFSET,
1300             XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK);
1301     /* Read Packet Data from Data Port Register */
1302     for (Index = 0U; Index < (IdLen/4); Index++) {
1303         *(BufPtr+Index) = XNandPsu_ReadReg(
1304                     InstancePtr->Config.BaseAddress,
1305                     XNANDPSU_BUF_DATA_PORT_OFFSET);
1306     }
1307     Rem = IdLen % 4;
1308     if (Rem != 0U) {
1309         RegVal = XNandPsu_ReadReg(
1310                     InstancePtr->Config.BaseAddress,
1311                     XNANDPSU_BUF_DATA_PORT_OFFSET);
1312         for (RemIdx = 0U; RemIdx < Rem; RemIdx++) {
1313             *(Buf + (Index * 4U) + RemIdx) = (u8) (RegVal >>
1314                         (RemIdx * 8U)) & 0xFFU;
1315         }
1316     }
1317 
1318     Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
1319 
1320 Out:
1321     return Status;
1322 }
1323 
1324 /*****************************************************************************/
1325 /**
1326 *
1327 * This function sends the ONFI Read Parameter Page command to flash.
1328 *
1329 * @param    InstancePtr is a pointer to the XNandPsu instance.
1330 * @param    Target is the chip select value.
1331 * @param    PrmIndex is the index of parameter page.
1332 * @param    Buf is the parameter page information to return.
1333 *
1334 * @return
1335 *       - XST_SUCCESS if successful.
1336 *       - XST_FAILURE if failed.
1337 *
1338 * @note     None
1339 *
1340 ******************************************************************************/
1341 static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target,
1342                         u8 *Buf)
1343 {
1344     s32 Status = XST_FAILURE;
1345 
1346     /*
1347      * Enable Buffer Read Ready Interrupt in Interrupt Status Enable
1348      * Register
1349      */
1350     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1351         XNANDPSU_INTR_STS_EN_OFFSET,
1352         XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
1353     /* Program Command */
1354     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_PRM_PG, ONFI_CMD_INVALID,
1355                     0U, 0U, ONFI_PRM_PG_ADDR_CYCLES);
1356     /* Program Column, Page, Block address */
1357     XNandPsu_SetPageColAddr(InstancePtr, 0U, 0U);
1358     /* Program Memory Address Register2 for chip select */
1359     XNandPsu_SelectChip(InstancePtr, Target);
1360     /* Program Packet Size and Packet Count */
1361     XNandPsu_SetPktSzCnt(InstancePtr, ONFI_MND_PRM_PGS*ONFI_PRM_PG_LEN, 1U);
1362     /* Set Read Parameter Page in Program Register */
1363     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1364             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_PRM_PG_MASK);
1365 
1366     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, 1U, ONFI_MND_PRM_PGS*ONFI_PRM_PG_LEN, 0, 0);
1367 
1368     return Status;
1369 }
1370 
1371 /*****************************************************************************/
1372 /**
1373 *
1374 * This function returns the length including bad blocks from a given offset and
1375 * length.
1376 *
1377 * @param    InstancePtr is the pointer to the XNandPsu instance.
1378 * @param    Offset is the flash data address to read from.
1379 * @param    Length is number of bytes to read.
1380 *
1381 * @return
1382 *       - Return actual length including bad blocks.
1383 *
1384 * @note     None.
1385 *
1386 ******************************************************************************/
1387 static s32 XNandPsu_CalculateLength(XNandPsu *InstancePtr, u64 Offset,
1388                             u64 Length)
1389 {
1390     s32 Status;
1391     u32 BlockSize;
1392     u32 BlockLen;
1393     u32 Block;
1394     u64 TempLen = 0;
1395     u64 OffsetVar = Offset;
1396 
1397     BlockSize = InstancePtr->Geometry.BlockSize;
1398 
1399     while (TempLen < Length) {
1400         Block = (u32)(OffsetVar/BlockSize);
1401         BlockLen = BlockSize - (u32)(OffsetVar % BlockSize);
1402         if (OffsetVar >= InstancePtr->Geometry.DeviceSize) {
1403             Status = XST_FAILURE;
1404             goto Out;
1405         }
1406         /* Check if the block is bad */
1407         Status = XNandPsu_IsBlockBad(InstancePtr, Block);
1408         if (Status != XST_SUCCESS) {
1409             /* Good block */
1410             TempLen += BlockLen;
1411         }
1412         OffsetVar += BlockLen;
1413     }
1414 
1415     Status = XST_SUCCESS;
1416 Out:
1417     return Status;
1418 }
1419 
1420 /*****************************************************************************/
1421 /**
1422 *
1423 * This function writes to the flash.
1424 *
1425 * @param    InstancePtr is a pointer to the XNandPsu instance.
1426 * @param    Offset is the starting offset of flash to write.
1427 * @param    Length is the number of bytes to write.
1428 * @param    SrcBuf is the source data buffer to write.
1429 *
1430 * @return
1431 *       - XST_SUCCESS if successful.
1432 *       - XST_FAILURE if failed.
1433 *
1434 * @note     None
1435 *
1436 ******************************************************************************/
1437 s32 XNandPsu_Write(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *SrcBuf)
1438 {
1439     /* Assert the input arguments. */
1440     Xil_AssertNonvoid(InstancePtr != NULL);
1441     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1442     Xil_AssertNonvoid(SrcBuf != NULL);
1443     Xil_AssertNonvoid(Length != 0U);
1444     Xil_AssertNonvoid((Offset + Length) <=
1445                 InstancePtr->Geometry.DeviceSize);
1446 
1447     s32 Status = XST_FAILURE;
1448     u32 Page;
1449     u32 Col;
1450     u32 Target;
1451     u32 Block;
1452     u32 PartialBytes = 0;
1453     u32 NumBytes;
1454     u32 RemLen;
1455     u8 *BufPtr;
1456     u8 *SrcBufPtr = (u8 *)SrcBuf;
1457     u64 OffsetVar = Offset;
1458     u64 LengthVar = Length;
1459 
1460     /*
1461      * Check if write operation exceeds flash size when including
1462      * bad blocks.
1463      */
1464     Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
1465     if (Status != XST_SUCCESS) {
1466         goto Out;
1467     }
1468 
1469 #ifdef __rtems__
1470     if (InstancePtr->PartialDataPageIndex != XNANDPSU_PAGE_CACHE_UNAVAILABLE) {
1471         /* All writes invalidate the page cache */
1472         InstancePtr->PartialDataPageIndex = XNANDPSU_PAGE_CACHE_NONE;
1473     }
1474 #endif
1475     while (LengthVar > 0U) {
1476         Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
1477         /*
1478          * Skip the bad blocks. Increment the offset by block size.
1479          * For better results, always program the flash starting at
1480          * a block boundary.
1481          */
1482         if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) {
1483             OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
1484             continue;
1485         }
1486         /* Calculate Page and Column address values */
1487         Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage);
1488         Col = (u32) (OffsetVar &
1489                 (InstancePtr->Geometry.BytesPerPage - 1U));
1490         PartialBytes = 0U;
1491         /*
1492          * Check if partial write.
1493          * If column address is > 0 or Length is < page size
1494          */
1495         if ((Col > 0U) ||
1496             (LengthVar < InstancePtr->Geometry.BytesPerPage)) {
1497             RemLen = InstancePtr->Geometry.BytesPerPage - Col;
1498             PartialBytes = (RemLen < (u32)LengthVar) ?
1499                     RemLen : (u32)LengthVar;
1500         }
1501 
1502         Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize);
1503 #ifdef __rtems__
1504         {
1505 #else
1506         if (Page > InstancePtr->Geometry.NumTargetPages) {
1507 #endif
1508             Page %= InstancePtr->Geometry.NumTargetPages;
1509         }
1510 
1511         /* Check if partial write */
1512         if (PartialBytes > 0U) {
1513             BufPtr = &InstancePtr->PartialDataBuf[0];
1514             (void)memset(BufPtr, 0xFF,
1515                     InstancePtr->Geometry.BytesPerPage);
1516             (void)Xil_MemCpy(BufPtr + Col, SrcBufPtr, PartialBytes);
1517 
1518             NumBytes = PartialBytes;
1519         } else {
1520             BufPtr = (u8 *)SrcBufPtr;
1521             NumBytes = (InstancePtr->Geometry.BytesPerPage <
1522                     (u32)LengthVar) ?
1523                     InstancePtr->Geometry.BytesPerPage :
1524                     (u32)LengthVar;
1525         }
1526         /* Program page */
1527         Status = XNandPsu_ProgramPage(InstancePtr, Target, Page, 0U,
1528                                 BufPtr);
1529         if (Status != XST_SUCCESS)
1530             goto Out;
1531 
1532         Status = XNandPsu_Device_Ready(InstancePtr, Target);
1533         if (Status != XST_SUCCESS)
1534             goto Out;
1535 
1536         SrcBufPtr += NumBytes;
1537         OffsetVar += NumBytes;
1538         LengthVar -= NumBytes;
1539     }
1540 
1541 Out:
1542     return Status;
1543 }
1544 
1545 /*****************************************************************************/
1546 /**
1547 *
1548 * This function reads from the flash.
1549 *
1550 * @param    InstancePtr is a pointer to the XNandPsu instance.
1551 * @param    Offset is the starting offset of flash to read.
1552 * @param    Length is the number of bytes to read.
1553 * @param    DestBuf is the destination data buffer to fill in.
1554 *
1555 * @return
1556 *       - XST_SUCCESS if successful.
1557 *       - XST_FAILURE if failed.
1558 *
1559 * @note     None
1560 *
1561 ******************************************************************************/
1562 s32 XNandPsu_Read(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *DestBuf)
1563 {
1564     /* Assert the input arguments. */
1565     Xil_AssertNonvoid(InstancePtr != NULL);
1566     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1567     Xil_AssertNonvoid(DestBuf != NULL);
1568     Xil_AssertNonvoid(Length != 0U);
1569     Xil_AssertNonvoid((Offset + Length) <=
1570                 InstancePtr->Geometry.DeviceSize);
1571 
1572     s32 Status = XST_FAILURE;
1573     u32 Page;
1574     u32 Col;
1575     u32 Target;
1576     u32 Block;
1577     u32 PartialBytes = 0U;
1578     u32 RemLen;
1579     u32 NumBytes;
1580     u8 *BufPtr;
1581     u8 *DestBufPtr = (u8 *)DestBuf;
1582     u64 OffsetVar = Offset;
1583     u64 LengthVar = Length;
1584 
1585     /*
1586      * Check if read operation exceeds flash size when including
1587      * bad blocks.
1588      */
1589     Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
1590     if (Status != XST_SUCCESS) {
1591         goto Out;
1592     }
1593 
1594     while (LengthVar > 0U) {
1595         Block = (u32)(OffsetVar/InstancePtr->Geometry.BlockSize);
1596         /*
1597          * Skip the bad block. Increment the offset by block size.
1598          * The flash programming utility must make sure to start
1599          * writing always at a block boundary and skip blocks if any.
1600          */
1601         if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) {
1602             OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
1603             continue;
1604         }
1605         /* Calculate Page and Column address values */
1606         Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage);
1607         Col = (u32) (OffsetVar &
1608                 (InstancePtr->Geometry.BytesPerPage - 1U));
1609         PartialBytes = 0U;
1610         /*
1611          * Check if partial write.
1612          * If column address is > 0 or Length is < page size
1613          */
1614         if ((Col > 0U) ||
1615             (LengthVar < InstancePtr->Geometry.BytesPerPage)) {
1616             RemLen = InstancePtr->Geometry.BytesPerPage - Col;
1617             PartialBytes = ((u32)RemLen < (u32)LengthVar) ?
1618                         (u32)RemLen : (u32)LengthVar;
1619         }
1620 
1621         Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize);
1622 #ifdef __rtems__
1623         {
1624 #else
1625         if (Page > InstancePtr->Geometry.NumTargetPages) {
1626 #endif
1627             Page %= InstancePtr->Geometry.NumTargetPages;
1628         }
1629         /* Check if partial read */
1630         if (PartialBytes > 0U) {
1631             BufPtr = &InstancePtr->PartialDataBuf[0];
1632             NumBytes = PartialBytes;
1633         } else {
1634             BufPtr = DestBufPtr;
1635             NumBytes = (InstancePtr->Geometry.BytesPerPage <
1636                     (u32)LengthVar) ?
1637                     InstancePtr->Geometry.BytesPerPage :
1638                     (u32)LengthVar;
1639         }
1640 #ifdef __rtems__
1641         if (Page == InstancePtr->PartialDataPageIndex) {
1642             /*
1643              * This is a whole page read for the currently cached
1644              * page. It will not be taken care of below, so perform
1645              * the copy here.
1646              */
1647             if (PartialBytes == 0U) {
1648                 (void)Xil_MemCpy(DestBufPtr,
1649                         &InstancePtr->PartialDataBuf[0],
1650                         NumBytes);
1651             }
1652         } else {
1653 #endif
1654         /* Read page */
1655         Status = XNandPsu_ReadPage(InstancePtr, Target, Page, 0U,
1656                                 BufPtr);
1657 #ifdef __rtems__
1658             if (PartialBytes > 0U &&
1659                 InstancePtr->PartialDataPageIndex != XNANDPSU_PAGE_CACHE_UNAVAILABLE) {
1660                 /*
1661                  * Partial read into page cache. Update the
1662                  * cached page index.
1663                  */
1664                 InstancePtr->PartialDataPageIndex = Page;
1665             }
1666         }
1667 #endif
1668         if (Status != XST_SUCCESS) {
1669             goto Out;
1670         }
1671         if (PartialBytes > 0U) {
1672             (void)Xil_MemCpy(DestBufPtr, BufPtr + Col, NumBytes);
1673 #ifdef __rtems__
1674             /* The destination buffer is touched by hardware, synchronize */
1675             if (InstancePtr->Config.IsCacheCoherent == 0) {
1676                 Xil_DCacheFlushRange((INTPTR)(void *)DestBufPtr, NumBytes);
1677             }
1678 #endif
1679         }
1680         DestBufPtr += NumBytes;
1681         OffsetVar += NumBytes;
1682         LengthVar -= NumBytes;
1683     }
1684 
1685     Status = XST_SUCCESS;
1686 Out:
1687     return Status;
1688 }
1689 
1690 /*****************************************************************************/
1691 /**
1692 *
1693 * This function erases the flash.
1694 *
1695 * @param    InstancePtr is a pointer to the XNandPsu instance.
1696 * @param    Offset is the starting offset of flash to erase.
1697 * @param    Length is the number of bytes to erase.
1698 *
1699 * @return
1700 *       - XST_SUCCESS if successful.
1701 *       - XST_FAILURE if failed.
1702 *
1703 * @note
1704 *       The Offset and Length should be aligned to block size boundary
1705 *       to get better results.
1706 *
1707 ******************************************************************************/
1708 s32 XNandPsu_Erase(XNandPsu *InstancePtr, u64 Offset, u64 Length)
1709 {
1710     /* Assert the input arguments. */
1711     Xil_AssertNonvoid(InstancePtr != NULL);
1712     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1713     Xil_AssertNonvoid(Length != 0U);
1714     Xil_AssertNonvoid((Offset + Length) <=
1715             InstancePtr->Geometry.DeviceSize);
1716 
1717     s32 Status = XST_FAILURE;
1718     u32 Target = 0;
1719     u32 StartBlock;
1720     u32 NumBlocks = 0;
1721     u32 Block;
1722     u32 AlignOff;
1723     u32 EraseLen;
1724     u32 BlockRemLen;
1725     u64 OffsetVar = Offset;
1726     u64 LengthVar = Length;
1727 
1728     /*
1729      * Check if erase operation exceeds flash size when including
1730      * bad blocks.
1731      */
1732     Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
1733     if (Status != XST_SUCCESS) {
1734         goto Out;
1735     }
1736     /* Calculate number of blocks to erase */
1737     StartBlock = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
1738 
1739     while (LengthVar > 0U) {
1740         Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
1741         if (XNandPsu_IsBlockBad(InstancePtr, Block) ==
1742                             XST_SUCCESS) {
1743             OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
1744             NumBlocks++;
1745             continue;
1746         }
1747 
1748         AlignOff = (u32)OffsetVar &
1749                 (InstancePtr->Geometry.BlockSize - (u32)1);
1750         if (AlignOff > 0U) {
1751             BlockRemLen = InstancePtr->Geometry.BlockSize -
1752                                 AlignOff;
1753             EraseLen = (BlockRemLen < (u32)LengthVar) ?
1754                         BlockRemLen :(u32)LengthVar;
1755         } else {
1756             EraseLen = (InstancePtr->Geometry.BlockSize <
1757                         (u32)LengthVar) ?
1758                     InstancePtr->Geometry.BlockSize:
1759                         (u32)LengthVar;
1760         }
1761         NumBlocks++;
1762         OffsetVar += EraseLen;
1763         LengthVar -= EraseLen;
1764     }
1765 
1766     for (Block = StartBlock; Block < (StartBlock + NumBlocks); Block++) {
1767         Target = Block/InstancePtr->Geometry.NumTargetBlocks;
1768 #ifdef __rtems__
1769         u32 ModBlock = Block % InstancePtr->Geometry.NumTargetBlocks;
1770 #else
1771         Block %= InstancePtr->Geometry.NumTargetBlocks;
1772 #endif
1773         /* Don't erase bad block */
1774         if (XNandPsu_IsBlockBad(InstancePtr, Block) ==
1775                             XST_SUCCESS)
1776             continue;
1777         /* Block Erase */
1778 #ifdef __rtems__
1779         Status = XNandPsu_EraseBlock(InstancePtr, Target, ModBlock);
1780 #else
1781         Status = XNandPsu_EraseBlock(InstancePtr, Target, Block);
1782 #endif
1783         if (Status != XST_SUCCESS)
1784             goto Out;
1785 
1786         Status = XNandPsu_Device_Ready(InstancePtr, Target);
1787         if (Status != XST_SUCCESS)
1788                     goto Out;
1789 
1790                 }
1791 Out:
1792     return Status;
1793 }
1794 
1795 /*****************************************************************************/
1796 /**
1797 *
1798 * This function sends ONFI Program Page command to flash.
1799 *
1800 * @param    InstancePtr is a pointer to the XNandPsu instance.
1801 * @param    Target is the chip select value.
1802 * @param    Page is the page address value to program.
1803 * @param    Col is the column address value to program.
1804 * @param    Buf is the data buffer to program.
1805 *
1806 * @return
1807 *       - XST_SUCCESS if successful.
1808 *       - XST_FAILURE if failed.
1809 *
1810 * @note     None
1811 *
1812 ******************************************************************************/
1813 static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
1814                             u32 Col, u8 *Buf)
1815 {
1816     u32 PktSize;
1817     u32 PktCount;
1818     s32 Status = XST_FAILURE;
1819     u32 IsrValue;
1820     u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
1821                 InstancePtr->Geometry.ColAddrCycles;
1822 
1823     if (InstancePtr->EccCfg.CodeWordSize > 9U) {
1824         PktSize = 1024U;
1825     } else {
1826         PktSize = 512U;
1827     }
1828     PktCount = InstancePtr->Geometry.BytesPerPage/PktSize;
1829 
1830     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1, ONFI_CMD_PG_PROG2,
1831                     1U, 1U, (u8)AddrCycles);
1832 
1833     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
1834         IsrValue = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
1835                XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
1836         if (InstancePtr->Config.IsCacheCoherent == 0) {
1837             Xil_DCacheFlushRange((INTPTR)(void *)Buf, (PktSize * PktCount));
1838         }
1839         XNandPsu_Update_DmaAddr(InstancePtr, Buf);
1840     } else {
1841         IsrValue = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK;
1842     }
1843 
1844         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1845                XNANDPSU_INTR_STS_EN_OFFSET, IsrValue);
1846     /* Program Page Size */
1847     XNandPsu_SetPageSize(InstancePtr);
1848     /* Program Packet Size and Packet Count */
1849     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
1850     /* Program Column, Page, Block address */
1851     XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col);
1852     /* Program Memory Address Register2 for chip select */
1853     XNandPsu_SelectChip(InstancePtr, Target);
1854     /* Set ECC */
1855     if (InstancePtr->EccMode == XNANDPSU_HWECC) {
1856         XNandPsu_SetEccSpareCmd(InstancePtr, ONFI_CMD_CHNG_WR_COL,
1857                     InstancePtr->Geometry.ColAddrCycles);
1858     }
1859     /* Set Page Program in Program Register */
1860     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1861             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK);
1862 
1863 
1864     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 1);
1865 
1866     return Status;
1867 }
1868 
1869 /*****************************************************************************/
1870 /**
1871 *
1872 * This function sends ONFI Program Page command to flash.
1873 *
1874 * @param    InstancePtr is a pointer to the XNandPsu instance.
1875 * @param    Page is the page address value to program.
1876 * @param    Buf is the data buffer to program.
1877 *
1878 * @return
1879 *       - XST_SUCCESS if successful.
1880 *       - XST_FAILURE if failed.
1881 *
1882 * @note     None
1883 *
1884 ******************************************************************************/
1885 s32 XNandPsu_WriteSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf)
1886 {
1887     /* Assert the input arguments. */
1888     Xil_AssertNonvoid(InstancePtr != NULL);
1889     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1890     Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages);
1891     Xil_AssertNonvoid(Buf != NULL);
1892 
1893     u32 PktCount = 1U;
1894     u16 PreEccSpareCol = 0U;
1895     u16 PreEccSpareWrCnt = 0U;
1896     u16 PostEccSpareCol = 0U;
1897     u16 PostEccSpareWrCnt = 0U;
1898     u32 PostWrite = 0U;
1899     OnfiCmdFormat Cmd;
1900     s32 Status = XST_FAILURE;
1901     u32 RegVal;
1902     u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
1903                 InstancePtr->Geometry.ColAddrCycles;
1904     u32 Col = InstancePtr->Geometry.BytesPerPage;
1905     u32 Target = Page/InstancePtr->Geometry.NumTargetPages;
1906     u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage;
1907     u32 *BufPtr = (u32 *)(void *)Buf;
1908     u32 PageVar = Page;
1909 
1910     PageVar %= InstancePtr->Geometry.NumTargetPages;
1911 
1912     if (InstancePtr->EccMode == XNANDPSU_HWECC) {
1913         /* Calculate ECC free positions before and after ECC code */
1914         PreEccSpareCol = 0x0U;
1915         PreEccSpareWrCnt = InstancePtr->EccCfg.EccAddr -
1916                 (u16)InstancePtr->Geometry.BytesPerPage;
1917 
1918         PostEccSpareCol = PreEccSpareWrCnt +
1919                     InstancePtr->EccCfg.EccSize;
1920         PostEccSpareWrCnt = InstancePtr->Geometry.SpareBytesPerPage -
1921                     PostEccSpareCol;
1922 
1923         PreEccSpareWrCnt = (PreEccSpareWrCnt/4U) * 4U;
1924         PostEccSpareWrCnt = (PostEccSpareWrCnt/4U) * 4U;
1925 
1926         if (PreEccSpareWrCnt > 0U) {
1927             PktSize = PreEccSpareWrCnt;
1928             PktCount = 1U;
1929             Col = InstancePtr->Geometry.BytesPerPage +
1930                             PreEccSpareCol;
1931             BufPtr = (u32 *)(void *)Buf;
1932             if (PostEccSpareWrCnt > 0U) {
1933                 PostWrite = 1U;
1934             }
1935         } else if (PostEccSpareWrCnt > 0U) {
1936             PktSize = PostEccSpareWrCnt;
1937             PktCount = 1U;
1938             Col = InstancePtr->Geometry.BytesPerPage +
1939                             PostEccSpareCol;
1940             BufPtr = (u32 *)(Buf + Col);
1941         } else {
1942             /* No free spare bytes available for writing */
1943             Status = XST_FAILURE;
1944             goto Out;
1945         }
1946     }
1947 
1948     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
1949         RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK;
1950         if (InstancePtr->Config.IsCacheCoherent == 0) {
1951             Xil_DCacheFlushRange((INTPTR)(void *)BufPtr, (PktSize * PktCount));
1952         }
1953         XNandPsu_Update_DmaAddr(InstancePtr, (u8 *)BufPtr);
1954     } else {
1955         RegVal = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK;
1956     }
1957 
1958         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1959                XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
1960     /* Program Command hack for change write column */
1961     if (PostWrite > 0U) {
1962         Cmd.Command1 = 0x80U;
1963         Cmd.Command2 = 0x00U;
1964         XNandPsu_Prepare_Cmd(InstancePtr, Cmd.Command1, Cmd.Command2,
1965                 0U , 1U, (u8)AddrCycles);
1966 
1967     } else {
1968         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1,
1969                 ONFI_CMD_PG_PROG2, 0U , 1U, (u8)AddrCycles);
1970     }
1971     /* Program Page Size */
1972     XNandPsu_SetPageSize(InstancePtr);
1973     /* Program Packet Size and Packet Count */
1974     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
1975     /* Program Column, Page, Block address */
1976     XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col);
1977     /* Program Memory Address Register2 for chip select */
1978     XNandPsu_SelectChip(InstancePtr, Target);
1979     /* Set Page Program in Program Register */
1980     if (PostWrite > 0U) {
1981         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1982             XNANDPSU_PROG_OFFSET,((u32)XNANDPSU_PROG_PG_PROG_MASK |
1983                 (u32)XNANDPSU_PROG_CHNG_ROW_ADDR_MASK));
1984     } else {
1985     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1986             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK);
1987     }
1988 
1989     Status = XNandPsu_Data_ReadWrite(InstancePtr, (u8 *)BufPtr, PktCount,
1990                      PktSize, 1, 1);
1991 
1992     if (InstancePtr->EccMode == XNANDPSU_HWECC) {
1993         if (PostWrite > 0U) {
1994             BufPtr = (u32 *)(Buf + PostEccSpareCol);
1995             Status = XNandPsu_ChangeWriteColumn(InstancePtr,
1996                     Target,
1997                     PostEccSpareCol, PostEccSpareWrCnt, 1U,
1998                     (u8 *)(void *)BufPtr);
1999             if (Status != XST_SUCCESS) {
2000                 goto Out;
2001             }
2002         }
2003     }
2004 Out:
2005     return Status;
2006 }
2007 
2008 /*****************************************************************************/
2009 /**
2010 *
2011 * This function sends ONFI Read Page command to flash.
2012 *
2013 * @param    InstancePtr is a pointer to the XNandPsu instance.
2014 * @param    Target is the chip select value.
2015 * @param    Page is the page address value to read.
2016 * @param    Col is the column address value to read.
2017 * @param    Buf is the data buffer to fill in.
2018 *
2019 * @return
2020 *       - XST_SUCCESS if successful.
2021 *       - XST_FAILURE if failed.
2022 *
2023 * @note     None
2024 *
2025 ******************************************************************************/
2026 static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
2027                             u32 Col, u8 *Buf)
2028 {
2029     u32 PktSize;
2030     u32 PktCount;
2031     s32 Status = XST_FAILURE;
2032     u32 RegVal;
2033     u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
2034                 InstancePtr->Geometry.ColAddrCycles;
2035 
2036     if (InstancePtr->EccCfg.CodeWordSize > 9U) {
2037         PktSize = 1024U;
2038     } else {
2039         PktSize = 512U;
2040     }
2041     PktCount = InstancePtr->Geometry.BytesPerPage/PktSize;
2042 
2043     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2,
2044                     1U, 1U, (u8)AddrCycles);
2045 
2046     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2047         RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
2048              XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
2049         if (InstancePtr->Config.IsCacheCoherent == 0) {
2050             Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
2051         }
2052         XNandPsu_Update_DmaAddr(InstancePtr, Buf);
2053     } else {
2054         RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK;
2055     }
2056     /* Enable Single bit error and Multi bit error */
2057     if (InstancePtr->EccMode == XNANDPSU_HWECC)
2058         RegVal |= XNANDPSU_INTR_STS_EN_MUL_BIT_ERR_STS_EN_MASK |
2059              XNANDPSU_INTR_STS_EN_ERR_INTR_STS_EN_MASK;
2060 
2061     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2062               XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
2063     /* Program Page Size */
2064     XNandPsu_SetPageSize(InstancePtr);
2065     /* Program Column, Page, Block address */
2066     XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col);
2067     /* Program Packet Size and Packet Count */
2068     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2069     /* Program Memory Address Register2 for chip select */
2070     XNandPsu_SelectChip(InstancePtr, Target);
2071     /* Set ECC */
2072     if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2073         XNandPsu_SetEccSpareCmd(InstancePtr,
2074                     (ONFI_CMD_CHNG_RD_COL1 |
2075                     (ONFI_CMD_CHNG_RD_COL2 << (u8)8U)),
2076                     InstancePtr->Geometry.ColAddrCycles);
2077     }
2078 
2079     /* Set Read command in Program Register */
2080     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2081                 XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
2082 
2083     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1);
2084 
2085 #ifdef __rtems__
2086     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2087         if (InstancePtr->Config.IsCacheCoherent == 0) {
2088             Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
2089         }
2090     }
2091 #endif
2092 
2093     /* Check ECC Errors */
2094     if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2095         /* Hamming Multi Bit Errors */
2096         if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
2097                 XNANDPSU_INTR_STS_OFFSET) &
2098             (u32)XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK) != 0U) {
2099 
2100             XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2101                 XNANDPSU_INTR_STS_OFFSET,
2102                 XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK);
2103 
2104 #ifdef XNANDPSU_DEBUG
2105             xil_printf("%s: ECC Hamming multi bit error\r\n",
2106                             __func__);
2107 #endif
2108             InstancePtr->Ecc_Stat_PerPage_flips =
2109                     ((XNandPsu_ReadReg(
2110                     InstancePtr->Config.BaseAddress,
2111                     XNANDPSU_ECC_ERR_CNT_OFFSET) &
2112                     0x1FF00U) >> 8U);
2113             InstancePtr->Ecc_Stats_total_flips +=
2114                     InstancePtr->Ecc_Stat_PerPage_flips;
2115             Status = XST_FAILURE;
2116         }
2117         /* Hamming Single Bit or BCH Errors */
2118         if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
2119                 XNANDPSU_INTR_STS_OFFSET) &
2120             (u32)XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK) != 0U) {
2121 
2122             XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2123                     XNANDPSU_INTR_STS_OFFSET,
2124                     XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK);
2125 
2126             if (InstancePtr->EccCfg.IsBCH == 1U) {
2127                 InstancePtr->Ecc_Stat_PerPage_flips =
2128                         ((XNandPsu_ReadReg(
2129                         InstancePtr->Config.BaseAddress,
2130                         XNANDPSU_ECC_ERR_CNT_OFFSET)&
2131                         0x1FF00U) >> 8U);
2132                 InstancePtr->Ecc_Stats_total_flips +=
2133                     InstancePtr->Ecc_Stat_PerPage_flips;
2134                 Status = XST_SUCCESS;
2135             }
2136         }
2137     }
2138 
2139     return Status;
2140 }
2141 
2142 /*****************************************************************************/
2143 /**
2144 *
2145 * This function reads spare bytes from flash.
2146 *
2147 * @param    InstancePtr is a pointer to the XNandPsu instance.
2148 * @param    Page is the page address value to read.
2149 * @param    Buf is the data buffer to fill in.
2150 *
2151 * @return
2152 *       - XST_SUCCESS if successful.
2153 *       - XST_FAILURE if failed.
2154 *
2155 * @note     None
2156 *
2157 ******************************************************************************/
2158 s32 XNandPsu_ReadSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf)
2159 {
2160     /* Assert the input arguments. */
2161     Xil_AssertNonvoid(InstancePtr != NULL);
2162     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
2163     Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages);
2164     Xil_AssertNonvoid(Buf != NULL);
2165 
2166     u32 PktCount = 1U;
2167     s32 Status = XST_FAILURE;
2168     u32 RegVal;
2169     u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
2170                 InstancePtr->Geometry.ColAddrCycles;
2171     u32 Col = InstancePtr->Geometry.BytesPerPage;
2172     u32 Target = Page/InstancePtr->Geometry.NumTargetPages;
2173     u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage;
2174     u32 PageVar = Page;
2175 
2176     PageVar %= InstancePtr->Geometry.NumTargetPages;
2177 
2178     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2179         RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK;
2180         if (InstancePtr->Config.IsCacheCoherent == 0) {
2181             Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
2182         }
2183         XNandPsu_Update_DmaAddr(InstancePtr, Buf);
2184     } else {
2185         RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK;
2186     }
2187         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2188                XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
2189     /* Program Command */
2190     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2, 0U,
2191                         1U, (u8)AddrCycles);
2192     /* Program Page Size */
2193     XNandPsu_SetPageSize(InstancePtr);
2194     /* Program Column, Page, Block address */
2195     XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col);
2196     /* Program Packet Size and Packet Count */
2197     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2198     /* Program Memory Address Register2 for chip select */
2199     XNandPsu_SelectChip(InstancePtr, Target);
2200     /* Set Read command in Program Register */
2201     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2202                 XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
2203 
2204     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1);
2205 
2206 #ifdef __rtems__
2207     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2208         if (InstancePtr->Config.IsCacheCoherent == 0) {
2209             Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
2210         }
2211     }
2212 #endif
2213 
2214     return Status;
2215 }
2216 
2217 /*****************************************************************************/
2218 /**
2219 *
2220 * This function sends ONFI block erase command to the flash.
2221 *
2222 * @param    InstancePtr is a pointer to the XNandPsu instance.
2223 * @param    Target is the chip select value.
2224 * @param    Block is the block to erase.
2225 *
2226 * @return
2227 *       - XST_SUCCESS if successful.
2228 *       - XST_FAILURE if failed.
2229 *
2230 * @note     None
2231 *
2232 ******************************************************************************/
2233 s32 XNandPsu_EraseBlock(XNandPsu *InstancePtr, u32 Target, u32 Block)
2234 {
2235     /* Assert the input arguments. */
2236     Xil_AssertNonvoid(InstancePtr != NULL);
2237     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
2238     Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
2239 #ifdef __rtems__
2240     Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumTargetBlocks);
2241 #else
2242     Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
2243 #endif
2244 
2245     s32 Status = XST_FAILURE;
2246     u32 Page;
2247     u32 ErasePage;
2248     u32 EraseCol;
2249     u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles;
2250 
2251     Page = Block * InstancePtr->Geometry.PagesPerBlock;
2252     ErasePage = (Page >> 16U) & 0xFFFFU;
2253     EraseCol = Page & 0xFFFFU;
2254 
2255     /*
2256      * Enable Transfer Complete Interrupt in Interrupt Status Enable
2257      * Register
2258      */
2259     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2260             XNANDPSU_INTR_STS_EN_OFFSET,
2261             XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
2262 
2263     /* Program Command */
2264     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_BLK_ERASE1,
2265             ONFI_CMD_BLK_ERASE2, 0U , 0U, (u8)AddrCycles);
2266     /* Program Column, Page, Block address */
2267     XNandPsu_SetPageColAddr(InstancePtr, ErasePage, (u16)EraseCol);
2268     /* Program Memory Address Register2 for chip select */
2269     XNandPsu_SelectChip(InstancePtr, Target);
2270     /* Set Block Erase in Program Register */
2271     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2272             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_BLK_ERASE_MASK);
2273     /* Poll for Transfer Complete event */
2274     Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
2275     return Status;
2276 }
2277 
2278 /*****************************************************************************/
2279 /**
2280 *
2281 * This function sends ONFI Get Feature command to flash.
2282 *
2283 * @param    InstancePtr is a pointer to the XNandPsu instance.
2284 * @param    Target is the chip select value.
2285 * @param    Feature is the feature selector.
2286 * @param    Buf is the buffer to fill feature value.
2287 *
2288 * @return
2289 *       - XST_SUCCESS if successful.
2290 *       - XST_FAILURE if failed.
2291 *
2292 * @note     None
2293 *
2294 ******************************************************************************/
2295 s32 XNandPsu_GetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
2296                                 u8 *Buf)
2297 {
2298     /* Assert the input arguments. */
2299     Xil_AssertNonvoid(InstancePtr != NULL);
2300     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
2301     Xil_AssertNonvoid(Buf != NULL);
2302     Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
2303 
2304     s32 Status;
2305     u32 PktSize = 4;
2306     u32 PktCount = 1;
2307 
2308     if (InstancePtr->DataInterface == XNANDPSU_NVDDR) {
2309         PktSize = 8U;
2310     }
2311 
2312     /*
2313      * Enable Buffer Read Ready Interrupt in Interrupt Status
2314      * Enable Register
2315      */
2316     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2317             XNANDPSU_INTR_STS_EN_OFFSET,
2318             XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
2319     /* Program Command */
2320     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_GET_FEATURES,
2321                 ONFI_CMD_INVALID, 0U, 0U, 1U);
2322     /* Program Column, Page, Block address */
2323     XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature);
2324     /* Program Memory Address Register2 for chip select */
2325     XNandPsu_SelectChip(InstancePtr, Target);
2326     /* Program Packet Size and Packet Count */
2327     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2328     /* Set Read Parameter Page in Program Register */
2329     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2330             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_GET_FEATURES_MASK);
2331 
2332     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 0);
2333 
2334     return Status;
2335 }
2336 
2337 /*****************************************************************************/
2338 /**
2339 *
2340 * This function sends ONFI Set Feature command to flash.
2341 *
2342 * @param    InstancePtr is a pointer to the XNandPsu instance.
2343 * @param    Target is the chip select value.
2344 * @param    Feature is the feature selector.
2345 * @param    Buf is the feature value to send.
2346 *
2347 * @return
2348 *       - XST_SUCCESS if successful.
2349 *       - XST_FAILURE if failed.
2350 *
2351 * @note     None
2352 *
2353 ******************************************************************************/
2354 s32 XNandPsu_SetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
2355                                 u8 *Buf)
2356 {
2357     /* Assert the input arguments. */
2358     Xil_AssertNonvoid(InstancePtr != NULL);
2359     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
2360     Xil_AssertNonvoid(Buf != NULL);
2361     Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
2362 
2363     s32 Status;
2364     u32 PktSize = 4U;
2365     u32 PktCount = 1U;
2366 
2367     if (InstancePtr->DataInterface == XNANDPSU_NVDDR) {
2368         PktSize = 8U;
2369     }
2370 
2371     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2372             XNANDPSU_INTR_STS_EN_OFFSET, 0U);
2373 
2374     /*
2375      * Enable Buffer Write Ready Interrupt in Interrupt Status
2376      * Enable Register
2377      */
2378     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2379             XNANDPSU_INTR_STS_EN_OFFSET,
2380             XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
2381 
2382     /* Program Command */
2383     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_SET_FEATURES,
2384                 ONFI_CMD_INVALID, 0U , 0U, 1U);
2385     /* Program Column, Page, Block address */
2386     XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature);
2387     /* Program Memory Address Register2 for chip select */
2388     XNandPsu_SelectChip(InstancePtr, Target);
2389     /* Program Packet Size and Packet Count */
2390     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2391     /* Set Read Parameter Page in Program Register */
2392     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2393             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_SET_FEATURES_MASK);
2394 
2395     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 0);
2396     return Status;
2397 }
2398 
2399 /*****************************************************************************/
2400 /**
2401 *
2402 * This function changes clock frequency of flash controller.
2403 *
2404 * @param    InstancePtr is a pointer to the XNandPsu instance.
2405 * @param    ClockFreq is the clock frequency to change.
2406 *
2407 * @return
2408 *       None
2409 *
2410 * @note     None
2411 *
2412 ******************************************************************************/
2413 static void XNandPsu_ChangeClockFreq(XNandPsu *InstancePtr, u32 ClockFreq)
2414 {
2415     (void) InstancePtr;
2416     (void) ClockFreq;
2417 
2418     /* Not implemented */
2419 }
2420 /*****************************************************************************/
2421 /**
2422 *
2423 * This function changes the data interface and timing mode.
2424 *
2425 * @param    InstancePtr is a pointer to the XNandPsu instance.
2426 * @param    NewIntf is the new data interface.
2427 * @param    NewMode is the new timing mode.
2428 *
2429 * @return
2430 *       - XST_SUCCESS if successful.
2431 *       - XST_FAILURE if failed.
2432 *
2433 * @note     None
2434 *
2435 ******************************************************************************/
2436 s32 XNandPsu_ChangeTimingMode(XNandPsu *InstancePtr,
2437                 XNandPsu_DataInterface NewIntf,
2438                 XNandPsu_TimingMode NewMode)
2439 {
2440     /* Assert the input arguments. */
2441     Xil_AssertNonvoid(InstancePtr != NULL);
2442     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
2443 
2444     s32 Status = XST_SUCCESS;
2445     u32 Target;
2446     u32 RegVal;
2447     u8 Buf[4] = {0U};
2448     u32 *Feature = (u32 *)(void *)&Buf[0];
2449     u32 SetFeature = 0U;
2450     u32 NewModeVar = (u32)NewMode;
2451 
2452     /* Check for valid input arguments */
2453     if(((NewIntf != XNANDPSU_SDR) && (NewIntf != XNANDPSU_NVDDR)) ||
2454             (NewModeVar > 5U)){
2455         Status = XST_FAILURE;
2456         goto Out;
2457     }
2458 
2459     if(NewIntf == XNANDPSU_NVDDR){
2460         NewModeVar = NewModeVar | (u32)0x10;
2461     }
2462     /* Get current data interface type and timing mode */
2463     XNandPsu_DataInterface CurIntf = InstancePtr->DataInterface;
2464     XNandPsu_TimingMode CurMode = InstancePtr->TimingMode;
2465 
2466     /* Check if the flash is in same mode */
2467     if ((CurIntf == NewIntf) && (CurMode == NewModeVar)) {
2468         Status = XST_SUCCESS;
2469         goto Out;
2470     }
2471 
2472     if ((CurIntf == XNANDPSU_NVDDR) && (NewIntf == XNANDPSU_SDR)) {
2473 
2474         NewModeVar = XNANDPSU_SDR0;
2475 
2476         /* Change the clock frequency */
2477         XNandPsu_ChangeClockFreq(InstancePtr, XNANDPSU_SDR_CLK);
2478 
2479         /* Update Data Interface Register */
2480         RegVal = ((NewModeVar % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) |
2481                 ((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT);
2482         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2483                     XNANDPSU_DATA_INTF_OFFSET, RegVal);
2484 
2485         for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
2486                             Target++) {
2487             Status = XNandPsu_OnfiReset(InstancePtr, Target);
2488             if (Status != XST_SUCCESS) {
2489                 goto Out;
2490             }
2491         }
2492 
2493         /* Set Feature */
2494         for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
2495                                 Target++) {
2496             Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U,
2497                             (u8 *)(void *)&NewModeVar);
2498             if (Status != XST_SUCCESS) {
2499                 goto Out;
2500             }
2501         }
2502 
2503         InstancePtr->DataInterface = NewIntf;
2504         InstancePtr->TimingMode = NewModeVar;
2505 
2506         for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
2507                                 Target++) {
2508             Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U,
2509                                 &Buf[0]);
2510             if (Status != XST_SUCCESS) {
2511                 goto Out;
2512             }
2513             /* Check if set_feature was successful */
2514             if (*Feature != NewModeVar) {
2515                 Status = XST_FAILURE;
2516                 goto Out;
2517             }
2518         }
2519 
2520         goto Out;
2521     }
2522 
2523     SetFeature = NewModeVar;
2524     if((CurIntf == XNANDPSU_NVDDR) && (NewIntf == XNANDPSU_NVDDR)){
2525         SetFeature |= SetFeature << 8U;
2526     }
2527     /* Set Feature */
2528     for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
2529                             Target++) {
2530         Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U,
2531                         (u8 *)(void *)&SetFeature);
2532         if (Status != XST_SUCCESS) {
2533             goto Out;
2534         }
2535     }
2536 
2537     InstancePtr->DataInterface = NewIntf;
2538     InstancePtr->TimingMode = NewModeVar;
2539     /* Update Data Interface Register */
2540     RegVal = ((NewMode % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) |
2541             ((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT);
2542     XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2543                 XNANDPSU_DATA_INTF_OFFSET, RegVal);
2544 
2545     /* Get Feature */
2546     for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
2547                             Target++) {
2548         Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U,
2549                             &Buf[0]);
2550         if (Status != XST_SUCCESS) {
2551             goto Out;
2552         }
2553 
2554         /* Check if set_feature was successful */
2555         if (*Feature != NewModeVar) {
2556             Status = XST_FAILURE;
2557             goto Out;
2558         }
2559     }
2560 
2561 Out:
2562     return Status;
2563 }
2564 
2565 /*****************************************************************************/
2566 /**
2567 *
2568 * This function issues change read column and reads the data into buffer
2569 * specified by user.
2570 *
2571 * @param    InstancePtr is a pointer to the XNandPsu instance.
2572 * @param    Target is the chip select value.
2573 * @param    Col is the coulmn address.
2574 * @param    PktSize is the number of bytes to read.
2575 * @param    PktCount is the number of transactions to read.
2576 * @param    Buf is the data buffer to fill in.
2577 *
2578 * @return
2579 *       - XST_SUCCESS if successful.
2580 *       - XST_FAILURE if failed.
2581 *
2582 * @note     None
2583 *
2584 ******************************************************************************/
2585 static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target,
2586                     u32 Col, u32 PktSize, u32 PktCount,
2587                     u8 *Buf)
2588 {
2589     s32 Status = XST_FAILURE;
2590     u32 RegVal;
2591     u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles;
2592 
2593     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2594         RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
2595              XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
2596         Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount));
2597         XNandPsu_Update_DmaAddr(InstancePtr, Buf);
2598     } else {
2599         RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK;
2600     }
2601 
2602         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2603                XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
2604     /* Program Command */
2605     XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_CHNG_RD_COL1,
2606             ONFI_CMD_CHNG_RD_COL2, 0U , 1U, (u8)AddrCycles);
2607     /* Program Page Size */
2608     XNandPsu_SetPageSize(InstancePtr);
2609     /* Program Column, Page, Block address */
2610     XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col);
2611     /* Program Packet Size and Packet Count */
2612     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2613     /* Program Memory Address Register2 for chip select */
2614     XNandPsu_SelectChip(InstancePtr, Target);
2615     /* Set Read command in Program Register */
2616     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2617             XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
2618 
2619     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1);
2620 
2621     return Status;
2622 }
2623 
2624 /*****************************************************************************/
2625 /**
2626 *
2627 * This function issues change read column and reads the data into buffer
2628 * specified by user.
2629 *
2630 * @param    InstancePtr is a pointer to the XNandPsu instance.
2631 * @param    Target is the chip select value.
2632 * @param    Col is the coulmn address.
2633 * @param    PktSize is the number of bytes to read.
2634 * @param    PktCount is the number of transactions to read.
2635 * @param    Buf is the data buffer to fill in.
2636 *
2637 * @return
2638 *       - XST_SUCCESS if successful.
2639 *       - XST_FAILURE if failed.
2640 *
2641 * @note     None
2642 *
2643 ******************************************************************************/
2644 static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target,
2645                     u32 Col, u32 PktSize, u32 PktCount,
2646                     u8 *Buf)
2647 {
2648     s32 Status = XST_FAILURE;
2649     OnfiCmdFormat OnfiCommand;
2650     u32 RegVal;
2651     u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles;
2652 
2653     if (PktCount == 0U) {
2654         return XST_SUCCESS;
2655     }
2656 
2657     if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2658         RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
2659              XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK;
2660 #ifdef __rtems__
2661         if (InstancePtr->Config.IsCacheCoherent == 0) {
2662             Xil_DCacheFlushRange((INTPTR)(void *)Buf, (PktSize * PktCount));
2663         }
2664 #endif
2665         XNandPsu_Update_DmaAddr(InstancePtr, Buf);
2666     } else {
2667         RegVal = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK;
2668     }
2669 
2670         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2671                XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
2672     /* Change write column hack */
2673     OnfiCommand.Command1 = 0x85U;
2674     OnfiCommand.Command2 = 0x10U;
2675     XNandPsu_Prepare_Cmd(InstancePtr, OnfiCommand.Command1,
2676                 OnfiCommand.Command2, 0U , 0U, (u8)AddrCycles);
2677 
2678     /* Program Page Size */
2679     XNandPsu_SetPageSize(InstancePtr);
2680     /* Program Column, Page, Block address */
2681     XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col);
2682     /* Program Packet Size and Packet Count */
2683     XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2684     /* Program Memory Address Register2 for chip select */
2685     XNandPsu_SelectChip(InstancePtr, Target);
2686     /* Set Page Program in Program Register */
2687     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2688         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_CHNG_ROW_ADDR_END_MASK);
2689 
2690     Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 0);
2691     return Status;
2692 }
2693 
2694 /*****************************************************************************/
2695 /**
2696 *
2697 * This function initializes extended parameter page ECC information.
2698 *
2699 * @param    InstancePtr is a pointer to the XNandPsu instance.
2700 * @param    ExtPrm is the Extended parameter page buffer.
2701 *
2702 * @return
2703 *       - XST_SUCCESS if successful.
2704 *       - XST_FAILURE if failed.
2705 *
2706 * @note     None
2707 *
2708 ******************************************************************************/
2709 static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm)
2710 {
2711     s32 Status = XST_FAILURE;
2712     u32 Offset = 0U;
2713     u32 Found = 0U;
2714     OnfiExtEccBlock *EccBlock;
2715 
2716     if (ExtPrm->Section0Type != 0x2U) {
2717         Offset += (u32)ExtPrm->Section0Len;
2718         if (ExtPrm->Section1Type != 0x2U) {
2719 #ifdef XNANDPSU_DEBUG
2720         xil_printf("%s: Extended ECC section not found\r\n",__func__);
2721 #endif
2722             Status = XST_FAILURE;
2723         } else {
2724             Found = 1U;
2725         }
2726     } else {
2727         Found = 1U;
2728     }
2729 
2730     if (Found != 0U) {
2731         EccBlock = (OnfiExtEccBlock *)&ExtPrm->SectionData[Offset];
2732         Xil_AssertNonvoid(EccBlock != NULL);
2733         if (EccBlock->CodeWordSize == 0U) {
2734             Status = XST_FAILURE;
2735         } else {
2736             InstancePtr->Geometry.NumBitsECC =
2737                         EccBlock->NumEccBits;
2738             InstancePtr->Geometry.EccCodeWordSize =
2739                         (u32)EccBlock->CodeWordSize;
2740             Status = XST_SUCCESS;
2741         }
2742     }
2743     return Status;
2744 }
2745 
2746 /*****************************************************************************/
2747 /**
2748 *
2749 * This function prepares command to be written into command register.
2750 *
2751 * @param    InstancePtr is a pointer to the XNandPsu instance.
2752 * @param    Cmd1 is the first Onfi Command.
2753 * @param    Cmd2 is the second Onfi Command.
2754 * @param    EccState is the flag to set Ecc State.
2755 * @param    DmaMode is the flag to set DMA mode.
2756 * @param    AddrCycles is the number of Address Cycles.
2757 *
2758 * @return
2759 *       None
2760 *
2761 * @note     None
2762 *
2763 ******************************************************************************/
2764 void XNandPsu_Prepare_Cmd(XNandPsu *InstancePtr, u8 Cmd1, u8 Cmd2, u8 EccState,
2765             u8 DmaMode, u8 AddrCycles)
2766 {
2767     Xil_AssertVoid(InstancePtr != NULL);
2768 
2769     u32 RegValue = 0U;
2770 
2771     RegValue = (u32)Cmd1 | (((u32)Cmd2 << (u32)XNANDPSU_CMD_CMD2_SHIFT) &
2772             (u32)XNANDPSU_CMD_CMD2_MASK);
2773 
2774     if ((EccState != 0U) && (InstancePtr->EccMode == XNANDPSU_HWECC)) {
2775         RegValue |= 1U << XNANDPSU_CMD_ECC_ON_SHIFT;
2776     }
2777 
2778     if ((DmaMode != 0U) && (InstancePtr->DmaMode == XNANDPSU_MDMA)) {
2779         RegValue |= XNANDPSU_MDMA << XNANDPSU_CMD_DMA_EN_SHIFT;
2780     }
2781 
2782     if (AddrCycles != 0U) {
2783         RegValue |= (u32)AddrCycles <<
2784                 (u32)XNANDPSU_CMD_ADDR_CYCLES_SHIFT;
2785     }
2786 
2787     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2788             XNANDPSU_CMD_OFFSET, RegValue);
2789 }
2790 
2791 /*****************************************************************************/
2792 /**
2793 *
2794 * This function Read/Writes data from the nand controller.
2795 *
2796 * @param    InstancePtr is a pointer to the XNandPsu instance.
2797 * @param    Buf is the data buffer.
2798 * @param    PktCount is the number packet chunks.
2799 * @param    PktSize is the size of the packet.
2800 * @param    Operation is 1 for write and 0 for read.
2801 * @param    DmaMode is 1 for Dma and 0 for PIO.
2802 *
2803 * @return
2804 *       - XST_SUCCESS if successful.
2805 *       - XST_FAILURE if failed.
2806 *
2807 * @note     None
2808 *
2809 ******************************************************************************/
2810 static s32 XNandPsu_Data_ReadWrite(XNandPsu *InstancePtr, u8* Buf, u32 PktCount,
2811                 u32 PktSize, u32 Operation, u8 DmaMode)
2812 {
2813     u32 BufRwCnt = 0U;
2814     s32 Status = XST_FAILURE;
2815     u32 Event = XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK;
2816 
2817     if ((DmaMode != 0U) && (InstancePtr->DmaMode == XNANDPSU_MDMA))
2818         goto DmaDone;
2819 
2820     if (Operation)
2821         Event = XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK;
2822 
2823     while (BufRwCnt < PktCount) {
2824         /* Poll for Buffer Write Ready event */
2825         Status = XNandPsu_PollRegTimeout(InstancePtr,
2826                 XNANDPSU_INTR_STS_OFFSET, Event,
2827                 XNANDPSU_INTR_POLL_TIMEOUT);
2828         if (Status != XST_SUCCESS) {
2829             xil_printf("%s: Poll for buf write ready timeout\r\n",
2830                     __func__);
2831             goto Out;
2832         }
2833 
2834         /* Increment Buffer Write Interrupt Count */
2835         BufRwCnt++;
2836 
2837         if (BufRwCnt == PktCount)
2838             XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2839                 XNANDPSU_INTR_STS_EN_OFFSET,
2840                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
2841 
2842         else
2843             XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2844                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
2845         /*
2846              * Clear Buffer Write Ready Interrupt in Interrupt Status
2847          * Register
2848          */
2849         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2850             XNANDPSU_INTR_STS_OFFSET, Event);
2851         /* Write Packet Data to Data Port Register */
2852         if (Operation)
2853             XNandPsu_Fifo_Write(InstancePtr, Buf, PktSize);
2854         else
2855             XNandPsu_Fifo_Read(InstancePtr, Buf, PktSize);
2856 
2857         Buf += PktSize;
2858 
2859         if (BufRwCnt < PktCount)
2860             XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2861                 XNANDPSU_INTR_STS_EN_OFFSET, Event);
2862         else
2863             break;
2864     }
2865 
2866 DmaDone:
2867     Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr);
2868 Out:
2869     return Status;
2870 }
2871 
2872 /*****************************************************************************/
2873 /**
2874 *
2875 * This function writes data to the fifo.
2876 *
2877 * @param    InstancePtr is a pointer to the XNandPsu instance.
2878 * @param    Buf is the buffer pointer.
2879 * @param    Size of the Buffer.
2880 *
2881 * @return
2882 *       None
2883 *
2884 * @note     None
2885 *
2886 ******************************************************************************/
2887 static void XNandPsu_Fifo_Write(XNandPsu *InstancePtr, u8* Buffer, u32 Size)
2888 {
2889     u32 *BufPtr = (u32 *)(void *)Buffer;
2890     u32 Index;
2891 
2892     for (Index = 0U; Index < Size/4U; Index++)
2893         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2894                 XNANDPSU_BUF_DATA_PORT_OFFSET,
2895                 BufPtr[Index]);
2896 }
2897 
2898 /*****************************************************************************/
2899 /**
2900 *
2901 * This function reads data from the fifo.
2902 *
2903 * @param    InstancePtr is a pointer to the XNandPsu instance.
2904 * @param    Buf is the buffer pointer.
2905 * @param    Size of the Buffer.
2906 *
2907 * @return
2908 *       None
2909 *
2910 * @note     None
2911 *
2912 ******************************************************************************/
2913 static void XNandPsu_Fifo_Read(XNandPsu *InstancePtr, u8* Buf, u32 Size)
2914 {
2915     u32 *BufPtr = (u32 *)(void *)Buf;
2916     u32 Index;
2917 
2918     for (Index = 0U; Index < Size/4U; Index++)
2919         BufPtr[Index] = XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
2920                     XNANDPSU_BUF_DATA_PORT_OFFSET);
2921 }
2922 
2923 /*****************************************************************************/
2924 /**
2925 *
2926 * This function configures the given dma address to the controller.
2927 *
2928 * @param    InstancePtr is a pointer to the XNandPsu instance.
2929 * @param    Buf is the buffer pointer.
2930 *
2931 * @return
2932 *       None
2933 *
2934 * @note     None
2935 *
2936 ******************************************************************************/
2937 static void XNandPsu_Update_DmaAddr(XNandPsu *InstancePtr, u8* Buf)
2938 {
2939 #if defined(__aarch64__) || defined(__arch64__)
2940         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2941                 XNANDPSU_DMA_SYS_ADDR1_OFFSET,
2942                 (u32) (((INTPTR)Buf >> 32U) & 0xFFFFFFFFU));
2943 #endif
2944         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2945                 XNANDPSU_DMA_SYS_ADDR0_OFFSET,
2946                 (u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU));
2947 
2948 }
2949 
2950 /*****************************************************************************/
2951 /**
2952 *
2953 * This function waits for the device ready stataus.
2954 *
2955 * @param    InstancePtr is a pointer to the XNandPsu instance.
2956 * @param    Target is the chipselect value.
2957 *
2958 * @return
2959 *       - XST_SUCCESS if successful.
2960 *       - XST_FAILURE if failed.
2961 *
2962 * @note     None
2963 *
2964 ******************************************************************************/
2965 static s32 XNandPsu_Device_Ready(XNandPsu *InstancePtr, u32 Target)
2966 {
2967     s32 Status = XST_SUCCESS;
2968     u16 OnfiStatus = 0U;
2969 
2970     do {
2971         Status = XNandPsu_OnfiReadStatus(InstancePtr, Target,
2972                             &OnfiStatus);
2973         if (Status != XST_SUCCESS)
2974             goto Out;
2975         if ((OnfiStatus & (1U << 6U)) != 0U) {
2976             if ((OnfiStatus & (1U << 0U)) != 0U) {
2977                 Status = XST_FAILURE;
2978                 goto Out;
2979             }
2980         }
2981     } while (((OnfiStatus >> 6U) & 0x1U) == 0U);
2982 
2983 Out:
2984     return Status;
2985 }
2986 
2987 /*****************************************************************************/
2988 /**
2989 *
2990 * This function waits for the  transfer complete event.
2991 *
2992 * @param    InstancePtr is a pointer to the XNandPsu instance.
2993 *
2994 * @return
2995 *       - XST_SUCCESS if successful.
2996 *       - XST_FAILURE if failed.
2997 *
2998 * @note     Expects that transfer complete event was set before calling
2999 *       this function.
3000 *
3001 ******************************************************************************/
3002 static s32 XNandPsu_WaitFor_Transfer_Complete(XNandPsu *InstancePtr)
3003 {
3004 s32 Status = XST_FAILURE;
3005 
3006      /* Poll for Transfer Complete event */
3007     Status = XNandPsu_PollRegTimeout(
3008             InstancePtr,
3009             XNANDPSU_INTR_STS_OFFSET,
3010             XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
3011             XNANDPSU_INTR_POLL_TIMEOUT);
3012     if (Status != XST_SUCCESS) {
3013         xil_printf("%s: Poll for xfer complete timeout\r\n", __func__);
3014         goto Out;
3015     }
3016 
3017     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3018         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3019 
3020     XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3021             XNANDPSU_INTR_STS_OFFSET,
3022             XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
3023 #if defined  (XCLOCKING)
3024     Xil_ClockDisable(InstancePtr->Config.RefClk);
3025 #endif
3026 Out:
3027     return Status;
3028 }
3029 /** @} */