embeddedsw/XilinxProcessorIPLib/drivers/nandpsu/src/xnandpsu_bbm.c
Punnaiah Choudary Kalluri c46210930c nandpsu: Convert the three line comments to single line
This patch converts the three line comments to single line

Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
Acked-by: Anirudha Sarangi   <anirudh@xilinx.com>
2015-07-31 16:56:13 +05:30

912 lines
27 KiB
C

/******************************************************************************
*
* 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
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- ---------- -----------------------------------------------
* 1.0 nm 05/06/2014 First release
* 2.0 sb 01/12/2015 Added support for writing BBT signature and version
* in page section by enabling XNANDPSU_BBT_NO_OOB.
* Modified Bbt Signature and Version Offset value for
* Oob and No-Oob region.
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include <string.h> /**< 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;
}
/** @} */