883 lines
29 KiB
C
883 lines
29 KiB
C
/*
|
||
* 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;
|
||
} |