?? nand_util_func.c
字號:
if( S_DONE == ret ) {
*p_row_addr = block_addr;
return S_DONE;
}
else {
block_addr += NUTL_PAGES_PER_BLOCK(nand_info);
}
}
return S_NO_GOOD_BLOCK_FOUND;
}
//------------------------------------------------------------------------------
// Block Erase
//------------------------------------------------------------------------------
STATUS_E NUTL_BlockErase(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,const uint32 row_addr
,NUTL_EraseFlag_E flag
) {
uint32 i;
uint32 block_addr;
uint32 timeout = c_timeout;
uint32 spare32[NAND_MAX_SPARE_SIZE_BYTE>>2];
STATUS_E ret=S_UNKNOWN_ERR;
// search block addr
block_addr = NUTL_RowAddrToBlockAddr(nand_info, row_addr);
// NUTL_ERASE -> good block will be erased, bad block will be skip.
// NUTL_FORCE_ERASE -> target block will be erased forcedly.
// NUTL_MARK_BAD_BLOCK -> target block will be erased forcedly.
if( (NUTL_ERASE == flag) &&
(S_DONE != (ret=NUTL_BadBlock_Check(nand_info, c_timeout, block_addr)))
) {
// bad block or fail to read spare to check bad block
return ret;
}
// erase block
if( S_DONE != (ret=CB_NAND_BLOCK_ERASE(nand_info, block_addr)) ) {
goto erase_fail;
}
timeout = c_timeout;
NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
if( 0 == timeout ) {
goto erase_fail;
}
else if( S_DONE != ret ) {
goto erase_fail;
}
if( NUTL_MARK_BAD_BLOCK == flag ) {
// goto mark as bad block
goto erase_fail;
}
return S_DONE;
erase_fail:
// mark bad block symbol
CB_NAND_BAD_BLOCK_SYMBOL_SET(nand_info, spare32);
// write bad block symbol in 1st and 2nd page of this block
for(i=0; i<2; i++) {
// program spare
CB_NAND_SPARE_PROGRAM(nand_info, c_timeout, block_addr+i, spare32);
timeout = c_timeout;
NFI_Wait( (S_IN_PROGRESS==CB_NAND_READ_STATUS(nand_info, c_timeout)), timeout);
}
if( S_UNKNOWN_ERR == ret ) {
return S_ERASE_FAILED;
}
else {
return ret;
}
}
//------------------------------------------------------------------------------
// Spare Area CheckSum Encode/Decode Related Function
//------------------------------------------------------------------------------
STATUS_E NUTL_SpareCheckSum_Encode(
const NAND_DeviceInfo_S *nand_info
,uint32 *p_spare32 /* MUST be 32bits alignment addr */
) {
uint32 page_size;
uint32 spare_size;
uint32 i;
uint16 checksum;
// uint8 *p_spare8 = (uint8 *)p_spare32;
uint16 *p_spare16 = (uint16 *)p_spare32;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
if( 512 < page_size ) {
//-------------------------------------------------------
// 2048 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 5 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)
// E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)
// E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)
// E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes 16bits checksum.
//
}
else {
//-------------------------------------------------------
// 512 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 2 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes (16bits) checksum.
//
}
// encode checksum
checksum = 0;
for(i=0; i<((spare_size>>1)-1); i++) {
checksum += p_spare16[i];
}
p_spare16[i] = checksum;
return S_DONE;
}
STATUS_E NUTL_SpareCheckSum_Decode(
const NAND_DeviceInfo_S *nand_info
,const uint32 *p_spare32 /* MUST be 32bits alignment addr */
) {
uint32 page_size;
uint32 spare_size;
uint32 i;
uint16 checksum;
// const uint8 *p_spare8 = (const uint8 *)p_spare32;
const uint16 *p_spare16 = (const uint16 *)p_spare32;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
if( 512 < page_size ) {
//-------------------------------------------------------
// 2048 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 5 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)
// E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)
// E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)
// E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes 16bits checksum.
//
}
else {
//-------------------------------------------------------
// 512 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 2 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes (16bits) checksum.
//
}
// decode checksum
checksum = 0;
for(i=0; i<((spare_size>>1)-1); i++) {
checksum += p_spare16[i];
}
if( checksum != p_spare16[(spare_size>>1)-1] ) {
return S_SPARE_CHKSUM_ERR;
}
return S_DONE;
}
//------------------------------------------------------------------------------
// Spare Area Compose/Decompose Related Function
//------------------------------------------------------------------------------
STATUS_E NUTL_SpareCompose(
const NAND_DeviceInfo_S *nand_info
,const uint32 ecc_parity_from_reg[4]
,uint32 *p_spare32 /* MUST be 32bits alignment addr */
) {
uint32 page_size;
uint32 spare_size;
uint32 i;
uint32 *p_ptr32 = p_spare32;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
// fill spare to 0xFF
for(i=0; i<(spare_size>>2); i++) {
p_spare32[i] = 0xFFFFFFFF;
}
// store ECC parity
if( 512 < page_size ) {
//-------------------------------------------------------
// 2048 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 5 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)
// E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)
// E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)
// E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes 16bits checksum.
//
p_ptr32 = p_spare32 + ((spare_size>>2)-5);
*p_ptr32++ = ecc_parity_from_reg[0];
*p_ptr32++ = ecc_parity_from_reg[1];
*p_ptr32++ = ecc_parity_from_reg[2];
*p_ptr32++ = ecc_parity_from_reg[3];
}
else {
//-------------------------------------------------------
// 512 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 2 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes (16bits) checksum.
//
p_ptr32 = p_spare32 + ((spare_size>>2)-2);
*p_ptr32++ = ecc_parity_from_reg[0];
}
// calculate spare area checksum
NUTL_SpareCheckSum_Encode(nand_info, p_spare32);
return S_DONE;
}
STATUS_E NUTL_SpareDecompose(
const NAND_DeviceInfo_S *nand_info
,const uint32 *p_spare32 /* MUST be 32bits alignment addr */
,uint32 ecc_parity_from_spare[4]
) {
uint32 page_size;
uint32 spare_size;
const uint32 *p_ptr32 = p_spare32;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
// calculate spare area checksum
if( S_DONE != NUTL_SpareCheckSum_Decode(nand_info, p_spare32) ) {
return S_SPARE_CHKSUM_ERR;
}
// store ECC parity
if( 512 < page_size ) {
//-------------------------------------------------------
// 2048 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 5 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)
// E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)
// E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)
// E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes 16bits checksum.
//
p_ptr32 = p_spare32 + ((spare_size>>2)-5);
ecc_parity_from_spare[0] = *p_ptr32++;
ecc_parity_from_spare[1] = *p_ptr32++;
ecc_parity_from_spare[2] = *p_ptr32++;
ecc_parity_from_spare[3] = *p_ptr32++;
}
else {
//-------------------------------------------------------
// 512 page size spare area definition
//-------------------------------------------------------
//
// |... PAGE DATA ...|...SPARE...|E0|NG|CHK|
//
// We store the ECC parity, next good block address and
// spare checksum in the last 2 DWORDs of spare data.
//
// E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)
// NG -> 2 bytes row addr point to next good block.
// CHK -> 2 bytes (16bits) checksum.
//
p_ptr32 = p_spare32 + ((spare_size>>2)-2);
ecc_parity_from_spare[0] = *p_ptr32++;
ecc_parity_from_spare[1] = 0;
ecc_parity_from_spare[2] = 0;
ecc_parity_from_spare[3] = 0;
}
return S_DONE;
}
//------------------------------------------------------------------------------
// ECC Correction
//------------------------------------------------------------------------------
STATUS_E NUTL_ECC_Correction(
const NAND_DeviceInfo_S *nand_info
,const uint32 ecc_block_size
,const uint32 ecc_parity_from_reg[4]
,const uint32 ecc_parity_from_spare[4]
,uint32 *p_data32 /* MUST be 32bits alignment addr */
) {
uint32 page_size;
uint32 spare_size;
uint32 addr_cycle;
uint32 i;
uint32 error_bit_address;
uint32 error_bit_offset;
uint8 *p_data8 = (uint8 *)p_data32;
uint8 update_data;
UnionData_U xor_ecc_parity[4];
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
addr_cycle = NUTL_ADDR_CYCLE(nand_info);
// XOR two ECC parity bit strings
// ecc_parity_from_reg[4]: current ECC parity generated by reading whole page
// ecc_parity_from_spare[4]: original ECC parity stored in spare area
xor_ecc_parity[0].d32 = (ecc_parity_from_reg[0]^ecc_parity_from_spare[0])&0x0FFF0FFF;
xor_ecc_parity[1].d32 = (ecc_parity_from_reg[1]^ecc_parity_from_spare[1])&0x0FFF0FFF;
xor_ecc_parity[2].d32 = (ecc_parity_from_reg[2]^ecc_parity_from_spare[2])&0x0FFF0FFF;
xor_ecc_parity[3].d32 = (ecc_parity_from_reg[3]^ecc_parity_from_spare[3])&0x0FFF0FFF;
// compare ECC parity between reg and spare
for(i=0; i<(page_size/ecc_block_size); i++) {
if( 0 != xor_ecc_parity[i].d32 ) {
if( 0x0FFF == ((xor_ecc_parity[i].d16[0]^xor_ecc_parity[i].d16[1])&0x0FFF) ) {
// one-bit correctable error
error_bit_address = xor_ecc_parity[i].d16[1]&(~xor_ecc_parity[i].d16[0]);
error_bit_offset = ecc_block_size*i + (error_bit_address>>3);
update_data = p_data8[error_bit_offset];
update_data = update_data^(1<<(uint8)(error_bit_address&0x0007));
p_data8[error_bit_offset] = update_data;
return S_ECC_1BIT_CORRECT;
}
else {
return S_ECC_2BITS_ERR;
}
}
}
return S_DONE;
}
//------------------------------------------------------------------------------
// Page Read
//------------------------------------------------------------------------------
STATUS_E NUTL_PageRead(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,const uint32 row_addr
,uint32 *p_data32 /* MUST be 32bits alignment addr */
,uint32 *p_spare32 /* MUST be 32bits alignment addr */
,uint32 ecc_parity_from_reg[4]
,uint32 ecc_parity_from_spare[4]
,NUTL_ReadFlag_E flag
) {
uint32 page_size;
uint32 spare_size;
uint32 *p_ecc_parity_from_reg;
uint32 *p_ecc_parity_from_spare;
uint32 *p_page;
uint32 *p_spare;
STATUS_E ret=S_UNKNOWN_ERR;
uint32 i;
bool bIsEmptyPage = TRUE;
spare_size = NUTL_SPARE_SIZE(nand_info);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -