rt-thread/bsp/phytium/libraries/standalone/drivers/nand/fnand/fnand_bbm.c

883 lines
29 KiB
C
Raw Normal View History

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Phytium Public License for more details.
*
*
* FilePath: fnand_bbm.c
* Date: 2022-02-10 14:53:42
* LastEditTime: 2022-02-18 08:56:12
* Description:  This file implements the bad block management (BBM) functionality.
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 huanghe 2022/05/10 first release
*/
#include "fnand_bbm.h"
#include "fnand.h"
#include "fparameters.h"
#include <string.h>
#include "fdebug.h"
#define FNAND_BBM_DEBUG_TAG "FNAND_BBM"
#define FNAND_BBM_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FNAND_BBM_DEBUG_TAG, format, ##__VA_ARGS__)
#define FNAND_BBM_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FNAND_BBM_DEBUG_TAG, format, ##__VA_ARGS__)
#define FNAND_BBM_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FNAND_BBM_DEBUG_TAG, format, ##__VA_ARGS__)
static FError FNandWriteBbt(FNand *instance_p,
FNandBbtDesc *desc_p,
FNandBbtDesc *mirror_desc_p,
u32 chip_addr);
/**
* @name: FNandInitBbtDesc
* @msg: This function initializes the Bad Block Table(BBT) descriptors with a
* predefined pattern for searching Bad Block Table(BBT) in flash.
* @param {FNand} *instance_p is the pointer to the FNand instance.
* @return {*}
* @note:
*/
void FNandInitBbtDesc(FNand *instance_p)
{
u32 i;
int index;
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
for (i = 0; i < FNAND_CONNECT_MAX_NUM; i++)
{
/*
* Initialize primary Bad Block Table(BBT)
*/
instance_p->bbt_manager[i].bbt_desc.page_offset = FNAND_BBT_DESC_PAGE_OFFSET;
instance_p->bbt_manager[i].bbt_desc.sig_offset = FNAND_BBT_DESC_SIG_OFFSET;
instance_p->bbt_manager[i].bbt_desc.ver_offset = FNAND_BBT_DESC_VER_OFFSET;
instance_p->bbt_manager[i].bbt_desc.max_blocks = FNAND_BBT_DESC_MAX_BLOCKS;
instance_p->bbt_manager[i].bbt_desc.sig_length = FNAND_BBT_DESC_SIG_LEN;
strcpy(&instance_p->bbt_manager[i].bbt_desc.signature[0], "Bbt0");
instance_p->bbt_manager[i].bbt_desc.version = 0;
instance_p->bbt_manager[i].bbt_desc.valid = 0;
/*
* Initialize mirror Bad Block Table(BBT)
*/
instance_p->bbt_manager[i].bbt_mirror_desc.page_offset = FNAND_BBT_DESC_PAGE_OFFSET;
instance_p->bbt_manager[i].bbt_mirror_desc.sig_offset = FNAND_BBT_DESC_SIG_OFFSET;
instance_p->bbt_manager[i].bbt_mirror_desc.ver_offset = FNAND_BBT_DESC_VER_OFFSET;
instance_p->bbt_manager[i].bbt_mirror_desc.sig_length = FNAND_BBT_DESC_SIG_LEN;
instance_p->bbt_manager[i].bbt_mirror_desc.max_blocks = FNAND_BBT_DESC_MAX_BLOCKS;
strcpy(&instance_p->bbt_manager[i].bbt_mirror_desc.signature[0], "1tbB");
instance_p->bbt_manager[i].bbt_mirror_desc.version = 0;
instance_p->bbt_manager[i].bbt_mirror_desc.valid = 0;
/*
* Initialize Bad block search pattern structure
*/
if (instance_p->nand_geometry[i].bytes_per_page > 512)
{
/* For flash page size > 512 bytes */
instance_p->bbt_manager[i].bb_pattern.options = FNAND_BBT_SCAN_2ND_PAGE;
instance_p->bbt_manager[i].bb_pattern.offset =
FNAND_BB_PATTERN_OFFSET_LARGE_PAGE;
instance_p->bbt_manager[i].bb_pattern.length =
FNAND_BB_PATTERN_LENGTH_LARGE_PAGE;
}
else
{
instance_p->bbt_manager[i].bb_pattern.options = FNAND_BBT_SCAN_2ND_PAGE;
instance_p->bbt_manager[i].bb_pattern.offset =
FNAND_BB_PATTERN_OFFSET_SMALL_PAGE;
instance_p->bbt_manager[i].bb_pattern.length =
FNAND_BB_PATTERN_LENGTH_SMALL_PAGE;
}
for (index = 0; index < FNAND_BB_PATTERN_LENGTH_LARGE_PAGE; index++)
{
instance_p->bbt_manager[i].bb_pattern.pattern[index] = FNAND_BB_PATTERN;
}
}
}
/**
* @name: FNandConvertBbt
* @msg: Convert bitmask read in flash to information stored in RAM
* @return {*}
* @note:
* @param {FNand} *instance_p is the pointer to the FNand instance.
* @param {u8} *buf is buffer to store the bitmask
* @param {u32} chip_addr is chip address
*/
static void FNandConvertBbt(FNand *instance_p, u8 *buf, u32 chip_addr)
{
u32 block_offset;
u32 block_shift;
u32 data;
u8 block_type;
u32 block_index;
u32 bbtlen = instance_p->nand_geometry[chip_addr].num_blocks >>
FNAND_BBT_BLOCK_SHIFT;
for (block_offset = 0; block_offset < bbtlen; block_offset++)
{
data = buf[block_offset];
/*
* Clear the RAM based Bad Block Table(BBT) contents
*/
instance_p->bbt_manager[chip_addr].bbt[block_offset] = 0x0;
/*
* Loop through the every 4 blocks in the bitmap
*/
for (block_index = 0; block_index < FNAND_BBT_ENTRY_NUM_BLOCKS;
block_index++)
{
block_shift = FNAND_BBTBLOCKSHIFT(block_index);
block_type = (data >> block_shift) &
FNAND_BLOCK_TYPE_MASK;
switch (block_type)
{
case FNAND_FLASH_BLOCK_FACTORY_BAD:
/* Factory bad block */
instance_p->bbt_manager[chip_addr].bbt[block_offset] |=
FNAND_BLOCK_FACTORY_BAD << block_shift;
break;
case FNAND_FLASH_BLOCK_RESERVED:
/* Reserved block */
instance_p->bbt_manager[chip_addr].bbt[block_offset] |=
FNAND_BLOCK_RESERVED << block_shift;
break;
case FNAND_FLASH_BLOCK_BAD:
/* Bad block due to wear */
instance_p->bbt_manager[chip_addr].bbt[block_offset] |=
FNAND_BLOCK_BAD << block_shift;
break;
default:
/* Good block */
/* The BBT entry already defaults to
* zero */
break;
}
}
}
}
static FError FNandUpdateBbt(FNand *instance_p, u32 chip_addr)
{
FError ret;
u8 version;
/*
* Update the version number
*/
version = instance_p->bbt_manager[chip_addr].bbt_desc.version;
instance_p->bbt_manager[chip_addr].bbt_desc.version = (version + 1) % 256;
version = instance_p->bbt_manager[chip_addr].bbt_mirror_desc.version;
instance_p->bbt_manager[chip_addr].bbt_mirror_desc.version = (version + 1) % 256;
/*
* Update the primary Bad Block Table(BBT) in flash
*/
ret = FNandWriteBbt(instance_p,
&instance_p->bbt_manager[chip_addr].bbt_desc,
&instance_p->bbt_manager[chip_addr].bbt_mirror_desc, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
/*
* Update the mirrored Bad Block Table(BBT) in flash
*/
ret = FNandWriteBbt(instance_p,
&instance_p->bbt_manager[chip_addr].bbt_mirror_desc,
&instance_p->bbt_manager[chip_addr].bbt_desc, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
return FT_SUCCESS;
}
static FError FNandMarkBbt(FNand *instance_p,
FNandBbtDesc *desc_p,
u32 chip_addr)
{
u32 block_index;
u32 block_offset;
u8 block_shift;
u8 old_val;
u8 new_val;
FError ret;
u32 updatebbt = 0;
u32 index;
/*
* Mark the last four blocks as Reserved
*/
block_index = instance_p->nand_geometry[chip_addr].num_blocks - desc_p->max_blocks;
for (index = 0; index < desc_p->max_blocks; index++, block_index++)
{
block_offset = block_index >> FNAND_BBT_BLOCK_SHIFT;
block_shift = FNAND_BBTBLOCKSHIFT(block_index);
old_val = instance_p->bbt_manager[chip_addr].bbt[block_offset];
new_val = old_val | (FNAND_BLOCK_RESERVED << block_shift);
instance_p->bbt_manager[chip_addr].bbt[block_offset] = new_val;
if (old_val != new_val)
{
updatebbt = 1;
}
}
/*
* Update the BBT to flash
*/
if (updatebbt)
{
ret = FNandUpdateBbt(instance_p, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
}
return FT_SUCCESS;
}
static FError FNandWriteBbt(FNand *instance_p,
FNandBbtDesc *desc_p,
FNandBbtDesc *mirror_desc_p,
u32 chip_addr)
{
u64 offset;
u32 block = instance_p->nand_geometry[chip_addr].num_blocks - 1;
u8 buf[FNAND_MAX_BLOCKS >> FNAND_BBT_BLOCK_SHIFT];
u8 sparebuf[FNAND_MAX_SPARE_SIZE];
u8 mask[4] = {0x00, 0x01, 0x02, 0x03};
u8 Data;
u32 block_offset;
u32 block_shift;
FError ret;
u32 block_index;
u32 index;
u8 block_type;
u32 bbtlen = instance_p->nand_geometry[chip_addr].num_blocks >>
FNAND_BBT_BLOCK_SHIFT;
FNAND_BBM_DEBUG_I("FNandWriteBbt bbtlen is %d", bbtlen);
/*
* Find a valid block to write the Bad Block Table(BBT)
*/
if (!desc_p->valid)
{
for (index = 0; index < desc_p->max_blocks; index++)
{
block = (block - index);
block_offset = block >> FNAND_BBT_BLOCK_SHIFT;
block_shift = FNAND_BBTBLOCKSHIFT(block);
block_type = (instance_p->bbt_manager[chip_addr].bbt[block_offset] >>
block_shift) &
FNAND_BLOCK_TYPE_MASK;
switch (block_type)
{
case FNAND_BLOCK_BAD:
case FNAND_BLOCK_FACTORY_BAD:
continue;
default:
/* Good Block */
break;
}
desc_p->page_offset = block *
instance_p->nand_geometry[chip_addr].pages_per_block;
if (desc_p->page_offset != mirror_desc_p->page_offset)
{
/* Free block found */
desc_p->valid = 1;
break;
}
}
/*
* Block not found for writing Bad Block Table(BBT)
*/
if (index >= desc_p->max_blocks)
{
return FNAND_VALUE_FAILURE;
}
}
else
{
block = desc_p->page_offset / instance_p->nand_geometry[chip_addr].pages_per_block;
}
/*
* Convert the memory based BBT to flash based table
*/
memset(buf, 0xff, bbtlen);
/*
* Loop through the number of blocks
*/
for (block_offset = 0; block_offset < bbtlen; block_offset++)
{
Data = instance_p->bbt_manager[chip_addr].bbt[block_offset];
/*
* Calculate the bit mask for 4 blocks at a time in loop
*/
for (block_index = 0; block_index < FNAND_BBT_ENTRY_NUM_BLOCKS;
block_index++)
{
block_shift = FNAND_BBTBLOCKSHIFT(block_index);
buf[block_offset] &= ~(mask[Data &
FNAND_BLOCK_TYPE_MASK]
<< block_shift);
Data >>= FNAND_BBT_BLOCK_SHIFT;
}
}
/*
* Write the Bad Block Table(BBT) to flash
*/
ret = FNandEraseBlock(instance_p, block, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
/*
* Write the signature and version in the spare data area
*/
memset(sparebuf, 0xff, instance_p->nand_geometry[chip_addr].spare_bytes_per_page);
memcpy(sparebuf + desc_p->sig_offset, &desc_p->signature[0],
desc_p->sig_length);
memcpy(sparebuf + desc_p->ver_offset, &desc_p->version, 1);
/*
* Write the BBT to page offset
*/
FNandWritePage(instance_p, desc_p->page_offset, &buf[0], 0, bbtlen, sparebuf, 0, sizeof(sparebuf), chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
return FT_SUCCESS;
}
static void FNandCreateBbt(FNand *instance_p, u32 chip_addr)
{
u32 block_index;
u32 page_index;
u32 length;
u32 block_offset;
u32 block_shift;
u32 num_pages;
u32 page;
u8 buf[FNAND_MAX_SPARE_SIZE];
u32 bbt_len = instance_p->nand_geometry[chip_addr].num_blocks >>
FNAND_BBT_BLOCK_SHIFT;
FError ret;
/*
* Number of pages to search for bad block pattern
*/
if (instance_p->bbt_manager[chip_addr].bb_pattern.options & FNAND_BBT_SCAN_2ND_PAGE)
{
num_pages = 2;
}
else
{
num_pages = 1;
}
/*
* Zero the RAM based Bad Block Table(BBT) entries
*/
memset(&instance_p->bbt_manager[chip_addr].bbt[0], 0, bbt_len);
/*
* Scan all the blocks for factory marked bad blocks
*/
for (block_index = 0; block_index <
instance_p->nand_geometry[chip_addr].num_blocks;
block_index++)
{
/*
* Block offset in Bad Block Table(BBT) entry
*/
block_offset = block_index >> FNAND_BBT_BLOCK_SHIFT;
/*
* Block shift value in the byte
*/
block_shift = FNAND_BBTBLOCKSHIFT(block_index);
page = block_index * instance_p->nand_geometry[chip_addr].pages_per_block;
/*
* Search for the bad block pattern
*/
for (page_index = 0; page_index < num_pages; page_index++)
{
ret = FNandReadPageOOb(instance_p, page + page_index, buf, 0, sizeof(buf), chip_addr);
if (ret != FT_SUCCESS)
{
FNAND_BBM_DEBUG_E("%s FNandReadPageOOb is error", __func__);
/* Marking as bad block */
instance_p->bbt_manager[chip_addr].bbt[block_offset] |=
(FNAND_BLOCK_FACTORY_BAD << block_shift);
break;
}
/*
* Read the spare bytes to check for bad block
* pattern
*/
for (length = 0; length <
instance_p->bbt_manager[chip_addr].bb_pattern.length;
length++)
{
if (buf[instance_p->bbt_manager[chip_addr].bb_pattern.offset + length] !=
instance_p->bbt_manager[chip_addr].bb_pattern.pattern[length])
{
/* Bad block found */
instance_p->bbt_manager[chip_addr].bbt[block_offset] |=
(FNAND_BLOCK_FACTORY_BAD << block_shift);
FNAND_BBM_DEBUG_E("Bad block found block is %d", page + page_index);
break;
}
}
}
}
}
FError FNandSearchBbt(FNand *instance_p, FNandBbtDesc *desc, u32 chip_addr)
{
u32 start_block;
u32 sig_offset;
u32 ver_offset;
u32 max_blocks;
u32 pageoff;
u32 sig_length;
u8 buf[FNAND_MAX_SPARE_SIZE];
u32 block;
u32 offset;
FError ret;
start_block = instance_p->nand_geometry[chip_addr].num_blocks - 1; /* start block is last block start */
sig_offset = desc->sig_offset;
ver_offset = desc->ver_offset;
max_blocks = desc->max_blocks;
sig_length = desc->sig_length;
FNAND_BBM_DEBUG_I("FNandSearchBbt starts at 0x%x", start_block);
FNAND_BBM_DEBUG_I("Pages_per_block starts at %d", instance_p->nand_geometry[chip_addr].pages_per_block);
for (block = 0; block < max_blocks; block++)
{
pageoff = (start_block - block) *
instance_p->nand_geometry[chip_addr].pages_per_block;
FNAND_BBM_DEBUG_I("Block 0x%x", block);
FNAND_BBM_DEBUG_I("%s, Pageoff is 0x%x", __func__, pageoff);
ret = FNandReadPageOOb(instance_p, pageoff, buf, 0, sizeof(buf), chip_addr);
if (ret != FT_SUCCESS)
{
continue;
}
/*
* Check the Bad Block Table(BBT) signature
*/
for (offset = 0; offset < sig_length; offset++)
{
if (buf[offset + sig_offset] != desc->signature[offset])
{
break; /* Check the next blocks */
}
}
if (offset >= sig_length)
{
/*
* Bad Block Table(BBT) found
*/
desc->page_offset = pageoff;
desc->version = buf[ver_offset];
desc->valid = 1;
return FT_SUCCESS;
}
}
/*
* Bad Block Table(BBT) not found
*/
return FNAND_VALUE_ERROR;
}
/**
* @name:
* @msg:
* @return {*}
* @note:
* @param {FNand} *instance_p
* @param {u32} chip_addr
*/
FError FNandReadBbt(FNand *instance_p, u32 chip_addr)
{
u64 offset;
u8 buf[FNAND_MAX_BLOCKS >> FNAND_BBT_BLOCK_SHIFT];
FError status1;
FError status2;
FError ret;
u32 bbtlen;
FNandBbtDesc *desc_p = &instance_p->bbt_manager[chip_addr].bbt_desc;
FNandBbtDesc *mirror_desc_p = &instance_p->bbt_manager[chip_addr].bbt_mirror_desc;
bbtlen = instance_p->nand_geometry[chip_addr].num_blocks >> FNAND_BBT_BLOCK_SHIFT; /* 根据nand 介质信息获取的总块数除以4 的含义为每字节存储4个块信息 */
FNAND_BBM_DEBUG_I("FNandReadBbt ,bbtlen is %d", bbtlen);
status1 = FNandSearchBbt(instance_p, desc_p, chip_addr);
status2 = FNandSearchBbt(instance_p, mirror_desc_p, chip_addr);
if ((status1 != FT_SUCCESS) && (status2 != FT_SUCCESS))
{
FNAND_BBM_DEBUG_E("FNandReadBbt error status1 %x, status2 %x", status1, status2);
return FNAND_VALUE_FAILURE;
}
/*
* Bad Block Table found
*/
if (desc_p->valid && mirror_desc_p->valid)
{
if (desc_p->version > mirror_desc_p->version)
{
/*
* Valid BBT & Mirror BBT found
*/
FNAND_BBM_DEBUG_I("The desc_p->version > mirror_desc_p->version is not null , the page_offset is %d", desc_p->page_offset);
ret = FNandReadPage(instance_p, desc_p->page_offset, buf, 0, bbtlen, NULL, 0, 0, chip_addr);
if (ret != FT_SUCCESS)
{
FNAND_BBM_DEBUG_I("The desc_p->version > mirror_desc_p->version is not null , the FNandReadPage is error 0x%x", ret);
return ret;
}
/*
* Convert flash BBT to memory based BBT
*/
FNandConvertBbt(instance_p, &buf[0], chip_addr);
mirror_desc_p->version = desc_p->version;
/*
* Write the BBT to Mirror BBT location in flash
*/
ret = FNandWriteBbt(instance_p, mirror_desc_p,
desc_p, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
}
else if (desc_p->version < mirror_desc_p->version)
{
FNAND_BBM_DEBUG_I("desc_p->version < mirror_desc_p->version is not null, the page_offset is %d", mirror_desc_p->page_offset);
ret = FNandReadPage(instance_p, mirror_desc_p->page_offset, buf, 0, bbtlen, NULL, 0, 0, chip_addr);
if (ret != FT_SUCCESS)
{
FNAND_BBM_DEBUG_I("desc_p->version < mirror_desc_p->version is not null, the FNandReadPage is error 0x%x", ret);
return ret;
}
/*
* Convert flash BBT to memory based BBT
*/
FNandConvertBbt(instance_p, &buf[0], chip_addr);
desc_p->version = mirror_desc_p->version;
/*
* Write the BBT to Mirror BBT location in flash
*/
ret = FNandWriteBbt(instance_p, desc_p,
mirror_desc_p, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
}
else
{
/* Both are up-to-date */
FNAND_BBM_DEBUG_I("Both are up-to-date, the page_offset is %d", desc_p->page_offset);
ret = FNandReadPage(instance_p, desc_p->page_offset, buf, 0, bbtlen, NULL, 0, 0, chip_addr);
if (ret != FT_SUCCESS)
{
FNAND_BBM_DEBUG_I("Both are up-to-date, the FNandReadPage is error 0x%x", ret);
return ret;
}
/*
* Convert flash BBT to memory based BBT
*/
FNandConvertBbt(instance_p, &buf[0], chip_addr);
}
}
else if (desc_p->valid)
{
/*
* Valid Primary BBT found
*/
FNAND_BBM_DEBUG_I("Valid Primary BBT found is %d", desc_p->page_offset);
ret = FNandReadPage(instance_p, desc_p->page_offset, buf, 0, bbtlen, NULL, 0, 0, chip_addr);
if (ret != FT_SUCCESS)
{
FNAND_BBM_DEBUG_I("Valid Primary BBT found is error 0x%x", ret);
return ret;
}
/*
* Convert flash BBT to memory based BBT
*/
FNandConvertBbt(instance_p, &buf[0], chip_addr);
desc_p->version = mirror_desc_p->version;
/*
* Write the BBT to Mirror BBT location in flash
*/
ret = FNandWriteBbt(instance_p, mirror_desc_p,
desc_p, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
}
else
{
/*
* Valid Mirror BBT found
*/
FNAND_BBM_DEBUG_I("Valid Mirror BBT found is %d", mirror_desc_p->page_offset);
ret = FNandReadPage(instance_p, mirror_desc_p->page_offset, buf, 0, bbtlen, NULL, 0, 0, chip_addr);
if (ret != FT_SUCCESS)
{
FNAND_BBM_DEBUG_I("Valid Mirror BBT found is error 0x%x", ret);
return ret;
}
/*
* Convert flash BBT to memory based BBT
*/
FNandConvertBbt(instance_p, &buf[0], chip_addr);
desc_p->version = mirror_desc_p->version;
/*
* Write the BBT to Mirror BBT location in flash
*/
ret = FNandWriteBbt(instance_p, desc_p,
mirror_desc_p, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
}
return FT_SUCCESS;
}
static void FNandBbtDumpDebug(FNand *instance_p)
{
int i;
FNAND_BBM_DEBUG_W("/********************* Master bbt descriptor **********************/");
FNAND_BBM_DEBUG_I("page_offset 0x%x", instance_p->bbt_manager[0].bbt_desc.page_offset); /* Page offset where BBT resides */
FNAND_BBM_DEBUG_I("sig_offset 0x%x", instance_p->bbt_manager[0].bbt_desc.sig_offset); /* Signature offset in Spare area */
FNAND_BBM_DEBUG_I("ver_offset 0x%x", instance_p->bbt_manager[0].bbt_desc.ver_offset); /* Offset of BBT version */
FNAND_BBM_DEBUG_I("sig_length 0x%x", instance_p->bbt_manager[0].bbt_desc.sig_length); /* Length of the signature */
FNAND_BBM_DEBUG_I("max_blocks 0x%x", instance_p->bbt_manager[0].bbt_desc.max_blocks); /* Max blocks to search for BBT */
for (i = 0; i < 4; i++)
{
FNAND_BBM_DEBUG_I("Signature[%d] %c", i, instance_p->bbt_manager[0].bbt_desc.signature[i]);
}
FNAND_BBM_DEBUG_I("version 0x%x", instance_p->bbt_manager[0].bbt_desc.version); /* BBT version */
FNAND_BBM_DEBUG_I("valid 0x%x", instance_p->bbt_manager[0].bbt_desc.valid); /* BBT descriptor is valid or not */
FNAND_BBM_DEBUG_W("/********************* Mirror bbt descriptor **********************/");
FNAND_BBM_DEBUG_I("page_offset 0x%x", instance_p->bbt_manager[0].bbt_mirror_desc.page_offset); /* Page offset where BBT resides */
FNAND_BBM_DEBUG_I("sig_offset 0x%x", instance_p->bbt_manager[0].bbt_mirror_desc.sig_offset); /* Signature offset in Spare area */
FNAND_BBM_DEBUG_I("ver_offset 0x%x", instance_p->bbt_manager[0].bbt_mirror_desc.ver_offset); /* Offset of BBT version */
FNAND_BBM_DEBUG_I("sig_length 0x%x", instance_p->bbt_manager[0].bbt_mirror_desc.sig_length); /* Length of the signature */
FNAND_BBM_DEBUG_I("max_blocks 0x%x", instance_p->bbt_manager[0].bbt_mirror_desc.max_blocks); /* Max blocks to search for BBT */
for (i = 0; i < 4; i++)
{
FNAND_BBM_DEBUG_I("signature[%d] %c", i, instance_p->bbt_manager[0].bbt_mirror_desc.signature[i]);
}
FNAND_BBM_DEBUG_I("version 0x%x", instance_p->bbt_manager[0].bbt_mirror_desc.version); /* BBT version */
FNAND_BBM_DEBUG_I("valid 0x%x", instance_p->bbt_manager[0].bbt_mirror_desc.valid); /* BBT descriptor is valid or not */
FNAND_BBM_DEBUG_W("/********************* Bbt info **********************/");
FtDumpHexWord((const u32 *)instance_p->bbt_manager[0].bbt, instance_p->nand_geometry[0].num_blocks >>
FNAND_BBT_BLOCK_SHIFT);
}
/**
* @name: FNandScanBbt
* @msg: This function reads the Bad Block Table(BBT) if present in flash.
* @note:
* @param {FNand} *instance_p is the pointer to the FNand instance.
* @param {u32} chip_addr is chip address
* @return {FError}
*/
FError FNandScanBbt(FNand *instance_p, u32 chip_addr)
{
FError ret;
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
if (FNandReadBbt(instance_p, chip_addr) != FT_SUCCESS)
{
/*
* Create memory based Bad Block Table(BBT)
*/
FNandCreateBbt(instance_p, chip_addr);
/*
* Write the Bad Block Table(BBT) to the flash
*/
ret = FNandWriteBbt(instance_p,
&instance_p->bbt_manager[chip_addr].bbt_desc,
&instance_p->bbt_manager[chip_addr].bbt_mirror_desc, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
/*
* Write the Mirror Bad Block Table(BBT) to the flash
*/
ret = FNandWriteBbt(instance_p,
&instance_p->bbt_manager[chip_addr].bbt_mirror_desc,
&instance_p->bbt_manager[chip_addr].bbt_desc, chip_addr);
if (ret != FT_SUCCESS)
{
return ret;
}
/*
* Mark the blocks containing Bad Block Table(BBT) as Reserved
*/
FNandMarkBbt(instance_p, &instance_p->bbt_manager[chip_addr].bbt_desc, chip_addr);
FNandMarkBbt(instance_p, &instance_p->bbt_manager[chip_addr].bbt_mirror_desc, chip_addr);
FNAND_BBM_DEBUG_I("New bbt is ready");
FNandBbtDumpDebug(instance_p) ;
}
else
{
FNAND_BBM_DEBUG_I("Old bbt is valid");
FNandBbtDumpDebug(instance_p) ;
}
return FT_SUCCESS;
}
/**
* @name: FNandIsBlockBad
* @msg: This function checks whether a block is bad or not.
* @note:
* @param {FNand} *instance_p is the pointer to the FNand instance.
* @param {u32} block is the fnand flash block number
* @param {u32} chip_addr is chip address
* @return {FError} FT_SUCCESS if block is bad
*/
FError FNandIsBlockBad(FNand *instance_p, u32 block, u32 chip_addr)
{
u8 data;
u8 block_shift;
u8 BlockType;
u32 BlockOffset;
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
FASSERT_MSG(block < instance_p->nand_geometry[chip_addr].num_blocks, "block is %d,num_blocks is %d", block, instance_p->nand_geometry[chip_addr].num_blocks);
BlockOffset = block >> FNAND_BBT_BLOCK_SHIFT;
block_shift = FNAND_BBTBLOCKSHIFT(block);
data = instance_p->bbt_manager[chip_addr].bbt[BlockOffset]; /* Block information in BBT */
BlockType = (data >> block_shift) & FNAND_BLOCK_TYPE_MASK;
if (BlockType != FNAND_BLOCK_GOOD)
{
return FT_SUCCESS;
}
else
{
return FNAND_VALUE_FAILURE;
}
}
/**
* @name: FNandMarkBlockBad
* @msg: This function marks a block as bad in the RAM based Bad Block Table(BBT).
* @note:
* @param {FNand} *instance_p is the pointer to the FNand instance.
* @param {u32} block is the fnand flash block number
* @param {u32} chip_addr is chip address
* @return {*} FT_SUCCESS if successful
*/
FError FNandMarkBlockBad(FNand *instance_p, u32 block, u32 chip_addr)
{
u8 data;
u8 block_shift;
u32 block_offset;
u8 oldval;
u8 newval;
u32 Status;
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
FASSERT(block < instance_p->nand_geometry[chip_addr].num_blocks);
block_offset = block >> FNAND_BBT_BLOCK_SHIFT;
block_shift = FNAND_BBTBLOCKSHIFT(block);
data = instance_p->bbt_manager[chip_addr].bbt[block_offset]; /* Block information in BBT */
/*
* Mark the block as bad in the RAM based Bad Block Table
*/
oldval = data;
data &= ~(FNAND_BLOCK_TYPE_MASK << block_shift);
data |= (FNAND_BLOCK_BAD << block_shift);
newval = data;
instance_p->bbt_manager[chip_addr].bbt[block_offset] = data;
/*
* Update the Bad Block Table(BBT) in flash
*/
if (oldval != newval)
{
Status = FNandUpdateBbt(instance_p, chip_addr);
if (Status != FT_SUCCESS)
{
return Status;
}
}
return FT_SUCCESS;
}