/****************************************************************************** * * Copyright (C) 2015 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * * @file xnandpsu_bbm.c * @addtogroup nandpsu_v1_0 * @{ * * This file implements the Bad Block Management (BBM) functionality. * See xnandpsu_bbm.h for more details. * * @note None * *
* MODIFICATION HISTORY:
*
* Ver   Who    Date        Changes
* ----- ----   ----------  -----------------------------------------------
* 1.0   nm     05/06/2014  First release
* 2.0   sb     01/12/2015  Added support for writing BBT signature and version
*			   in page section by enabling XNANDPSU_BBT_NO_OOB.
*			   Modified Bbt Signature and Version Offset value for
*			   Oob and No-Oob region.
* 
* ******************************************************************************/ /***************************** Include Files *********************************/ #include /**< For memcpy and memset */ #include "xil_types.h" #include "xnandpsu.h" #include "xnandpsu_bbm.h" /************************** Constant Definitions *****************************/ /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target); static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, u32 Target); static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target); static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target); static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, XNandPsu_BbtDesc *MirrorDesc, u32 Target); static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc, u32 Target); static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target); /************************** Variable Definitions *****************************/ /*****************************************************************************/ /** * This function initializes the Bad Block Table(BBT) descriptors with a * predefined pattern for searching Bad Block Table(BBT) in flash. * * @param InstancePtr is a pointer to the XNandPsu instance. * * @return * - NONE * ******************************************************************************/ void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr) { u32 Index; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* Initialize primary Bad Block Table(BBT) */ for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { InstancePtr->BbtDesc.PageOffset[Index] = XNANDPSU_BBT_DESC_PAGE_OFFSET; } if (InstancePtr->EccMode == XNANDPSU_ONDIE) { InstancePtr->BbtDesc.SigOffset = XNANDPSU_ONDIE_SIG_OFFSET; InstancePtr->BbtDesc.VerOffset = XNANDPSU_ONDIE_VER_OFFSET; } else { InstancePtr->BbtDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET; InstancePtr->BbtDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET; } InstancePtr->BbtDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN; InstancePtr->BbtDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS; (void)strcpy(&InstancePtr->BbtDesc.Signature[0], "Bbt0"); for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { InstancePtr->BbtDesc.Version[Index] = 0U; } InstancePtr->BbtDesc.Valid = 0U; /* Assuming that the flash device will have at least 4 blocks. */ if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr-> BbtDesc.MaxBlocks){ InstancePtr->BbtDesc.MaxBlocks = 4U; } /* Initialize mirror Bad Block Table(BBT) */ for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { InstancePtr->BbtMirrorDesc.PageOffset[Index] = XNANDPSU_BBT_DESC_PAGE_OFFSET; } if (InstancePtr->EccMode == XNANDPSU_ONDIE) { InstancePtr->BbtMirrorDesc.SigOffset = XNANDPSU_ONDIE_SIG_OFFSET; InstancePtr->BbtMirrorDesc.VerOffset = XNANDPSU_ONDIE_VER_OFFSET; } else { InstancePtr->BbtMirrorDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET; InstancePtr->BbtMirrorDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET; } InstancePtr->BbtMirrorDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN; InstancePtr->BbtMirrorDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS; (void)strcpy(&InstancePtr->BbtMirrorDesc.Signature[0], "1tbB"); for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { InstancePtr->BbtMirrorDesc.Version[Index] = 0U; } InstancePtr->BbtMirrorDesc.Valid = 0U; /* Assuming that the flash device will have at least 4 blocks. */ if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr-> BbtMirrorDesc.MaxBlocks){ InstancePtr->BbtMirrorDesc.MaxBlocks = 4U; } /* Initialize Bad block search pattern structure */ if (InstancePtr->Geometry.BytesPerPage > 512U) { /* For flash page size > 512 bytes */ InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE; InstancePtr->BbPattern.Offset = XNANDPSU_BB_PTRN_OFF_LARGE_PAGE; InstancePtr->BbPattern.Length = XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; } else { InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE; InstancePtr->BbPattern.Offset = XNANDPSU_BB_PTRN_OFF_SML_PAGE; InstancePtr->BbPattern.Length = XNANDPSU_BB_PTRN_LEN_SML_PAGE; } for(Index = 0U; Index < XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; Index++) { InstancePtr->BbPattern.Pattern[Index] = XNANDPSU_BB_PATTERN; } } /*****************************************************************************/ /** * This function scans the NAND flash for factory marked bad blocks and creates * a RAM based Bad Block Table(BBT). * * @param InstancePtr is a pointer to the XNandPsu instance. * * @return * - NONE * ******************************************************************************/ static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target) { u32 BlockIndex; u32 PageIndex; u32 Length; u32 BlockOffset; u8 BlockShift; u32 NumPages; u32 Page; u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks; u32 NumBlocks = InstancePtr->Geometry.NumTargetBlocks; s32 Status; /* Number of pages to search for bad block pattern */ if ((InstancePtr->BbPattern.Options & XNANDPSU_BBT_SCAN_2ND_PAGE) != 0U) { NumPages = 2U; } else { NumPages = 1U; } /* Scan all the blocks for factory marked bad blocks */ for(BlockIndex = StartBlock; BlockIndex < (StartBlock + NumBlocks); BlockIndex++) { /* Block offset in Bad Block Table(BBT) entry */ BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT; /* Block shift value in the byte */ BlockShift = XNandPsu_BbtBlockShift(BlockIndex); Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock; /* Search for the bad block pattern */ for(PageIndex = 0U; PageIndex < NumPages; PageIndex++) { Status = XNandPsu_ReadSpareBytes(InstancePtr, (Page + PageIndex), &Buf[0]); if (Status != XST_SUCCESS) { /* Marking as bad block */ InstancePtr->Bbt[BlockOffset] |= (u8)(XNANDPSU_BLOCK_FACTORY_BAD << BlockShift); break; } /* * Read the spare bytes to check for bad block * pattern */ for(Length = 0U; Length < InstancePtr->BbPattern.Length; Length++) { if (Buf[InstancePtr->BbPattern.Offset + Length] != InstancePtr->BbPattern.Pattern[Length]) { /* Bad block found */ InstancePtr->Bbt[BlockOffset] |= (u8) (XNANDPSU_BLOCK_FACTORY_BAD << BlockShift); break; } } } } } /*****************************************************************************/ /** * This function reads the Bad Block Table(BBT) if present in flash. If not it * scans the flash for detecting factory marked bad blocks and creates a bad * block table and write the Bad Block Table(BBT) into the flash. * * @param InstancePtr is a pointer to the XNandPsu instance. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr) { s32 Status; u32 Index; u32 BbtLen; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* Zero the RAM based Bad Block Table(BBT) entries */ BbtLen = InstancePtr->Geometry.NumBlocks >> XNANDPSU_BBT_BLOCK_SHIFT; (void)memset(&InstancePtr->Bbt[0], 0, BbtLen); for (Index = 0U; Index < InstancePtr->Geometry.NumTargets; Index++) { if (XNandPsu_ReadBbt(InstancePtr, Index) != XST_SUCCESS) { /* Create memory based Bad Block Table(BBT) */ XNandPsu_CreateBbt(InstancePtr, Index); /* Write the Bad Block Table(BBT) to the flash */ Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtDesc, &InstancePtr->BbtMirrorDesc, Index); if (Status != XST_SUCCESS) { goto Out; } /* Write the Mirror Bad Block Table(BBT) to the flash */ Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc, &InstancePtr->BbtDesc, Index); if (Status != XST_SUCCESS) { goto Out; } /* * Mark the blocks containing Bad Block Table * (BBT) as Reserved */ Status = XNandPsu_MarkBbt(InstancePtr, &InstancePtr->BbtDesc, Index); if (Status != XST_SUCCESS) { goto Out; } Status = XNandPsu_MarkBbt(InstancePtr, &InstancePtr->BbtMirrorDesc, Index); if (Status != XST_SUCCESS) { goto Out; } } } Status = XST_SUCCESS; Out: return Status; } /*****************************************************************************/ /** * This function converts the Bad Block Table(BBT) read from the flash to the * RAM based Bad Block Table(BBT). * * @param InstancePtr is a pointer to the XNandPsu instance. * @param Buf is the buffer which contains BBT read from flash. * * @return * - NONE. * ******************************************************************************/ static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target) { u32 BlockOffset; u8 BlockShift; u32 Data; u8 BlockType; u32 BlockIndex; u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >> XNANDPSU_BBT_BLOCK_SHIFT; u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks; for(BlockOffset = StartBlock; BlockOffset < (StartBlock + BbtLen); BlockOffset++) { Data = *(Buf + BlockOffset); /* Clear the RAM based Bad Block Table(BBT) contents */ InstancePtr->Bbt[BlockOffset] = 0x0U; /* Loop through the every 4 blocks in the bitmap */ for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS; BlockIndex++) { BlockShift = XNandPsu_BbtBlockShift(BlockIndex); BlockType = (u8) ((Data >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK); switch(BlockType) { case XNANDPSU_FLASH_BLOCK_FAC_BAD: /* Factory bad block */ InstancePtr->Bbt[BlockOffset] |= (u8) (XNANDPSU_BLOCK_FACTORY_BAD << BlockShift); break; case XNANDPSU_FLASH_BLOCK_RESERVED: /* Reserved block */ InstancePtr->Bbt[BlockOffset] |= (u8) (XNANDPSU_BLOCK_RESERVED << BlockShift); break; case XNANDPSU_FLASH_BLOCK_BAD: /* Bad block due to wear */ InstancePtr->Bbt[BlockOffset] |= (u8)(XNANDPSU_BLOCK_BAD << BlockShift); break; default: /* Good block */ /* The BBT entry already defaults to * zero */ break; } } } } /*****************************************************************************/ /** * This function searches the Bad Bloock Table(BBT) in flash and loads into the * memory based Bad Block Table(BBT). * * @param InstancePtr is the pointer to the XNandPsu instance. * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target) { u64 Offset; u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U}; s32 Status1; s32 Status2; s32 Status; u32 BufLen; XNandPsu_BbtDesc *Desc = &InstancePtr->BbtDesc; XNandPsu_BbtDesc *MirrorDesc = &InstancePtr->BbtMirrorDesc; BufLen = InstancePtr->Geometry.NumBlocks >> XNANDPSU_BBT_BLOCK_SHIFT; /* Search the Bad Block Table(BBT) in flash */ Status1 = XNandPsu_SearchBbt(InstancePtr, Desc, Target); Status2 = XNandPsu_SearchBbt(InstancePtr, MirrorDesc, Target); if ((Status1 != XST_SUCCESS) && (Status2 != XST_SUCCESS)) { #ifdef XNANDPSU_DEBUG xil_printf("%s: Bad block table not found\r\n",__func__); #endif Status = XST_FAILURE; goto Out; } #ifdef XNANDPSU_DEBUG xil_printf("%s: Bad block table found\r\n",__func__); #endif /* Bad Block Table found */ if ((Desc->Valid != 0U) && (MirrorDesc->Valid != 0U)) { /* Valid BBT & Mirror BBT found */ if (Desc->Version[Target] > MirrorDesc->Version[Target]) { Offset = (u64)Desc->PageOffset[Target] * (u64)InstancePtr->Geometry.BytesPerPage; Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); if (Status != XST_SUCCESS) { goto Out; } /* Convert flash BBT to memory based BBT */ XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); MirrorDesc->Version[Target] = Desc->Version[Target]; /* Write the BBT to Mirror BBT location in flash */ Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc, Target); if (Status != XST_SUCCESS) { goto Out; } } else if (Desc->Version[Target] < MirrorDesc->Version[Target]) { Offset = (u64)MirrorDesc->PageOffset[Target] * (u64)InstancePtr->Geometry.BytesPerPage; Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); if (Status != XST_SUCCESS) { goto Out; } /* Convert flash BBT to memory based BBT */ XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); Desc->Version[Target] = MirrorDesc->Version[Target]; /* Write the Mirror BBT to BBT location in flash */ Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc, Target); if (Status != XST_SUCCESS) { goto Out; } } else { /* Both are up-to-date */ Offset = (u64)Desc->PageOffset[Target] * (u64)InstancePtr->Geometry.BytesPerPage; Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); if (Status != XST_SUCCESS) { goto Out; } /* Convert flash BBT to memory based BBT */ XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); } } else if (Desc->Valid != 0U) { /* Valid Primary BBT found */ Offset = (u64)Desc->PageOffset[Target] * (u64)InstancePtr->Geometry.BytesPerPage; Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); if (Status != XST_SUCCESS) { goto Out; } /* Convert flash BBT to memory based BBT */ XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); MirrorDesc->Version[Target] = Desc->Version[Target]; /* Write the BBT to Mirror BBT location in flash */ Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc, Target); if (Status != XST_SUCCESS) { goto Out; } } else { /* Valid Mirror BBT found */ Offset = (u64)MirrorDesc->PageOffset[Target] * (u64)InstancePtr->Geometry.BytesPerPage; Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); if (Status != XST_SUCCESS) { goto Out; } /* Convert flash BBT to memory based BBT */ XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); Desc->Version[Target] = MirrorDesc->Version[Target]; /* Write the Mirror BBT to BBT location in flash */ Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc, Target); if (Status != XST_SUCCESS) { goto Out; } } Status = XST_SUCCESS; Out: return Status; } /*****************************************************************************/ /** * This function searches the BBT in flash. * * @param InstancePtr is the pointer to the XNandPsu instance. * @param Desc is the BBT descriptor pattern to search. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, u32 Target) { u32 StartBlock; u32 SigOffset; u32 VerOffset; u32 MaxBlocks; u32 PageOff; u32 SigLength; u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; u32 Block; u32 Offset; s32 Status; u64 BlockOff; StartBlock = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) - (u32)1; SigOffset = Desc->SigOffset; VerOffset = Desc->VerOffset; MaxBlocks = Desc->MaxBlocks; SigLength = Desc->SigLength; /* Read the last 4 blocks for Bad Block Table(BBT) signature */ for(Block = 0U; Block < MaxBlocks; Block++) { PageOff = (StartBlock - Block) * InstancePtr->Geometry.PagesPerBlock; Status = XNandPsu_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]); if (Status != XST_SUCCESS) { continue; } /* Check the Bad Block Table(BBT) signature */ for(Offset = 0U; Offset < SigLength; Offset++) { if (Buf[Offset + SigOffset] != (u8)(Desc->Signature[Offset])) { break; /* Check the next blocks */ } } if (Offset >= SigLength) { /* Bad Block Table(BBT) found */ Desc->PageOffset[Target] = PageOff; Desc->Version[Target] = Buf[VerOffset]; Desc->Valid = 1U; Status = XST_SUCCESS; goto Out; } } /* Bad Block Table(BBT) not found */ Status = XST_FAILURE; Out: return Status; } /*****************************************************************************/ /** * This function writes Bad Block Table(BBT) from RAM to flash. * * @param InstancePtr is the pointer to the XNandPsu instance. * @param Desc is the BBT descriptor to be written to flash. * @param MirrorDesc is the mirror BBT descriptor. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, XNandPsu_BbtDesc *MirrorDesc, u32 Target) { u64 Offset; u32 Block = {0U}; u32 EndBlock = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) - (u32)1; u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U}; u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; u8 Mask[4] = {0x00U, 0x01U, 0x02U, 0x03U}; u8 Data; u32 BlockOffset; u8 BlockShift; s32 Status; u32 BlockIndex; u32 Index; u8 BlockType; u32 BbtLen = InstancePtr->Geometry.NumBlocks >> XNANDPSU_BBT_BLOCK_SHIFT; /* Find a valid block to write the Bad Block Table(BBT) */ if ((!Desc->Valid) != 0U) { for(Index = 0U; Index < Desc->MaxBlocks; Index++) { Block = (EndBlock - Index); BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; BlockShift = XNandPsu_BbtBlockShift(Block); BlockType = (InstancePtr->Bbt[BlockOffset] >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK; switch(BlockType) { case XNANDPSU_BLOCK_BAD: case XNANDPSU_BLOCK_FACTORY_BAD: continue; default: /* Good Block */ break; } Desc->PageOffset[Target] = Block * InstancePtr->Geometry.PagesPerBlock; if (Desc->PageOffset[Target] != MirrorDesc->PageOffset[Target]) { /* Free block found */ Desc->Valid = 1U; break; } } /* Block not found for writing Bad Block Table(BBT) */ if (Index >= Desc->MaxBlocks) { #ifdef XNANDPSU_DEBUG xil_printf("%s: Blocks unavailable for writing BBT\r\n", __func__); #endif Status = XST_FAILURE; goto Out; } } else { Block = Desc->PageOffset[Target] / InstancePtr->Geometry.PagesPerBlock; } /* Convert the memory based BBT to flash based table */ (void)memset(Buf, 0xff, BbtLen); /* Loop through the number of blocks */ for(BlockOffset = 0U; BlockOffset < BbtLen; BlockOffset++) { Data = InstancePtr->Bbt[BlockOffset]; /* Calculate the bit mask for 4 blocks at a time in loop */ for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS; BlockIndex++) { BlockShift = XNandPsu_BbtBlockShift(BlockIndex); Buf[BlockOffset] &= ~(Mask[Data & XNANDPSU_BLOCK_TYPE_MASK] << BlockShift); Data >>= XNANDPSU_BBT_BLOCK_SHIFT; } } /* Write the Bad Block Table(BBT) to flash */ Status = XNandPsu_EraseBlock(InstancePtr, 0U, Block); if (Status != XST_SUCCESS) { goto Out; } /* Write the BBT to page offset */ Offset = (u64)Desc->PageOffset[Target] * (u64)InstancePtr->Geometry.BytesPerPage; Status = XNandPsu_Write(InstancePtr, Offset, BbtLen, &Buf[0]); if (Status != XST_SUCCESS) { goto Out; } /* Write the signature and version in the spare data area */ (void)memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage); Status = XNandPsu_ReadSpareBytes(InstancePtr, Desc->PageOffset[Target], &SpareBuf[0]); if (Status != XST_SUCCESS) { goto Out; } (void)memcpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0], Desc->SigLength); (void)memcpy(SpareBuf + Desc->VerOffset, &Desc->Version[Target], 1U); Status = XNandPsu_WriteSpareBytes(InstancePtr, Desc->PageOffset[Target], &SpareBuf[0]); if (Status != XST_SUCCESS) { goto Out; } Status = XST_SUCCESS; Out: return Status; } /*****************************************************************************/ /** * This function updates the primary and mirror Bad Block Table(BBT) in the * flash. * * @param InstancePtr is the pointer to the XNandPsu instance. * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target) { s32 Status; u8 Version; /* Update the version number */ Version = InstancePtr->BbtDesc.Version[Target]; InstancePtr->BbtDesc.Version[Target] = (u8)(((u16)Version + (u16)1) % (u16)256U); Version = InstancePtr->BbtMirrorDesc.Version[Target]; InstancePtr->BbtMirrorDesc.Version[Target] = (u8)(((u16)Version + (u16)1) % (u16)256); /* Update the primary Bad Block Table(BBT) in flash */ Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtDesc, &InstancePtr->BbtMirrorDesc, Target); if (Status != XST_SUCCESS) { goto Out; } /* Update the mirrored Bad Block Table(BBT) in flash */ Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc, &InstancePtr->BbtDesc, Target); if (Status != XST_SUCCESS) { goto Out; } Status = XST_SUCCESS; Out: return Status; } /*****************************************************************************/ /** * This function marks the block containing Bad Block Table as reserved * and updates the BBT. * * @param InstancePtr is the pointer to the XNandPsu instance. * @param Desc is the BBT descriptor pointer. * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc, u32 Target) { u32 BlockIndex; u32 BlockOffset; u8 BlockShift; u8 OldVal; u8 NewVal; s32 Status; u32 UpdateBbt = 0U; u32 Index; /* Mark the last four blocks as Reserved */ BlockIndex = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) - Desc->MaxBlocks - (u32)1; for(Index = 0U; Index < Desc->MaxBlocks; Index++) { BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT; BlockShift = XNandPsu_BbtBlockShift(BlockIndex); OldVal = InstancePtr->Bbt[BlockOffset]; NewVal = (u8) (OldVal | (XNANDPSU_BLOCK_RESERVED << BlockShift)); InstancePtr->Bbt[BlockOffset] = NewVal; if (OldVal != NewVal) { UpdateBbt = 1U; } BlockIndex++; } /* Update the BBT to flash */ if (UpdateBbt != 0U) { Status = XNandPsu_UpdateBbt(InstancePtr, Target); if (Status != XST_SUCCESS) { goto Out; } } Status = XST_SUCCESS; Out: return Status; } /*****************************************************************************/ /** * * This function checks whether a block is bad or not. * * @param InstancePtr is the pointer to the XNandPsu instance. * * @param Block is the block number. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block) { u8 Data; u8 BlockShift; u8 BlockType; u32 BlockOffset; s32 Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; BlockShift = XNandPsu_BbtBlockShift(Block); Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ BlockType = (Data >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK; if ((BlockType != XNANDPSU_BLOCK_GOOD) && (BlockType != XNANDPSU_BLOCK_RESERVED)) { Status = XST_SUCCESS; } else { Status = XST_FAILURE; } return Status; } /*****************************************************************************/ /** * This function marks a block as bad in the RAM based Bad Block Table(BBT). It * also updates the Bad Block Table(BBT) in the flash. * * @param InstancePtr is the pointer to the XNandPsu instance. * @param Block is the block number. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if fail. * ******************************************************************************/ s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block) { u8 Data; u8 BlockShift; u32 BlockOffset; u8 OldVal; u8 NewVal; s32 Status; u32 Target; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); Target = Block / InstancePtr->Geometry.NumTargetBlocks; BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; BlockShift = XNandPsu_BbtBlockShift(Block); Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ /* Mark the block as bad in the RAM based Bad Block Table */ OldVal = Data; Data &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift); Data |= (XNANDPSU_BLOCK_BAD << BlockShift); NewVal = Data; InstancePtr->Bbt[BlockOffset] = Data; /* Update the Bad Block Table(BBT) in flash */ if (OldVal != NewVal) { Status = XNandPsu_UpdateBbt(InstancePtr, Target); if (Status != XST_SUCCESS) { goto Out; } } Status = XST_SUCCESS; Out: return Status; } /** @} */