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

883 lines
29 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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;
}