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_bbm.c
0010 * @addtogroup Overview
0011 * @{
0012 *
0013 * This file implements the Bad Block Management (BBM) functionality.
0014 * See xnandpsu_bbm.h for more details.
0015 *
0016 * @note     None
0017 *
0018 * <pre>
0019 * MODIFICATION HISTORY:
0020 *
0021 * Ver   Who    Date        Changes
0022 * ----- ----   ----------  -----------------------------------------------
0023 * 1.0   nm     05/06/2014  First release
0024 * 2.0   sb     01/12/2015  Added support for writing BBT signature and version
0025 *              in page section by enabling XNANDPSU_BBT_NO_OOB.
0026 *              Modified Bbt Signature and Version Offset value for
0027 *              Oob and No-Oob region.
0028 * 1.1   nsk    11/07/16    Change memcpy to Xil_MemCpy to handle word aligned
0029 *                      data access.
0030 * 1.4   nsk    04/10/18    Added ICCARM compiler support.
0031 * 1.10  akm    01/05/22    Remove assert checks form static and internal APIs.
0032 * </pre>
0033 *
0034 ******************************************************************************/
0035 
0036 /***************************** Include Files *********************************/
0037 #include <string.h> /**< For Xil_MemCpy and memset */
0038 #ifndef __rtems__
0039 #include "xil_types.h"
0040 #endif
0041 #include "xnandpsu.h"
0042 #include "xnandpsu_bbm.h"
0043 #ifndef __rtems__
0044 #include "xil_mem.h"
0045 #endif
0046 
0047 /************************** Constant Definitions *****************************/
0048 
0049 /**************************** Type Definitions *******************************/
0050 
0051 /***************** Macros (Inline Functions) Definitions *********************/
0052 
0053 /************************** Function Prototypes ******************************/
0054 static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target);
0055 
0056 static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
0057                             u32 Target);
0058 
0059 static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target);
0060 
0061 static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target);
0062 
0063 static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
0064                 XNandPsu_BbtDesc *MirrorDesc, u32 Target);
0065 
0066 static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
0067                             u32 Target);
0068 
0069 #ifndef __rtems__
0070 static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target);
0071 #endif
0072 
0073 /************************** Variable Definitions *****************************/
0074 
0075 /*****************************************************************************/
0076 /**
0077 * This function initializes the Bad Block Table(BBT) descriptors with a
0078 * predefined pattern for searching Bad Block Table(BBT) in flash.
0079 *
0080 * @param    InstancePtr is a pointer to the XNandPsu instance.
0081 *
0082 * @return
0083 *       - NONE
0084 *
0085 ******************************************************************************/
0086 void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr)
0087 {
0088     u32 Index;
0089 
0090     /* Initialize primary Bad Block Table(BBT) */
0091     for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
0092         InstancePtr->BbtDesc.PageOffset[Index] =
0093                         XNANDPSU_BBT_DESC_PAGE_OFFSET;
0094     }
0095     if (InstancePtr->EccMode == XNANDPSU_ONDIE) {
0096         InstancePtr->BbtDesc.SigOffset = XNANDPSU_ONDIE_SIG_OFFSET;
0097         InstancePtr->BbtDesc.VerOffset = XNANDPSU_ONDIE_VER_OFFSET;
0098     } else {
0099         InstancePtr->BbtDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET;
0100         InstancePtr->BbtDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET;
0101     }
0102     InstancePtr->BbtDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN;
0103     InstancePtr->BbtDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS;
0104     (void)strcpy(&InstancePtr->BbtDesc.Signature[0], "Bbt0");
0105     for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
0106         InstancePtr->BbtDesc.Version[Index] = 0U;
0107     }
0108     InstancePtr->BbtDesc.Valid = 0U;
0109 
0110     /* Assuming that the flash device will have at least 4 blocks. */
0111     if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
0112                             BbtDesc.MaxBlocks){
0113         InstancePtr->BbtDesc.MaxBlocks = 4U;
0114     }
0115 
0116     /* Initialize mirror Bad Block Table(BBT) */
0117     for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
0118         InstancePtr->BbtMirrorDesc.PageOffset[Index] =
0119                         XNANDPSU_BBT_DESC_PAGE_OFFSET;
0120     }
0121     if (InstancePtr->EccMode == XNANDPSU_ONDIE) {
0122         InstancePtr->BbtMirrorDesc.SigOffset =
0123                     XNANDPSU_ONDIE_SIG_OFFSET;
0124         InstancePtr->BbtMirrorDesc.VerOffset =
0125                     XNANDPSU_ONDIE_VER_OFFSET;
0126     } else {
0127         InstancePtr->BbtMirrorDesc.SigOffset =
0128                     XNANDPSU_BBT_DESC_SIG_OFFSET;
0129         InstancePtr->BbtMirrorDesc.VerOffset =
0130                     XNANDPSU_BBT_DESC_VER_OFFSET;
0131     }
0132     InstancePtr->BbtMirrorDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN;
0133     InstancePtr->BbtMirrorDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS;
0134     (void)strcpy(&InstancePtr->BbtMirrorDesc.Signature[0], "1tbB");
0135     for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
0136         InstancePtr->BbtMirrorDesc.Version[Index] = 0U;
0137     }
0138     InstancePtr->BbtMirrorDesc.Valid = 0U;
0139 
0140     /* Assuming that the flash device will have at least 4 blocks. */
0141     if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
0142                         BbtMirrorDesc.MaxBlocks){
0143         InstancePtr->BbtMirrorDesc.MaxBlocks = 4U;
0144     }
0145 
0146     /* Initialize Bad block search pattern structure */
0147     if (InstancePtr->Geometry.BytesPerPage > 512U) {
0148         /* For flash page size > 512 bytes */
0149         InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE;
0150         InstancePtr->BbPattern.Offset =
0151             XNANDPSU_BB_PTRN_OFF_LARGE_PAGE;
0152         InstancePtr->BbPattern.Length =
0153             XNANDPSU_BB_PTRN_LEN_LARGE_PAGE;
0154     } else {
0155         InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE;
0156         InstancePtr->BbPattern.Offset =
0157             XNANDPSU_BB_PTRN_OFF_SML_PAGE;
0158         InstancePtr->BbPattern.Length =
0159             XNANDPSU_BB_PTRN_LEN_SML_PAGE;
0160     }
0161     for(Index = 0U; Index < XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; Index++) {
0162         InstancePtr->BbPattern.Pattern[Index] = XNANDPSU_BB_PATTERN;
0163     }
0164 }
0165 
0166 /*****************************************************************************/
0167 /**
0168 * This function scans the NAND flash for factory marked bad blocks and creates
0169 * a RAM based Bad Block Table(BBT).
0170 *
0171 * @param    InstancePtr is a pointer to the XNandPsu instance.
0172 *
0173 * @return
0174 *       - NONE
0175 *
0176 ******************************************************************************/
0177 static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target)
0178 {
0179     u32 BlockIndex;
0180     u32 PageIndex;
0181     u32 Length;
0182     u32 BlockOffset;
0183     u8 BlockShift;
0184     u32 NumPages;
0185     u32 Page;
0186 #ifdef __ICCARM__
0187 #pragma pack(push, 1)
0188     u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U};
0189 #pragma pack(pop)
0190 #else
0191     u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
0192 #endif
0193     u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
0194     u32 NumBlocks = InstancePtr->Geometry.NumTargetBlocks;
0195     s32 Status;
0196 
0197     /* Number of pages to search for bad block pattern */
0198     if ((InstancePtr->BbPattern.Options & XNANDPSU_BBT_SCAN_2ND_PAGE) != 0U)
0199     {
0200         NumPages = 2U;
0201     } else {
0202         NumPages = 1U;
0203     }
0204     /* Scan all the blocks for factory marked bad blocks */
0205     for(BlockIndex = StartBlock; BlockIndex < (StartBlock + NumBlocks);
0206                             BlockIndex++) {
0207         /* Block offset in Bad Block Table(BBT) entry */
0208         BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
0209         /* Block shift value in the byte */
0210         BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
0211         Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock;
0212         /* Search for the bad block pattern */
0213         for(PageIndex = 0U; PageIndex < NumPages; PageIndex++) {
0214             Status = XNandPsu_ReadSpareBytes(InstancePtr,
0215                     (Page + PageIndex), &Buf[0]);
0216 
0217             if (Status != XST_SUCCESS) {
0218                 /* Marking as bad block */
0219                 InstancePtr->Bbt[BlockOffset] |=
0220                     (u8)(XNANDPSU_BLOCK_FACTORY_BAD <<
0221                      BlockShift);
0222                 break;
0223             }
0224             /*
0225              * Read the spare bytes to check for bad block
0226              * pattern
0227              */
0228             for(Length = 0U; Length <
0229                 InstancePtr->BbPattern.Length; Length++) {
0230                 if (Buf[InstancePtr->BbPattern.Offset + Length]
0231                         !=
0232                     InstancePtr->BbPattern.Pattern[Length])
0233                 {
0234                     /* Bad block found */
0235                     InstancePtr->Bbt[BlockOffset] |=
0236                         (u8)
0237                         (XNANDPSU_BLOCK_FACTORY_BAD <<
0238                          BlockShift);
0239                     break;
0240                 }
0241             }
0242         }
0243     }
0244 }
0245 
0246 /*****************************************************************************/
0247 /**
0248 * This function reads the Bad Block Table(BBT) if present in flash. If not it
0249 * scans the flash for detecting factory marked bad blocks and creates a bad
0250 * block table and write the Bad Block Table(BBT) into the flash.
0251 *
0252 * @param    InstancePtr is a pointer to the XNandPsu instance.
0253 *
0254 * @return
0255 *       - XST_SUCCESS if successful.
0256 *       - XST_FAILURE if fail.
0257 *
0258 ******************************************************************************/
0259 s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr)
0260 {
0261     Xil_AssertNonvoid(InstancePtr != NULL);
0262     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
0263 
0264     s32 Status;
0265     u32 Index;
0266     u32 BbtLen;
0267 
0268     /* Zero the RAM based Bad Block Table(BBT) entries */
0269     BbtLen = InstancePtr->Geometry.NumBlocks >>
0270                     XNANDPSU_BBT_BLOCK_SHIFT;
0271     (void)memset(&InstancePtr->Bbt[0], 0, BbtLen);
0272 
0273     for (Index = 0U; Index < InstancePtr->Geometry.NumTargets; Index++) {
0274 
0275         if (XNandPsu_ReadBbt(InstancePtr, Index) != XST_SUCCESS) {
0276             /* Create memory based Bad Block Table(BBT) */
0277             XNandPsu_CreateBbt(InstancePtr, Index);
0278             /* Write the Bad Block Table(BBT) to the flash */
0279             Status = XNandPsu_WriteBbt(InstancePtr,
0280                     &InstancePtr->BbtDesc,
0281                     &InstancePtr->BbtMirrorDesc, Index);
0282             if (Status != XST_SUCCESS) {
0283                 goto Out;
0284             }
0285             /* Write the Mirror Bad Block Table(BBT) to the flash */
0286             Status = XNandPsu_WriteBbt(InstancePtr,
0287                     &InstancePtr->BbtMirrorDesc,
0288                     &InstancePtr->BbtDesc, Index);
0289             if (Status != XST_SUCCESS) {
0290                 goto Out;
0291             }
0292             /*
0293              * Mark the blocks containing Bad Block Table
0294              * (BBT) as Reserved
0295              */
0296             Status = XNandPsu_MarkBbt(InstancePtr,
0297                             &InstancePtr->BbtDesc,
0298                             Index);
0299             if (Status != XST_SUCCESS) {
0300                 goto Out;
0301             }
0302             Status = XNandPsu_MarkBbt(InstancePtr,
0303                         &InstancePtr->BbtMirrorDesc,
0304                             Index);
0305             if (Status != XST_SUCCESS) {
0306                 goto Out;
0307             }
0308         }
0309     }
0310 
0311     Status = XST_SUCCESS;
0312 Out:
0313     return Status;
0314 }
0315 
0316 /*****************************************************************************/
0317 /**
0318 * This function converts the Bad Block Table(BBT) read from the flash to the
0319 * RAM based Bad Block Table(BBT).
0320 *
0321 * @param    InstancePtr is a pointer to the XNandPsu instance.
0322 * @param    Buf is the buffer which contains BBT read from flash.
0323 *
0324 * @return
0325 *       - NONE.
0326 *
0327 ******************************************************************************/
0328 static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target)
0329 {
0330 #ifndef __rtems__
0331     u32 BlockOffset;
0332     u8 BlockShift;
0333     u32 Data;
0334     u8 BlockType;
0335     u32 BlockIndex;
0336 #endif
0337     u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >>
0338                     XNANDPSU_BBT_BLOCK_SHIFT;
0339 #ifdef __rtems__
0340     u32 BbtOffset = Target * InstancePtr->Geometry.NumTargetBlocks / XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
0341 
0342     for(u32 BbtIndex = 0; BbtIndex < BbtLen; BbtIndex++) {
0343         /* Invert the byte to convert from in-flash BBT to in-memory BBT */
0344         InstancePtr->Bbt[BbtIndex + BbtOffset] = ~Buf[BbtIndex];
0345     }
0346 #else
0347     u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
0348 
0349     for(BlockOffset = StartBlock; BlockOffset < (StartBlock + BbtLen);
0350                         BlockOffset++) {
0351         Data = *(Buf + BlockOffset);
0352         /* Clear the RAM based Bad Block Table(BBT) contents */
0353         InstancePtr->Bbt[BlockOffset] = 0x0U;
0354         /* Loop through the every 4 blocks in the bitmap */
0355         for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
0356                 BlockIndex++) {
0357             BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
0358             BlockType = (u8) ((Data >> BlockShift) &
0359                 XNANDPSU_BLOCK_TYPE_MASK);
0360             switch(BlockType) {
0361                 case XNANDPSU_FLASH_BLOCK_FAC_BAD:
0362                     /* Factory bad block */
0363                     InstancePtr->Bbt[BlockOffset] |=
0364                         (u8)
0365                         (XNANDPSU_BLOCK_FACTORY_BAD <<
0366                         BlockShift);
0367                     break;
0368                 case XNANDPSU_FLASH_BLOCK_RESERVED:
0369                     /* Reserved block */
0370                     InstancePtr->Bbt[BlockOffset] |=
0371                         (u8)
0372                         (XNANDPSU_BLOCK_RESERVED <<
0373                         BlockShift);
0374                     break;
0375                 case XNANDPSU_FLASH_BLOCK_BAD:
0376                     /* Bad block due to wear */
0377                     InstancePtr->Bbt[BlockOffset] |=
0378                         (u8)(XNANDPSU_BLOCK_BAD <<
0379                         BlockShift);
0380                     break;
0381                 default:
0382                     /* Good block */
0383                     /* The BBT entry already defaults to
0384                      * zero */
0385                     break;
0386             }
0387         }
0388     }
0389 #endif
0390 }
0391 
0392 /*****************************************************************************/
0393 /**
0394 * This function searches the Bad Bloock Table(BBT) in flash and loads into the
0395 * memory based Bad Block Table(BBT).
0396 *
0397 * @param    InstancePtr is the pointer to the XNandPsu instance.
0398 * @return
0399 *       - XST_SUCCESS if successful.
0400 *       - XST_FAILURE if fail.
0401 *
0402 ******************************************************************************/
0403 static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target)
0404 {
0405     u64 Offset;
0406 #ifdef __ICCARM__
0407 #pragma pack(push, 1)
0408     u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U};
0409 #pragma pack(pop)
0410 #else
0411     u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U};
0412 #endif
0413     s32 Status1;
0414     s32 Status2;
0415     s32 Status;
0416     u32 BufLen;
0417 
0418     XNandPsu_BbtDesc *Desc = &InstancePtr->BbtDesc;
0419     XNandPsu_BbtDesc *MirrorDesc = &InstancePtr->BbtMirrorDesc;
0420 #ifdef __rtems__
0421     BufLen = InstancePtr->Geometry.NumTargetBlocks >>
0422 #else
0423     BufLen = InstancePtr->Geometry.NumBlocks >>
0424 #endif
0425             XNANDPSU_BBT_BLOCK_SHIFT;
0426     /* Search the Bad Block Table(BBT) in flash */
0427     Status1 = XNandPsu_SearchBbt(InstancePtr, Desc, Target);
0428     Status2 = XNandPsu_SearchBbt(InstancePtr, MirrorDesc, Target);
0429     if ((Status1 != XST_SUCCESS) && (Status2 != XST_SUCCESS)) {
0430 #ifdef XNANDPSU_DEBUG
0431         xil_printf("%s: Bad block table not found\r\n",__func__);
0432 #endif
0433         Status = XST_FAILURE;
0434         goto Out;
0435     }
0436 #ifdef XNANDPSU_DEBUG
0437     xil_printf("%s: Bad block table found\r\n",__func__);
0438 #endif
0439     /* Bad Block Table found */
0440     if ((Desc->Valid != 0U) && (MirrorDesc->Valid != 0U)) {
0441         /* Valid BBT & Mirror BBT found */
0442         if (Desc->Version[Target] > MirrorDesc->Version[Target]) {
0443             Offset = (u64)Desc->PageOffset[Target] *
0444                 (u64)InstancePtr->Geometry.BytesPerPage;
0445             Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
0446                                 &Buf[0]);
0447             if (Status != XST_SUCCESS) {
0448                 goto Out;
0449             }
0450             /* Convert flash BBT to memory based BBT */
0451             XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
0452             MirrorDesc->Version[Target] = Desc->Version[Target];
0453 
0454             /* Write the BBT to Mirror BBT location in flash */
0455             Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc,
0456                             Desc, Target);
0457             if (Status != XST_SUCCESS) {
0458                 goto Out;
0459             }
0460         } else if (Desc->Version[Target] <
0461                         MirrorDesc->Version[Target]) {
0462             Offset = (u64)MirrorDesc->PageOffset[Target] *
0463                 (u64)InstancePtr->Geometry.BytesPerPage;
0464             Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
0465                                 &Buf[0]);
0466             if (Status != XST_SUCCESS) {
0467                 goto Out;
0468             }
0469             /* Convert flash BBT to memory based BBT */
0470             XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
0471             Desc->Version[Target] = MirrorDesc->Version[Target];
0472 
0473             /* Write the Mirror BBT to BBT location in flash */
0474             Status = XNandPsu_WriteBbt(InstancePtr, Desc,
0475                             MirrorDesc, Target);
0476             if (Status != XST_SUCCESS) {
0477                 goto Out;
0478             }
0479         } else {
0480             /* Both are up-to-date */
0481             Offset = (u64)Desc->PageOffset[Target] *
0482                 (u64)InstancePtr->Geometry.BytesPerPage;
0483             Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
0484                                 &Buf[0]);
0485             if (Status != XST_SUCCESS) {
0486                 goto Out;
0487             }
0488             /* Convert flash BBT to memory based BBT */
0489             XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
0490         }
0491     } else if (Desc->Valid != 0U) {
0492         /* Valid Primary BBT found */
0493         Offset = (u64)Desc->PageOffset[Target] *
0494             (u64)InstancePtr->Geometry.BytesPerPage;
0495         Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]);
0496         if (Status != XST_SUCCESS) {
0497             goto Out;
0498         }
0499         /* Convert flash BBT to memory based BBT */
0500         XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
0501         MirrorDesc->Version[Target] = Desc->Version[Target];
0502 
0503         /* Write the BBT to Mirror BBT location in flash */
0504         Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc,
0505                                 Target);
0506         if (Status != XST_SUCCESS) {
0507             goto Out;
0508         }
0509     } else {
0510         /* Valid Mirror BBT found */
0511         Offset = (u64)MirrorDesc->PageOffset[Target] *
0512             (u64)InstancePtr->Geometry.BytesPerPage;
0513         Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]);
0514         if (Status != XST_SUCCESS) {
0515             goto Out;
0516         }
0517         /* Convert flash BBT to memory based BBT */
0518         XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target);
0519         Desc->Version[Target] = MirrorDesc->Version[Target];
0520 
0521         /* Write the Mirror BBT to BBT location in flash */
0522         Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc,
0523                                 Target);
0524         if (Status != XST_SUCCESS) {
0525             goto Out;
0526         }
0527     }
0528 
0529     Status = XST_SUCCESS;
0530 Out:
0531     return Status;
0532 }
0533 
0534 /*****************************************************************************/
0535 /**
0536 * This function searches the BBT in flash.
0537 *
0538 * @param    InstancePtr is the pointer to the XNandPsu instance.
0539 * @param    Desc is the BBT descriptor pattern to search.
0540 *
0541 * @return
0542 *       - XST_SUCCESS if successful.
0543 *       - XST_FAILURE if fail.
0544 *
0545 ******************************************************************************/
0546 static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
0547                                 u32 Target)
0548 {
0549     u32 StartBlock;
0550     u32 SigOffset;
0551     u32 VerOffset;
0552     u32 MaxBlocks;
0553     u32 PageOff;
0554     u32 SigLength;
0555 #ifdef __ICCARM__
0556 #pragma pack(push, 1)
0557     u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U};
0558 #pragma pack(pop)
0559 #else
0560     u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
0561 #endif
0562     u32 Block;
0563     u32 Offset;
0564     s32 Status;
0565 
0566     StartBlock = ((Target + (u32)1) *
0567                 InstancePtr->Geometry.NumTargetBlocks) - (u32)1;
0568     SigOffset = Desc->SigOffset;
0569     VerOffset = Desc->VerOffset;
0570     MaxBlocks = Desc->MaxBlocks;
0571     SigLength = Desc->SigLength;
0572 #ifdef __rtems__
0573     Desc->Valid = 0;
0574 #endif
0575 
0576     /* Read the last 4 blocks for Bad Block Table(BBT) signature */
0577     for(Block = 0U; Block < MaxBlocks; Block++) {
0578         PageOff = (StartBlock - Block) *
0579             InstancePtr->Geometry.PagesPerBlock;
0580 
0581             Status = XNandPsu_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]);
0582         if (Status != XST_SUCCESS) {
0583             continue;
0584         }
0585         /* Check the Bad Block Table(BBT) signature */
0586         for(Offset = 0U; Offset < SigLength; Offset++) {
0587             if (Buf[Offset + SigOffset] !=
0588                 (u8)(Desc->Signature[Offset]))
0589             {
0590                 break; /* Check the next blocks */
0591             }
0592         }
0593         if (Offset >= SigLength) {
0594             /* Bad Block Table(BBT) found */
0595             Desc->PageOffset[Target] = PageOff;
0596             Desc->Version[Target] = Buf[VerOffset];
0597             Desc->Valid = 1U;
0598 
0599             Status = XST_SUCCESS;
0600             goto Out;
0601         }
0602     }
0603     /* Bad Block Table(BBT) not found */
0604     Status = XST_FAILURE;
0605 Out:
0606     return Status;
0607 }
0608 
0609 /*****************************************************************************/
0610 /**
0611 * This function writes Bad Block Table(BBT) from RAM to flash.
0612 *
0613 * @param    InstancePtr is the pointer to the XNandPsu instance.
0614 * @param    Desc is the BBT descriptor to be written to flash.
0615 * @param    MirrorDesc is the mirror BBT descriptor.
0616 *
0617 * @return
0618 *       - XST_SUCCESS if successful.
0619 *       - XST_FAILURE if fail.
0620 *
0621 ******************************************************************************/
0622 static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
0623                 XNandPsu_BbtDesc *MirrorDesc, u32 Target)
0624 {
0625     u64 Offset;
0626     u32 Block = {0U};
0627     u32 EndBlock = ((Target + (u32)1) *
0628             InstancePtr->Geometry.NumTargetBlocks) - (u32)1;
0629 #ifdef __ICCARM__
0630 #pragma pack(push, 1)
0631     u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U};
0632     u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE]= {0U};
0633 #pragma pack(pop)
0634 #else
0635     u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U};
0636     u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
0637 #endif
0638 
0639 #ifndef __rtems__
0640     u8 Mask[4] = {0x00U, 0x01U, 0x02U, 0x03U};
0641     u8 Data;
0642     u32 BlockOffset;
0643     u8 BlockShift;
0644     s32 Status;
0645     u32 BlockIndex;
0646     u32 Index;
0647     u8 BlockType;
0648     u32 BbtLen = InstancePtr->Geometry.NumBlocks >>
0649 #else
0650     s32 Status;
0651     u32 Index;
0652     u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >>
0653 #endif
0654                         XNANDPSU_BBT_BLOCK_SHIFT;
0655     /* Find a valid block to write the Bad Block Table(BBT) */
0656     if ((!Desc->Valid) != 0U) {
0657         for(Index = 0U; Index < Desc->MaxBlocks; Index++) {
0658             Block  = (EndBlock - Index);
0659 #ifdef __rtems__
0660             if (XNandPsu_IsBlockBad(InstancePtr, Block) != XST_FAILURE) {
0661                 continue;
0662             }
0663 #else
0664             BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
0665             BlockShift = XNandPsu_BbtBlockShift(Block);
0666             BlockType = (InstancePtr->Bbt[BlockOffset] >>
0667                     BlockShift) & XNANDPSU_BLOCK_TYPE_MASK;
0668             switch(BlockType)
0669             {
0670                 case XNANDPSU_BLOCK_BAD:
0671                 case XNANDPSU_BLOCK_FACTORY_BAD:
0672                     continue;
0673                 default:
0674                     /* Good Block */
0675                     break;
0676             }
0677 #endif
0678             Desc->PageOffset[Target] = Block *
0679                 InstancePtr->Geometry.PagesPerBlock;
0680             if (Desc->PageOffset[Target] !=
0681                     MirrorDesc->PageOffset[Target]) {
0682                 /* Free block found */
0683                 Desc->Valid = 1U;
0684                 break;
0685             }
0686         }
0687 
0688 
0689         /* Block not found for writing Bad Block Table(BBT) */
0690         if (Index >= Desc->MaxBlocks) {
0691 #ifdef XNANDPSU_DEBUG
0692         xil_printf("%s: Blocks unavailable for writing BBT\r\n",
0693                                 __func__);
0694 #endif
0695             Status = XST_FAILURE;
0696             goto Out;
0697         }
0698     } else {
0699         Block = Desc->PageOffset[Target] /
0700                     InstancePtr->Geometry.PagesPerBlock;
0701     }
0702     /* Convert the memory based BBT to flash based table */
0703     (void)memset(Buf, 0xff, BbtLen);
0704 
0705 #ifdef __rtems__
0706     u32 BbtTargetOffset = BbtLen * Target;
0707     /* Loop through the BBT entries */
0708     for(u32 BbtIndex = 0U; BbtIndex < BbtLen; BbtIndex++) {
0709         /* Invert byte to convert from in-memory BBT to in-flash BBT */
0710         Buf[BbtIndex] = ~InstancePtr->Bbt[BbtIndex + BbtTargetOffset];
0711     }
0712 #else
0713     /* Loop through the number of blocks */
0714     for(BlockOffset = 0U; BlockOffset < BbtLen; BlockOffset++) {
0715         Data = InstancePtr->Bbt[BlockOffset];
0716         /* Calculate the bit mask for 4 blocks at a time in loop */
0717         for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
0718                 BlockIndex++) {
0719             BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
0720             Buf[BlockOffset] &= ~(Mask[Data &
0721                     XNANDPSU_BLOCK_TYPE_MASK] <<
0722                     BlockShift);
0723             Data >>= XNANDPSU_BBT_BLOCK_SHIFT;
0724         }
0725     }
0726 #endif
0727     /* Write the Bad Block Table(BBT) to flash */
0728 #ifdef __rtems__
0729     Status = XNandPsu_EraseBlock(InstancePtr, Target,
0730         Block % InstancePtr->Geometry.NumTargetBlocks);
0731 #else
0732     Status = XNandPsu_EraseBlock(InstancePtr, 0U, Block);
0733 #endif
0734     if (Status != XST_SUCCESS) {
0735         goto Out;
0736     }
0737 
0738     /* Write the BBT to page offset */
0739     Offset = (u64)Desc->PageOffset[Target] *
0740             (u64)InstancePtr->Geometry.BytesPerPage;
0741     Status = XNandPsu_Write(InstancePtr, Offset, BbtLen, &Buf[0]);
0742     if (Status != XST_SUCCESS) {
0743         goto Out;
0744     }
0745     /* Write the signature and version in the spare data area */
0746     (void)memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage);
0747     Status = XNandPsu_ReadSpareBytes(InstancePtr, Desc->PageOffset[Target],
0748                      &SpareBuf[0]);
0749     if (Status != XST_SUCCESS) {
0750         goto Out;
0751     }
0752 
0753     (void)Xil_MemCpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0],
0754                             Desc->SigLength);
0755     (void)memcpy(SpareBuf + Desc->VerOffset, &Desc->Version[Target], 1U);
0756 
0757     Status = XNandPsu_WriteSpareBytes(InstancePtr,
0758                 Desc->PageOffset[Target], &SpareBuf[0]);
0759     if (Status != XST_SUCCESS) {
0760         goto Out;
0761     }
0762 
0763     Status = XST_SUCCESS;
0764 Out:
0765     return Status;
0766 }
0767 
0768 /*****************************************************************************/
0769 /**
0770 * This function updates the primary and mirror Bad Block Table(BBT) in the
0771 * flash.
0772 *
0773 * @param    InstancePtr is the pointer to the XNandPsu instance.
0774 * @return
0775 *       - XST_SUCCESS if successful.
0776 *       - XST_FAILURE if fail.
0777 *
0778 ******************************************************************************/
0779 #ifdef __rtems__
0780 s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target)
0781 #else
0782 static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target)
0783 #endif
0784 {
0785     s32 Status;
0786     u8 Version;
0787 
0788     /* Update the version number */
0789     Version = InstancePtr->BbtDesc.Version[Target];
0790     InstancePtr->BbtDesc.Version[Target] = (u8)(((u16)Version +
0791                             (u16)1) % (u16)256U);
0792 
0793     Version = InstancePtr->BbtMirrorDesc.Version[Target];
0794     InstancePtr->BbtMirrorDesc.Version[Target] = (u8)(((u16)Version +
0795                             (u16)1) % (u16)256);
0796     /* Update the primary Bad Block Table(BBT) in flash */
0797     Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtDesc,
0798                         &InstancePtr->BbtMirrorDesc,
0799                         Target);
0800     if (Status != XST_SUCCESS) {
0801         goto Out;
0802     }
0803 
0804     /* Update the mirrored Bad Block Table(BBT) in flash */
0805     Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc,
0806                         &InstancePtr->BbtDesc,
0807                         Target);
0808     if (Status != XST_SUCCESS) {
0809         goto Out;
0810     }
0811 
0812     Status = XST_SUCCESS;
0813 Out:
0814     return Status;
0815 }
0816 
0817 /*****************************************************************************/
0818 /**
0819 * This function marks the block containing Bad Block Table as reserved
0820 * and updates the BBT.
0821 *
0822 * @param    InstancePtr is the pointer to the XNandPsu instance.
0823 * @param    Desc is the BBT descriptor pointer.
0824 * @return
0825 *       - XST_SUCCESS if successful.
0826 *       - XST_FAILURE if fail.
0827 *
0828 ******************************************************************************/
0829 static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
0830                                 u32 Target)
0831 {
0832     u32 BlockIndex;
0833     u32 BlockOffset;
0834     u8 BlockShift;
0835     u8 OldVal;
0836     u8 NewVal;
0837     s32 Status;
0838     u32 UpdateBbt = 0U;
0839     u32 Index;
0840 
0841     /* Mark the last four blocks as Reserved */
0842     BlockIndex = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) -
0843 #ifdef __rtems__
0844                         Desc->MaxBlocks;
0845 #else
0846                         Desc->MaxBlocks - (u32)1;
0847 #endif
0848 
0849     for(Index = 0U; Index < Desc->MaxBlocks; Index++) {
0850 
0851         BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
0852         BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
0853         OldVal = InstancePtr->Bbt[BlockOffset];
0854         NewVal = (u8) (OldVal | (XNANDPSU_BLOCK_RESERVED <<
0855                             BlockShift));
0856         InstancePtr->Bbt[BlockOffset] = NewVal;
0857 
0858         if (OldVal != NewVal) {
0859             UpdateBbt = 1U;
0860         }
0861         BlockIndex++;
0862     }
0863 
0864     /* Update the BBT to flash */
0865     if (UpdateBbt != 0U) {
0866         Status = XNandPsu_UpdateBbt(InstancePtr, Target);
0867         if (Status != XST_SUCCESS) {
0868             goto Out;
0869         }
0870     }
0871 
0872     Status = XST_SUCCESS;
0873 Out:
0874     return Status;
0875 }
0876 
0877 /*****************************************************************************/
0878 /**
0879 *
0880 * This function checks whether a block is bad or not.
0881 *
0882 * @param    InstancePtr is the pointer to the XNandPsu instance.
0883 *
0884 * @param    Block is the block number.
0885 *
0886 * @return
0887 *       - XST_SUCCESS if successful.
0888 *       - XST_FAILURE if fail.
0889 *
0890 ******************************************************************************/
0891 s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block)
0892 {
0893     Xil_AssertNonvoid(InstancePtr != NULL);
0894     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
0895     Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
0896 
0897     u8 Data;
0898     u8 BlockShift;
0899     u8 BlockType;
0900     u32 BlockOffset;
0901     s32 Status;
0902 
0903     BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
0904     BlockShift = XNandPsu_BbtBlockShift(Block);
0905     Data = InstancePtr->Bbt[BlockOffset];   /* Block information in BBT */
0906     BlockType = (Data >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK;
0907 
0908     if ((BlockType != XNANDPSU_BLOCK_GOOD) &&
0909         (BlockType != XNANDPSU_BLOCK_RESERVED)) {
0910         Status = XST_SUCCESS;
0911     }
0912     else {
0913         Status = XST_FAILURE;
0914     }
0915     return Status;
0916 }
0917 
0918 /*****************************************************************************/
0919 /**
0920 * This function marks a block as bad in the RAM based Bad Block Table(BBT). It
0921 * also updates the Bad Block Table(BBT) in the flash.
0922 *
0923 * @param    InstancePtr is the pointer to the XNandPsu instance.
0924 * @param    Block is the block number.
0925 *
0926 * @return
0927 *       - XST_SUCCESS if successful.
0928 *       - XST_FAILURE if fail.
0929 *
0930 ******************************************************************************/
0931 s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block)
0932 #ifdef __rtems__
0933 {
0934     return XNandPsu_MarkBlock(InstancePtr, Block, XNANDPSU_BLOCK_BAD );
0935 }
0936 
0937 s32 XNandPsu_MarkBlock(XNandPsu *InstancePtr, u32 Block, u8 BlockMark)
0938 #endif
0939 {
0940     Xil_AssertNonvoid(InstancePtr != NULL);
0941     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY)
0942     Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
0943 
0944 #ifdef __rtems__
0945     BlockMark &= XNANDPSU_BLOCK_TYPE_MASK;
0946 #endif
0947 
0948     u8 Data;
0949     u8 BlockShift;
0950     u32 BlockOffset;
0951     u8 OldVal;
0952     u8 NewVal;
0953     s32 Status;
0954     u32 Target;
0955 
0956     Target = Block / InstancePtr->Geometry.NumTargetBlocks;
0957 
0958     BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
0959     BlockShift = XNandPsu_BbtBlockShift(Block);
0960     Data = InstancePtr->Bbt[BlockOffset];   /* Block information in BBT */
0961 
0962     /* Mark the block as bad in the RAM based Bad Block Table */
0963     OldVal = Data;
0964     Data &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift);
0965 #ifdef __rtems__
0966     Data |= (BlockMark << BlockShift);
0967 #else
0968     Data |= (XNANDPSU_BLOCK_BAD << BlockShift);
0969 #endif
0970     NewVal = Data;
0971     InstancePtr->Bbt[BlockOffset] = Data;
0972 
0973     /* Update the Bad Block Table(BBT) in flash */
0974     if (OldVal != NewVal) {
0975         Status = XNandPsu_UpdateBbt(InstancePtr, Target);
0976         if (Status != XST_SUCCESS) {
0977             goto Out;
0978         }
0979     }
0980 
0981     Status = XST_SUCCESS;
0982 Out:
0983     return Status;
0984 }
0985 
0986 #ifdef __rtems__
0987 bool XNandPsu_StageBlockMark(XNandPsu *InstancePtr, u32 Block, u8 BlockMark)
0988 {
0989     u8 BlockShift;
0990     u32 BlockOffset;
0991     u8 OldVal;
0992 
0993     BlockMark &= XNANDPSU_BLOCK_TYPE_MASK;
0994 
0995     BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
0996     BlockShift = XNandPsu_BbtBlockShift(Block);
0997     OldVal = InstancePtr->Bbt[BlockOffset] >> BlockShift;
0998     OldVal &= XNANDPSU_BLOCK_TYPE_MASK;
0999     InstancePtr->Bbt[BlockOffset] &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift);
1000     InstancePtr->Bbt[BlockOffset] |= (BlockMark << BlockShift);
1001     return BlockMark != OldVal;
1002 }
1003 #endif
1004 
1005 /** @} */