diff options
Diffstat (limited to 'bsps/shared/dev/nand/xnandpsu_bbm.c')
-rw-r--r-- | bsps/shared/dev/nand/xnandpsu_bbm.c | 1001 |
1 files changed, 1001 insertions, 0 deletions
diff --git a/bsps/shared/dev/nand/xnandpsu_bbm.c b/bsps/shared/dev/nand/xnandpsu_bbm.c new file mode 100644 index 0000000000..40cf798965 --- /dev/null +++ b/bsps/shared/dev/nand/xnandpsu_bbm.c @@ -0,0 +1,1001 @@ +/****************************************************************************** +* Copyright (C) 2015 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xnandpsu_bbm.c +* @addtogroup Overview +* @{ +* +* This file implements the Bad Block Management (BBM) functionality. +* See xnandpsu_bbm.h for more details. +* +* @note None +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- ---------- ----------------------------------------------- +* 1.0 nm 05/06/2014 First release +* 2.0 sb 01/12/2015 Added support for writing BBT signature and version +* in page section by enabling XNANDPSU_BBT_NO_OOB. +* Modified Bbt Signature and Version Offset value for +* Oob and No-Oob region. +* 1.1 nsk 11/07/16 Change memcpy to Xil_MemCpy to handle word aligned +* data access. +* 1.4 nsk 04/10/18 Added ICCARM compiler support. +* 1.10 akm 01/05/22 Remove assert checks form static and internal APIs. +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include <string.h> /**< For Xil_MemCpy and memset */ +#include "xil_types.h" +#include "xnandpsu.h" +#include "xnandpsu_bbm.h" +#include "xil_mem.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target); + +static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + u32 Target); + +static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target); + +static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target); + +static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + XNandPsu_BbtDesc *MirrorDesc, u32 Target); + +static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc, + u32 Target); + +#ifndef __rtems__ +static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target); +#endif + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* This function initializes the Bad Block Table(BBT) descriptors with a +* predefined pattern for searching Bad Block Table(BBT) in flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - NONE +* +******************************************************************************/ +void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr) +{ + u32 Index; + + /* Initialize primary Bad Block Table(BBT) */ + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtDesc.PageOffset[Index] = + XNANDPSU_BBT_DESC_PAGE_OFFSET; + } + if (InstancePtr->EccMode == XNANDPSU_ONDIE) { + InstancePtr->BbtDesc.SigOffset = XNANDPSU_ONDIE_SIG_OFFSET; + InstancePtr->BbtDesc.VerOffset = XNANDPSU_ONDIE_VER_OFFSET; + } else { + InstancePtr->BbtDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET; + InstancePtr->BbtDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET; + } + InstancePtr->BbtDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN; + InstancePtr->BbtDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS; + (void)strcpy(&InstancePtr->BbtDesc.Signature[0], "Bbt0"); + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtDesc.Version[Index] = 0U; + } + InstancePtr->BbtDesc.Valid = 0U; + + /* Assuming that the flash device will have at least 4 blocks. */ + if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr-> + BbtDesc.MaxBlocks){ + InstancePtr->BbtDesc.MaxBlocks = 4U; + } + + /* Initialize mirror Bad Block Table(BBT) */ + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtMirrorDesc.PageOffset[Index] = + XNANDPSU_BBT_DESC_PAGE_OFFSET; + } + if (InstancePtr->EccMode == XNANDPSU_ONDIE) { + InstancePtr->BbtMirrorDesc.SigOffset = + XNANDPSU_ONDIE_SIG_OFFSET; + InstancePtr->BbtMirrorDesc.VerOffset = + XNANDPSU_ONDIE_VER_OFFSET; + } else { + InstancePtr->BbtMirrorDesc.SigOffset = + XNANDPSU_BBT_DESC_SIG_OFFSET; + InstancePtr->BbtMirrorDesc.VerOffset = + XNANDPSU_BBT_DESC_VER_OFFSET; + } + InstancePtr->BbtMirrorDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN; + InstancePtr->BbtMirrorDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS; + (void)strcpy(&InstancePtr->BbtMirrorDesc.Signature[0], "1tbB"); + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtMirrorDesc.Version[Index] = 0U; + } + InstancePtr->BbtMirrorDesc.Valid = 0U; + + /* Assuming that the flash device will have at least 4 blocks. */ + if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr-> + BbtMirrorDesc.MaxBlocks){ + InstancePtr->BbtMirrorDesc.MaxBlocks = 4U; + } + + /* Initialize Bad block search pattern structure */ + if (InstancePtr->Geometry.BytesPerPage > 512U) { + /* For flash page size > 512 bytes */ + InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE; + InstancePtr->BbPattern.Offset = + XNANDPSU_BB_PTRN_OFF_LARGE_PAGE; + InstancePtr->BbPattern.Length = + XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; + } else { + InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE; + InstancePtr->BbPattern.Offset = + XNANDPSU_BB_PTRN_OFF_SML_PAGE; + InstancePtr->BbPattern.Length = + XNANDPSU_BB_PTRN_LEN_SML_PAGE; + } + for(Index = 0U; Index < XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; Index++) { + InstancePtr->BbPattern.Pattern[Index] = XNANDPSU_BB_PATTERN; + } +} + +/*****************************************************************************/ +/** +* This function scans the NAND flash for factory marked bad blocks and creates +* a RAM based Bad Block Table(BBT). +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - NONE +* +******************************************************************************/ +static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target) +{ + u32 BlockIndex; + u32 PageIndex; + u32 Length; + u32 BlockOffset; + u8 BlockShift; + u32 NumPages; + u32 Page; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; +#endif + u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks; + u32 NumBlocks = InstancePtr->Geometry.NumTargetBlocks; + s32 Status; + + /* Number of pages to search for bad block pattern */ + if ((InstancePtr->BbPattern.Options & XNANDPSU_BBT_SCAN_2ND_PAGE) != 0U) + { + NumPages = 2U; + } else { + NumPages = 1U; + } + /* Scan all the blocks for factory marked bad blocks */ + for(BlockIndex = StartBlock; BlockIndex < (StartBlock + NumBlocks); + BlockIndex++) { + /* Block offset in Bad Block Table(BBT) entry */ + BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT; + /* Block shift value in the byte */ + BlockShift = XNandPsu_BbtBlockShift(BlockIndex); + Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock; + /* Search for the bad block pattern */ + for(PageIndex = 0U; PageIndex < NumPages; PageIndex++) { + Status = XNandPsu_ReadSpareBytes(InstancePtr, + (Page + PageIndex), &Buf[0]); + + if (Status != XST_SUCCESS) { + /* Marking as bad block */ + InstancePtr->Bbt[BlockOffset] |= + (u8)(XNANDPSU_BLOCK_FACTORY_BAD << + BlockShift); + break; + } + /* + * Read the spare bytes to check for bad block + * pattern + */ + for(Length = 0U; Length < + InstancePtr->BbPattern.Length; Length++) { + if (Buf[InstancePtr->BbPattern.Offset + Length] + != + InstancePtr->BbPattern.Pattern[Length]) + { + /* Bad block found */ + InstancePtr->Bbt[BlockOffset] |= + (u8) + (XNANDPSU_BLOCK_FACTORY_BAD << + BlockShift); + break; + } + } + } + } +} + +/*****************************************************************************/ +/** +* This function reads the Bad Block Table(BBT) if present in flash. If not it +* scans the flash for detecting factory marked bad blocks and creates a bad +* block table and write the Bad Block Table(BBT) into the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + + s32 Status; + u32 Index; + u32 BbtLen; + + /* Zero the RAM based Bad Block Table(BBT) entries */ + BbtLen = InstancePtr->Geometry.NumBlocks >> + XNANDPSU_BBT_BLOCK_SHIFT; + (void)memset(&InstancePtr->Bbt[0], 0, BbtLen); + + for (Index = 0U; Index < InstancePtr->Geometry.NumTargets; Index++) { + + if (XNandPsu_ReadBbt(InstancePtr, Index) != XST_SUCCESS) { + /* Create memory based Bad Block Table(BBT) */ + XNandPsu_CreateBbt(InstancePtr, Index); + /* Write the Bad Block Table(BBT) to the flash */ + Status = XNandPsu_WriteBbt(InstancePtr, + &InstancePtr->BbtDesc, + &InstancePtr->BbtMirrorDesc, Index); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Write the Mirror Bad Block Table(BBT) to the flash */ + Status = XNandPsu_WriteBbt(InstancePtr, + &InstancePtr->BbtMirrorDesc, + &InstancePtr->BbtDesc, Index); + if (Status != XST_SUCCESS) { + goto Out; + } + /* + * Mark the blocks containing Bad Block Table + * (BBT) as Reserved + */ + Status = XNandPsu_MarkBbt(InstancePtr, + &InstancePtr->BbtDesc, + Index); + if (Status != XST_SUCCESS) { + goto Out; + } + Status = XNandPsu_MarkBbt(InstancePtr, + &InstancePtr->BbtMirrorDesc, + Index); + if (Status != XST_SUCCESS) { + goto Out; + } + } + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function converts the Bad Block Table(BBT) read from the flash to the +* RAM based Bad Block Table(BBT). +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Buf is the buffer which contains BBT read from flash. +* +* @return +* - NONE. +* +******************************************************************************/ +static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target) +{ +#ifndef __rtems__ + u32 BlockOffset; + u8 BlockShift; + u32 Data; + u8 BlockType; + u32 BlockIndex; +#endif + u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >> + XNANDPSU_BBT_BLOCK_SHIFT; +#ifdef __rtems__ + u32 BbtOffset = Target * InstancePtr->Geometry.NumTargetBlocks / XNANDPSU_BBT_ENTRY_NUM_BLOCKS; + + for(u32 BbtIndex = 0; BbtIndex < BbtLen; BbtIndex++) { + /* Invert the byte to convert from in-flash BBT to in-memory BBT */ + InstancePtr->Bbt[BbtIndex + BbtOffset] = ~Buf[BbtIndex]; + } +#else + 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; + } + } + } +#endif +} + +/*****************************************************************************/ +/** +* This function searches the Bad Bloock Table(BBT) in flash and loads into the +* memory based Bad Block Table(BBT). +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target) +{ + u64 Offset; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U}; +#endif + s32 Status1; + s32 Status2; + s32 Status; + u32 BufLen; + + XNandPsu_BbtDesc *Desc = &InstancePtr->BbtDesc; + XNandPsu_BbtDesc *MirrorDesc = &InstancePtr->BbtMirrorDesc; +#ifdef __rtems__ + BufLen = InstancePtr->Geometry.NumTargetBlocks >> +#else + BufLen = InstancePtr->Geometry.NumBlocks >> +#endif + XNANDPSU_BBT_BLOCK_SHIFT; + /* Search the Bad Block Table(BBT) in flash */ + Status1 = XNandPsu_SearchBbt(InstancePtr, Desc, Target); + Status2 = XNandPsu_SearchBbt(InstancePtr, MirrorDesc, Target); + if ((Status1 != XST_SUCCESS) && (Status2 != XST_SUCCESS)) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Bad block table not found\r\n",__func__); +#endif + Status = XST_FAILURE; + goto Out; + } +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Bad block table found\r\n",__func__); +#endif + /* Bad Block Table found */ + if ((Desc->Valid != 0U) && (MirrorDesc->Valid != 0U)) { + /* Valid BBT & Mirror BBT found */ + if (Desc->Version[Target] > MirrorDesc->Version[Target]) { + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + MirrorDesc->Version[Target] = Desc->Version[Target]; + + /* Write the BBT to Mirror BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, + Desc, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } else if (Desc->Version[Target] < + MirrorDesc->Version[Target]) { + Offset = (u64)MirrorDesc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + Desc->Version[Target] = MirrorDesc->Version[Target]; + + /* Write the Mirror BBT to BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, Desc, + MirrorDesc, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } else { + /* Both are up-to-date */ + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + } + } else if (Desc->Valid != 0U) { + /* Valid Primary BBT found */ + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + MirrorDesc->Version[Target] = Desc->Version[Target]; + + /* Write the BBT to Mirror BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc, + Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } else { + /* Valid Mirror BBT found */ + Offset = (u64)MirrorDesc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + Desc->Version[Target] = MirrorDesc->Version[Target]; + + /* Write the Mirror BBT to BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc, + Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function searches the BBT in flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Desc is the BBT descriptor pattern to search. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + u32 Target) +{ + u32 StartBlock; + u32 SigOffset; + u32 VerOffset; + u32 MaxBlocks; + u32 PageOff; + u32 SigLength; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; +#endif + u32 Block; + u32 Offset; + s32 Status; + + StartBlock = ((Target + (u32)1) * + InstancePtr->Geometry.NumTargetBlocks) - (u32)1; + SigOffset = Desc->SigOffset; + VerOffset = Desc->VerOffset; + MaxBlocks = Desc->MaxBlocks; + SigLength = Desc->SigLength; +#ifdef __rtems__ + Desc->Valid = 0; +#endif + + /* Read the last 4 blocks for Bad Block Table(BBT) signature */ + for(Block = 0U; Block < MaxBlocks; Block++) { + PageOff = (StartBlock - Block) * + InstancePtr->Geometry.PagesPerBlock; + + Status = XNandPsu_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]); + if (Status != XST_SUCCESS) { + continue; + } + /* Check the Bad Block Table(BBT) signature */ + for(Offset = 0U; Offset < SigLength; Offset++) { + if (Buf[Offset + SigOffset] != + (u8)(Desc->Signature[Offset])) + { + break; /* Check the next blocks */ + } + } + if (Offset >= SigLength) { + /* Bad Block Table(BBT) found */ + Desc->PageOffset[Target] = PageOff; + Desc->Version[Target] = Buf[VerOffset]; + Desc->Valid = 1U; + + Status = XST_SUCCESS; + goto Out; + } + } + /* Bad Block Table(BBT) not found */ + Status = XST_FAILURE; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function writes Bad Block Table(BBT) from RAM to flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Desc is the BBT descriptor to be written to flash. +* @param MirrorDesc is the mirror BBT descriptor. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + XNandPsu_BbtDesc *MirrorDesc, u32 Target) +{ + u64 Offset; + u32 Block = {0U}; + u32 EndBlock = ((Target + (u32)1) * + InstancePtr->Geometry.NumTargetBlocks) - (u32)1; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U}; + u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE]= {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U}; + u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; +#endif + +#ifndef __rtems__ + 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 >> +#else + s32 Status; + u32 Index; + u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >> +#endif + 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); +#ifdef __rtems__ + if (XNandPsu_IsBlockBad(InstancePtr, Block) != XST_FAILURE) { + continue; + } +#else + 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; + } +#endif + 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); + +#ifdef __rtems__ + u32 BbtTargetOffset = BbtLen * Target; + /* Loop through the BBT entries */ + for(u32 BbtIndex = 0U; BbtIndex < BbtLen; BbtIndex++) { + /* Invert byte to convert from in-memory BBT to in-flash BBT */ + Buf[BbtIndex] = ~InstancePtr->Bbt[BbtIndex + BbtTargetOffset]; + } +#else + /* 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; + } + } +#endif + /* Write the Bad Block Table(BBT) to flash */ +#ifdef __rtems__ + Status = XNandPsu_EraseBlock(InstancePtr, Target, + Block % InstancePtr->Geometry.NumTargetBlocks); +#else + Status = XNandPsu_EraseBlock(InstancePtr, 0U, Block); +#endif + if (Status != XST_SUCCESS) { + goto Out; + } + + /* Write the BBT to page offset */ + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Write(InstancePtr, Offset, BbtLen, &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Write the signature and version in the spare data area */ + (void)memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage); + Status = XNandPsu_ReadSpareBytes(InstancePtr, Desc->PageOffset[Target], + &SpareBuf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + + (void)Xil_MemCpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0], + Desc->SigLength); + (void)memcpy(SpareBuf + Desc->VerOffset, &Desc->Version[Target], 1U); + + Status = XNandPsu_WriteSpareBytes(InstancePtr, + Desc->PageOffset[Target], &SpareBuf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function updates the primary and mirror Bad Block Table(BBT) in the +* flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +#ifdef __rtems__ +s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target) +#else +static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target) +#endif +{ + 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) - +#ifdef __rtems__ + Desc->MaxBlocks; +#else + Desc->MaxBlocks - (u32)1; +#endif + + for(Index = 0U; Index < Desc->MaxBlocks; Index++) { + + BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(BlockIndex); + OldVal = InstancePtr->Bbt[BlockOffset]; + NewVal = (u8) (OldVal | (XNANDPSU_BLOCK_RESERVED << + BlockShift)); + InstancePtr->Bbt[BlockOffset] = NewVal; + + if (OldVal != NewVal) { + UpdateBbt = 1U; + } + BlockIndex++; + } + + /* Update the BBT to flash */ + if (UpdateBbt != 0U) { + Status = XNandPsu_UpdateBbt(InstancePtr, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function checks whether a block is bad or not. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* +* @param Block is the block number. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); + + u8 Data; + u8 BlockShift; + u8 BlockType; + u32 BlockOffset; + s32 Status; + + BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(Block); + Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ + BlockType = (Data >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK; + + if ((BlockType != XNANDPSU_BLOCK_GOOD) && + (BlockType != XNANDPSU_BLOCK_RESERVED)) { + Status = XST_SUCCESS; + } + else { + Status = XST_FAILURE; + } + return Status; +} + +/*****************************************************************************/ +/** +* This function marks a block as bad in the RAM based Bad Block Table(BBT). It +* also updates the Bad Block Table(BBT) in the flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Block is the block number. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block) +#ifdef __rtems__ +{ + return XNandPsu_MarkBlock(InstancePtr, Block, XNANDPSU_BLOCK_BAD ); +} + +s32 XNandPsu_MarkBlock(XNandPsu *InstancePtr, u32 Block, u8 BlockMark) +#endif +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); + +#ifdef __rtems__ + BlockMark &= XNANDPSU_BLOCK_TYPE_MASK; +#endif + + u8 Data; + u8 BlockShift; + u32 BlockOffset; + u8 OldVal; + u8 NewVal; + s32 Status; + u32 Target; + + Target = Block / InstancePtr->Geometry.NumTargetBlocks; + + BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(Block); + Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ + + /* Mark the block as bad in the RAM based Bad Block Table */ + OldVal = Data; + Data &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift); +#ifdef __rtems__ + Data |= (BlockMark << BlockShift); +#else + Data |= (XNANDPSU_BLOCK_BAD << BlockShift); +#endif + 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; +} + +#ifdef __rtems__ +bool XNandPsu_StageBlockMark(XNandPsu *InstancePtr, u32 Block, u8 BlockMark) +{ + u8 BlockShift; + u32 BlockOffset; + u8 OldVal; + + BlockMark &= XNANDPSU_BLOCK_TYPE_MASK; + + BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(Block); + OldVal = InstancePtr->Bbt[BlockOffset] >> BlockShift; + OldVal &= XNANDPSU_BLOCK_TYPE_MASK; + InstancePtr->Bbt[BlockOffset] &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift); + InstancePtr->Bbt[BlockOffset] |= (BlockMark << BlockShift); + return BlockMark != OldVal; +} +#endif + +/** @} */ |