📄 nand_util_func.c
字号:
page_size = NUTL_PAGE_SIZE(nand_info);
// initialize internal buffer pointer
p_ecc_parity_from_reg = g_NUTL_PageRead_Var.m_ecc_parity_from_reg;
p_ecc_parity_from_spare = g_NUTL_PageRead_Var.m_ecc_parity_from_spare;
if( 512 < page_size ) {
p_page = &(g_NUTL_PageRead_Var.m_PageBuf.m_2048.m_pagespare32.m_data[0]);
p_spare = &(g_NUTL_PageRead_Var.m_PageBuf.m_2048.m_pagespare32.m_spare[0]);
}
else {
p_page = &(g_NUTL_PageRead_Var.m_PageBuf.m_512.m_pagespare32.m_data[0]);
p_spare = &(g_NUTL_PageRead_Var.m_PageBuf.m_512.m_pagespare32.m_spare[0]);
}
// reset ecc parity and spare
for(i=0; i<4; i++) {
p_ecc_parity_from_reg[i] = 0xAAAAAAAA;
p_ecc_parity_from_spare[i] = 0xAAAAAAAA;
}
for(i=0; i<(spare_size>>2); i++) {
p_spare[i] = 0xAAAAAAAA;
}
if( NUTL_READ_PAGE_WITH_ECC == flag ) {
if( S_DONE != (ret=NUTL_BadBlock_Check(nand_info, c_timeout, row_addr)) ) {
// bad block, skip reading
return S_BAD_BLOCK;
}
}
// read page
if( NUTL_READ_SPARE_ONLY != flag ) {
if( S_DONE != (ret=CB_NAND_PAGE_READ(nand_info, c_timeout, row_addr, p_data32, p_ecc_parity_from_reg)) ) {
goto end;
}
}
// read spare
if( NUTL_READ_PAGE_ONLY != flag ) {
if( S_DONE != (ret=CB_NAND_SPARE_READ(nand_info, c_timeout, row_addr, p_spare)) ) {
goto end;
}
}
if( NUTL_READ_PAGE_WITH_ECC==flag || NUTL_VERIFY_AFTER_PROGRAM==flag ) {
// check if all the page data are 0xFF
for(i=0; bIsEmptyPage && i<(page_size/512); i++) {
if( 0xAAAAAAAA!=p_ecc_parity_from_reg[i] && 0!=p_ecc_parity_from_reg[i] ) {
bIsEmptyPage = FALSE;
break;
}
}
// check if all the spare data are 0xFF
for(i=0; bIsEmptyPage && i<(spare_size>>2); i++) {
if( 0xFFFFFFFF != p_spare[i] ) {
bIsEmptyPage = FALSE;
break;
}
}
// if it's erased page, skip spare checksum and ECC correction
if( NUTL_VERIFY_AFTER_PROGRAM==flag || !bIsEmptyPage ) {
// decompose spare area
if( S_DONE != (ret=NUTL_SpareDecompose(nand_info, p_spare, p_ecc_parity_from_spare)) ) {
goto end;
}
// ECC correction
if( S_DONE != (ret=NUTL_ECC_Correction(nand_info, 512, p_ecc_parity_from_reg, p_ecc_parity_from_spare, p_data32)) ) {
goto end;
}
}
}
ret = S_DONE;
end:
// assign return value
if( NULL != p_spare32 ) {
for(i=0; i<(spare_size>>2); i++) {
p_spare32[i] = p_spare[i];
}
}
if( NULL != ecc_parity_from_reg ) {
ecc_parity_from_reg[0] = p_ecc_parity_from_reg[0];
ecc_parity_from_reg[1] = p_ecc_parity_from_reg[1];
ecc_parity_from_reg[2] = p_ecc_parity_from_reg[2];
ecc_parity_from_reg[3] = p_ecc_parity_from_reg[3];
}
if( NULL != ecc_parity_from_spare ) {
ecc_parity_from_spare[0] = p_ecc_parity_from_spare[0];
ecc_parity_from_spare[1] = p_ecc_parity_from_spare[1];
ecc_parity_from_spare[2] = p_ecc_parity_from_spare[2];
ecc_parity_from_spare[3] = p_ecc_parity_from_spare[3];
}
return ret;
}
//------------------------------------------------------------------------------
// Page Program Related Callback Function
//------------------------------------------------------------------------------
STATUS_E NUTL_PageProgram(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,const uint32 row_addr
,const 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]
) {
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;
uint32 timeout = c_timeout;
spare_size = NUTL_SPARE_SIZE(nand_info);
page_size = NUTL_PAGE_SIZE(nand_info);
// initialize internal buffer pointer
p_ecc_parity_from_reg = g_NUTL_PageProgram_Var.m_ecc_parity_from_reg;
p_ecc_parity_from_spare = g_NUTL_PageProgram_Var.m_ecc_parity_from_spare;
if( 512 < page_size ) {
p_page = &(g_NUTL_PageProgram_Var.m_PageBuf.m_2048.m_pagespare32.m_data[0]);
p_spare = &(g_NUTL_PageProgram_Var.m_PageBuf.m_2048.m_pagespare32.m_spare[0]);
}
else {
p_page = &(g_NUTL_PageProgram_Var.m_PageBuf.m_512.m_pagespare32.m_data[0]);
p_spare = &(g_NUTL_PageProgram_Var.m_PageBuf.m_512.m_pagespare32.m_spare[0]);
}
// reset ecc parity and spare
for(i=0; i<4; i++) {
p_ecc_parity_from_reg[i] = 0xAAAAAAAA;
p_ecc_parity_from_spare[i] = 0xAAAAAAAA;
}
for(i=0; i<(spare_size>>2); i++) {
p_spare[i] = 0xAAAAAAAA;
}
// program page
if( S_DONE != (ret=CB_NAND_PAGE_PROGRAM(nand_info, c_timeout, row_addr, p_data32, p_ecc_parity_from_reg)) ) {
goto end;
}
timeout = c_timeout;
NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
if( 0 == timeout ) {
ret = S_TIMEOUT;
goto end;
}
else if( S_UNKNOWN_ERR == ret ) {
ret = S_PGM_FAILED;
goto end;
}
else if( S_DONE != ret ) {
goto end;
}
// compose spare area
NUTL_SpareCompose(nand_info, p_ecc_parity_from_reg, p_spare);
// program spare area
if( S_DONE != (ret=CB_NAND_SPARE_PROGRAM(nand_info, c_timeout, row_addr, p_spare)) ) {
return ret;
}
timeout = c_timeout;
NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
if( 0 == timeout ) {
ret = S_TIMEOUT;
goto end;
}
else if( S_UNKNOWN_ERR == ret ) {
ret = S_PGM_FAILED;
goto end;
}
else if( S_DONE != ret ) {
goto end;
}
// read back page to verify
if( S_DONE != (ret=NUTL_PageRead(nand_info, c_timeout, row_addr, p_page, p_spare, NULL, p_ecc_parity_from_spare, NUTL_VERIFY_AFTER_PROGRAM)) ) {
goto end;
}
ret = S_DONE;
end:
// assign return value
if( NULL != p_spare32 ) {
for(i=0; i<(spare_size>>2); i++) {
p_spare32[i] = p_spare[i];
}
}
if( NULL != ecc_parity_from_reg ) {
ecc_parity_from_reg[0] = p_ecc_parity_from_reg[0];
ecc_parity_from_reg[1] = p_ecc_parity_from_reg[1];
ecc_parity_from_reg[2] = p_ecc_parity_from_reg[2];
ecc_parity_from_reg[3] = p_ecc_parity_from_reg[3];
}
if( NULL != ecc_parity_from_spare ) {
ecc_parity_from_spare[0] = p_ecc_parity_from_spare[0];
ecc_parity_from_spare[1] = p_ecc_parity_from_spare[1];
ecc_parity_from_spare[2] = p_ecc_parity_from_spare[2];
ecc_parity_from_spare[3] = p_ecc_parity_from_spare[3];
}
return ret;
}
//------------------------------------------------------------------------------
// CopyBack
//------------------------------------------------------------------------------
STATUS_E NUTL_CopyBack(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,const uint32 src_row_addr
,const uint32 dest_row_addr
) {
uint32 page_size;
uint32 spare_size;
uint32 *p_ecc_parity_from_src_spare;
uint32 *p_ecc_parity_from_dest_spare;
uint32 *p_page;
uint32 *p_spare;
STATUS_E ret=S_UNKNOWN_ERR;
uint32 i;
uint32 timeout = c_timeout;
spare_size = NUTL_SPARE_SIZE(nand_info);
page_size = NUTL_PAGE_SIZE(nand_info);
// initialize internal buffer pointer
p_ecc_parity_from_src_spare = g_NUTL_CopyBack_Var.m_ecc_parity_from_reg;
p_ecc_parity_from_dest_spare = g_NUTL_CopyBack_Var.m_ecc_parity_from_spare;
if( 512 < page_size ) {
p_page = &(g_NUTL_CopyBack_Var.m_PageBuf.m_2048.m_pagespare32.m_data[0]);
p_spare = &(g_NUTL_CopyBack_Var.m_PageBuf.m_2048.m_pagespare32.m_spare[0]);
}
else {
p_page = &(g_NUTL_CopyBack_Var.m_PageBuf.m_512.m_pagespare32.m_data[0]);
p_spare = &(g_NUTL_CopyBack_Var.m_PageBuf.m_512.m_pagespare32.m_spare[0]);
}
// reset ecc parity and spare
for(i=0; i<4; i++) {
p_ecc_parity_from_src_spare[i] = 0xAAAAAAAA;
p_ecc_parity_from_dest_spare[i] = 0xAAAAAAAA;
}
for(i=0; i<(spare_size>>2); i++) {
p_spare[i] = 0xAAAAAAAA;
}
// if flash support H/W page copyback function
if( NULL != FP_CB_NAND_COPYBACK(nand_info) ) {
// check if src_row_addr and dest_row_addr are in the same memory plane
if( 0 == ((src_row_addr^dest_row_addr)&nand_info->m_dev->m_hw_info.m_copyback_plane_rowaddr_mask) ) {
if( S_DONE != (ret=CB_NAND_COPYBACK(nand_info, c_timeout, src_row_addr, dest_row_addr)) ) {
return ret;
}
timeout = c_timeout;
NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
if( 0 == timeout ) {
return S_TIMEOUT;
}
else if( S_UNKNOWN_ERR == ret ) {
return S_PGM_FAILED;
}
else if( S_DONE != ret ) {
return ret;
}
// read src spare
if( S_DONE != (ret=CB_NAND_SPARE_READ(nand_info, c_timeout, src_row_addr, p_spare)) ) {
return ret;
}
if( S_DONE != (ret=NUTL_SpareDecompose(nand_info, p_spare, p_ecc_parity_from_src_spare)) ) {
return ret;
}
// read dest spare
if( S_DONE != (ret=CB_NAND_SPARE_READ(nand_info, c_timeout, dest_row_addr, p_spare)) ) {
return ret;
}
if( S_DONE != (ret=NUTL_SpareDecompose(nand_info, p_spare, p_ecc_parity_from_dest_spare)) ) {
return ret;
}
// compare src and dest ecc parity
for(i=0; i<4; i++) {
if( p_ecc_parity_from_src_spare[i] != p_ecc_parity_from_dest_spare[i] ) {
return S_HW_COPYBACK_ERR;
}
}
return S_DONE;
}
}
// otherwise, use software to simulate
// read from source page
ret = NUTL_PageRead(nand_info, c_timeout, src_row_addr, p_page, NULL, NULL, p_ecc_parity_from_src_spare, NUTL_READ_PAGE_WITH_ECC);
if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
return ret;
}
// program to destination page
ret = NUTL_PageProgram(nand_info, c_timeout, dest_row_addr, p_page, NULL, NULL, p_ecc_parity_from_dest_spare);
if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
return ret;
}
return S_DONE;
}
//------------------------------------------------------------------------------
// Block Replacement
//------------------------------------------------------------------------------
STATUS_E NUTL_BlockReplacement(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,const uint32 src_row_addr /* any row_addr within source block */
,const uint32 dest_row_addr /* any row_addr within destination block */
,const uint32 err_page_index /* page index within block, 1st page index is 0 */
,const uint32 *p_err_page_data32 /* MUST be 32bits alignment addr */
) {
uint32 i;
uint32 src_block_addr;
uint32 dest_block_addr;
uint32 max_block_addr;
STATUS_E ret=S_UNKNOWN_ERR;
max_block_addr = (NUTL_TOTAL_BLOCK_COUNT(g_pNandInfo)-1)*NUTL_PAGES_PER_BLOCK(g_pNandInfo);
// check if err_page_index is valid
if( err_page_index >= nand_info->m_dev->m_hw_info.m_pages_per_block ) {
return S_INVALID_PAGE_INDEX;
}
// search block addr
src_block_addr = NUTL_RowAddrToBlockAddr(nand_info, src_row_addr);
dest_block_addr = NUTL_RowAddrToBlockAddr(nand_info, dest_row_addr);
// check if src and dest block_addr is in valid range
if( max_block_addr<src_block_addr || max_block_addr<dest_block_addr ) {
return S_INVALID_BEGIN_ADDR;
}
// erase dest block first
if( S_DONE != (ret=NUTL_BlockErase(nand_info, c_timeout, dest_block_addr, NUTL_ERASE)) ) {
return ret;
}
// copy healthy pages to dest block
for(i=0; i<err_page_index; i++) {
ret = NUTL_CopyBack(nand_info, c_timeout, src_block_addr+i, dest_block_addr+i);
if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
goto error;
}
}
// program the error page to dest block again
ret = NUTL_PageProgram(nand_info, c_timeout, dest_block_addr+err_page_index, p_err_page_data32, NULL, NULL, NULL);
if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
goto error;
}
goto end;
error:
// mark as bad block
NUTL_BlockErase(nand_info, c_timeout, dest_block_addr, NUTL_MARK_BAD_BLOCK);
end:
return ret;
}
//------------------------------------------------------------------------------
// Range Validation
//------------------------------------------------------------------------------
STATUS_E NUTL_CheckRange(
const NAND_DeviceInfo_S *nand_info
,const uint32 absolute_addr
,const uint32 length
) {
uint32 total_size;
total_size = NUTL_TOTAL_SIZE(g_pNandInfo);
// check base addr
if( absolute_addr >= total_size ) {
return S_INVALID_BEGIN_ADDR;
}
// check length
if( 0==length || (absolute_addr+length)>total_size ) {
return S_INVALID_RANGE;
}
return S_DONE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -