/******************************************************************************* *函数名称: NAND_BadBlockScan *函数原型:bad_blcok_scan(const boot_nand_para_t *nand_param) *函数功能: 标记blk_num指定的块为坏块。 *入口参数: nand_param *返 回 值: >0 编程操作成功 * -1 编程操作失败 *备 注: *******************************************************************************/ __s32 NAND_BadBlockScan(const boot_nand_para_t *nand_param) { boot_flash_info_t info; struct boot_physical_param para; __s32 i, j, k; __u32 page_with_bad_block, page_per_block; __s32 page_index[4]; __u32 bad_block_cnt[8]; __u32 bad_block_num = 0; __u32 good_block_num = 0; __s32 good_block_ratio = -1; __u32 chip; __u8 oob_buf[OOB_BUF_SIZE]; __u8* page_buf; __u32 die_skip_flag = (nand_param->OperationOpt)&(0x1<<11); __u32 block_cnt_of_die = (nand_param->BlkCntPerDie); for(i=0; i<8; i++) bad_block_cnt[i] = 0; NAND_Print("Ready to scan bad blocks.\n"); // get nand info to cal NAND_Print("nfb phy init ok.\n"); if( NAND_GetFlashInfo( &info ) ) { NAND_Print("get flash info failed.\n"); return -1; } NAND_Print("Succeed in getting flash info.\n"); //cal nand parameters //page_buf = (__u8*)(BAD_BLK_SCAN_BUF_ADR); page_buf = (__u8*)wBoot_malloc(32 * 1024); if(!page_buf) { NAND_Print("malloc memory for page buf fail\n"); return -1; } page_with_bad_block = info.pagewithbadflag; page_per_block = info.blocksize/info.pagesize; //read the first, second, last, last-1 page for check bad blocks page_index[0] = 0; page_index[1] = 0xEE; page_index[2] = 0xEE; page_index[3] = 0xEE; switch(page_with_bad_block & 0x03) { case 0x00: //the bad block flag is in the first page, same as the logical information, just read 1 page is ok break; case 0x01: //the bad block flag is in the first page or the second page, need read the first page and the second page page_index[1] = 1; break; case 0x02: //the bad block flag is in the last page, need read the first page and the last page page_index[1] = page_per_block - 1; break; case 0x03: //the bad block flag is in the last 2 page, so, need read the first page, the last page and the last-1 page page_index[1] = page_per_block - 1; page_index[2] = page_per_block - 2; break; } //scan bad blocks for( i = 0; i < info.chip_cnt; i++ ){ chip = _cal_real_chip( i, nand_param->ChipConnectInfo ); NAND_Print("scan CE %u\n", chip); bad_block_cnt[chip] = 0; for( j = 0; j < info.blk_cnt_per_chip; j++ ) { para.chip = chip; if(!die_skip_flag) para.block = j; else para.block = j%block_cnt_of_die + 2*block_cnt_of_die*(j/block_cnt_of_die); para.mainbuf = page_buf; para.oobbuf = oob_buf; for(k = 0; k<4; k++) { // read pages for check para.page = page_index[k]; if(para.page == 0xEE) continue; NAND_PhyRead(¶ ); // find bad blocks if(oob_buf[0] != 0xff) { NAND_Print("find defined bad block in chip %u, block %u.\n", i, j); bad_block_cnt[chip]++; break; } } } } // cal bad block num if(info.chip_cnt == 0x1) //for one CE { if(nand_param->ChipConnectInfo == 0x1) { bad_block_num = bad_block_cnt[0]<<1; } else { NAND_Print("chip connect parameter %x error \n", nand_param->ChipConnectInfo); wBoot_free(page_buf); return -1; } } else if(info.chip_cnt == 2) //for two CE { if(nand_param->ChipConnectInfo == 0x3) { bad_block_num = (bad_block_cnt[0] + bad_block_cnt[1])<<1; } else if(nand_param->ChipConnectInfo == 0x5) { bad_block_num = (bad_block_cnt[0] + bad_block_cnt[2])<<1; } else if(nand_param->ChipConnectInfo == 0x81) { bad_block_num = (bad_block_cnt[0] + bad_block_cnt[7])<<1; } else { NAND_Print("chip connect parameter %x error \n", nand_param->ChipConnectInfo); wBoot_free(page_buf); return -1; } } else if(info.chip_cnt == 4) //for four CE { if(nand_param->ChipConnectInfo == 0xf) { bad_block_num = max_badblk((bad_block_cnt[0] + bad_block_cnt[2]),(bad_block_cnt[1] + bad_block_cnt[3]))<<1; } else if(nand_param->ChipConnectInfo == 0x55) { bad_block_num = max_badblk((bad_block_cnt[0] + bad_block_cnt[2]),(bad_block_cnt[4] + bad_block_cnt[6]))<<1; } else { NAND_Print("chip connect parameter %x error \n",nand_param->ChipConnectInfo); wBoot_free(page_buf); return -1; } } else if(info.chip_cnt == 8) //for eight CE { if(nand_param->ChipConnectInfo == 0xff) { bad_block_num = max_badblk((bad_block_cnt[0] + bad_block_cnt[2]),(bad_block_cnt[1] + bad_block_cnt[3])); bad_block_num = 2*max_badblk(bad_block_num, max_badblk((bad_block_cnt[4] + bad_block_cnt[6]),(bad_block_cnt[5] + bad_block_cnt[7]))); } else { NAND_Print("chip connect parameter %x error \n",nand_param->ChipConnectInfo); wBoot_free(page_buf); return -1; } } else { NAND_Print("chip cnt parameter %x error \n",nand_param->ChipCnt); wBoot_free(page_buf); return -1; } //cal good block num required per 1024 blocks good_block_num = (1024*(info.blk_cnt_per_chip - bad_block_num))/info.blk_cnt_per_chip -114; for(i=0; i<info.chip_cnt; i++) { chip = _cal_real_chip( i, nand_param->ChipConnectInfo ); NAND_Print(" %d bad blocks in CE %u \n", bad_block_cnt[chip], chip); } NAND_Print("cal bad block num is %u \n", bad_block_num); NAND_Print("cal good block num is %u \n", good_block_num); //cal good block ratio for(i=0; i<10; i++) { if(good_block_num >= (nand_param->good_block_ratio - 32*i)) { good_block_ratio = (nand_param->good_block_ratio - 32*i); NAND_Print("good block ratio is %u \n",good_block_ratio); break; } } wBoot_free(page_buf); return good_block_ratio; }
/******************************************************************************* *函数名称: mark_bad_block *函数原型:mark_bad_block( __u32 chip_num, __u32 blk_num ) *函数功能: 标记blk_num指定的块为坏块。 *入口参数: chip_num chip number blk_num 块号 *返 回 值: 0 编程操作成功 * other 编程操作失败 *备 注: *******************************************************************************/ static __s32 mark_bad_block( __u32 chip_num, __u32 blk_num) { boot_flash_info_t info; struct boot_physical_param para; __u8 oob_buf[OOB_BUF_SIZE]; __u8* page_buf; __s32 page_index[4]; __u32 page_with_bad_block, page_per_block; __u32 i; __s32 mark_err_flag = -1; if( NAND_GetFlashInfo( &info )) { NAND_Print("get flash info failed.\n"); return -1; } //cal nand parameters //page_buf = (__u8*)(MARK_BAD_BLK_BUF_ADR); page_buf = (__u8*)wBoot_malloc(32 * 1024); if(!page_buf) { NAND_Print("malloc memory for page buf fail\n"); return -1; } page_with_bad_block = info.pagewithbadflag; page_per_block = info.blocksize/info.pagesize; //read the first, second, last, last-1 page for check bad blocks page_index[0] = 0; page_index[1] = 0xEE; page_index[2] = 0xEE; page_index[3] = 0xEE; switch(page_with_bad_block & 0x03) { case 0x00: //the bad block flag is in the first page, same as the logical information, just read 1 page is ok break; case 0x01: //the bad block flag is in the first page or the second page, need read the first page and the second page page_index[1] = 1; break; case 0x02: //the bad block flag is in the last page, need read the first page and the last page page_index[1] = page_per_block - 1; break; case 0x03: //the bad block flag is in the last 2 page, so, need read the first page, the last page and the last-1 page page_index[1] = page_per_block - 1; page_index[2] = page_per_block - 2; break; } for(i =0; i<4; i++) { oob_buf[0] = 0x0; oob_buf[1] = 0x1; oob_buf[2] = 0x2; oob_buf[3] = 0x3; oob_buf[4] = 0x89; oob_buf[5] = 0xab; oob_buf[6] = 0xcd; oob_buf[7] = 0xef; para.chip = chip_num; para.block = blk_num; para.page = page_index[i]; para.mainbuf = page_buf; para.oobbuf = oob_buf; if(para.page == 0xEE) continue; NAND_PhyWrite( ¶ ); NAND_PhyRead( ¶ ); if(oob_buf[0] !=0xff) mark_err_flag = 0; } wBoot_free(page_buf); return mark_err_flag; }
/* ************************************************************************************************************************ * NAND_EraseChip * *Description: Erase chip, only erase the all 0x0 blocks * *Arguments : connecnt info. * *Return : = 0 OK; * other Fail. ************************************************************************************************************************ */ __s32 NAND_EraseChip( const boot_nand_para_t *nand_param) { boot_flash_info_t info; struct boot_physical_param para_read; __s32 i,j,k,m; __s32 ret; __s32 cnt0, cnt1; __s32 mark_err_flag; __u32 bad_block_flag; __u32 page_with_bad_block, page_size, page_per_block; __s32 page_index[4]; __u32 chip; __u8 oob_buf_read[OOB_BUF_SIZE]; __u8* page_buf_read; __s32 error_flag = 0; __s32 block_start; __u32 die_skip_flag = (nand_param->OperationOpt)&(0x1<<11); __u32 block_cnt_of_die = (nand_param->BlkCntPerDie); bad_block_scan_flag = 0; page_buf_read = (__u8*)wBoot_malloc(32 * 1024); if(!page_buf_read) { NAND_Print("malloc memory for page read fail\n"); return -1; } NAND_Print("Ready to erase chip.\n"); // get nand info to cal NAND_Print("nfb phy init ok.\n"); if( NAND_GetFlashInfo( &info ) != 0 ) { NAND_Print("get flash info failed.\n"); wBoot_free(page_buf_read); return -1; } NAND_Print("Succeed in getting flash info.\n"); page_size = 512*info.pagesize; page_with_bad_block = info.pagewithbadflag; page_per_block = info.blocksize/info.pagesize; NAND_Print("page size:%x, block size: %x, bad block position: %x.\n",page_size, page_per_block,page_with_bad_block); page_index[0] = 0; page_index[1] = 0xEE; page_index[2] = 0xEE; page_index[3] = 0xEE; switch(page_with_bad_block & 0x03) { case 0x00: //the bad block flag is in the first page, same as the logical information, just read 1 page is ok break; case 0x01: //the bad block flag is in the first page or the second page, need read the first page and the second page page_index[1] = 1; break; case 0x02: //the bad block flag is in the last page, need read the first page and the last page page_index[1] = page_per_block - 1; break; case 0x03: //the bad block flag is in the last 2 page, so, need read the first page, the last page and the last-1 page page_index[1] = page_per_block - 1; page_index[2] = page_per_block - 2; break; } NAND_Print("chip_cnt = %x, chip_connect = %x, rb_cnt = %x, rb_connect = %x, good_block_ratio =%x \n",nand_param->ChipCnt,nand_param->ChipConnectInfo,nand_param->RbCnt,nand_param->RbConnectInfo,nand_param->good_block_ratio); for( i = 0; i < nand_param->ChipCnt; i++ ) { //select chip chip = _cal_real_chip( i, nand_param->ChipConnectInfo ); NAND_Print("erase chip %u \n", chip); //scan for bad blocks, only erase good block, all 0x00 blocks is defined bad blocks if(i == 0) { block_start = 7; } else { block_start = 0; } for( j = block_start; j < info.blk_cnt_per_chip; j++ ) { para_read.chip = chip; if(!die_skip_flag) para_read.block = j; else para_read.block = j%block_cnt_of_die + 2*block_cnt_of_die*(j/block_cnt_of_die); para_read.mainbuf = page_buf_read; para_read.oobbuf = oob_buf_read; bad_block_flag = 0; for(k = 0; k<4; k++) { cnt0 =0; cnt1 =0; para_read.page = page_index[k]; if( para_read.page== 0xEE) break; ret = NAND_PhyRead(& para_read ); //check the current block is a all 0x00 block #if 0 for(m=0; m<8; m++) //check user data, 8 byte { if(oob_buf_read[m] == ((__u8)0x0) ) cnt1++; else break; } for(m=0; m<page_size; m++) //check main data { if(page_buf_read[m] == ((__u8)0x0) ) cnt0++; else break; } if((cnt0 == page_size)&&(cnt1 == 8)) { bad_block_flag = 1; NAND_Print("find a all 0x00 block %u\n", j); break; } #endif if(oob_buf_read[0] == 0x0) { bad_block_flag = 1; NAND_Print("find a bad block %u\n", j); break; } } if(bad_block_flag) continue; ret = NAND_PhyErase( ¶_read ); if( ret != 0 ) { NAND_Print("erasing block %u failed.\n", j ); mark_err_flag = mark_bad_block( i, j ); if( mark_err_flag!= 0 ) { error_flag++; NAND_Print("error in marking bad block flag in chip %u, block %u, mark error flag %u.\n", i, j, mark_err_flag); } } } } NAND_Print("has cleared the chip.\n"); if(error_flag) NAND_Print("the nand is Bad.\n"); else NAND_Print("the nand is OK.\n"); wBoot_free(page_buf_read); return 0; }
/* ************************************************************************************************************ * * function * * 函数名称: * * 参数列表: * * 返回值 : * * 说明 : * * ************************************************************************************************************ */ __s32 NF_open( void ) { __u32 blk_for_boot1; struct boot_flash_info info; if( NAND_PhyInit( ) == FAIL ) return NF_ERROR; if( NAND_GetFlashInfo( &info ) == FAIL ) { goto error; } page_with_bad_block = info.pagewithbadflag; NF_BLOCK_SIZE = info.blocksize * NF_SECTOR_SIZE; switch( NF_BLOCK_SIZE ) { case SZ_16K : NF_BLK_SZ_WIDTH = 14; blk_for_boot1 = BLKS_FOR_BOOT1_IN_16K_BLK_NF; break; case SZ_32K : NF_BLK_SZ_WIDTH = 15; blk_for_boot1 = BLKS_FOR_BOOT1_IN_32K_BLK_NF; break; case SZ_128K : NF_BLK_SZ_WIDTH = 17; blk_for_boot1 = BLKS_FOR_BOOT1_IN_128K_BLK_NF; break; case SZ_256K : NF_BLK_SZ_WIDTH = 18; blk_for_boot1 = BLKS_FOR_BOOT1_IN_256K_BLK_NF; break; case SZ_512K : NF_BLK_SZ_WIDTH = 19; blk_for_boot1 = BLKS_FOR_BOOT1_IN_512K_BLK_NF; break; case SZ_1M : NF_BLK_SZ_WIDTH = 20; blk_for_boot1 = BLKS_FOR_BOOT1_IN_1M_BLK_NF; break; case SZ_2M : NF_BLK_SZ_WIDTH = 21; blk_for_boot1 = BLKS_FOR_BOOT1_IN_2M_BLK_NF; break; case SZ_4M : NF_BLK_SZ_WIDTH = 22; blk_for_boot1 = BLKS_FOR_BOOT1_IN_4M_BLK_NF; break; default : goto error; } BOOT1_LAST_BLK_NUM = BOOT1_START_BLK_NUM + blk_for_boot1 - 1; NF_PAGE_SIZE = info.pagesize * NF_SECTOR_SIZE; switch( NF_PAGE_SIZE ) { case SZ_512 : NF_PG_SZ_WIDTH = 9; break; case SZ_2K : NF_PG_SZ_WIDTH = 11; break; case SZ_4K : NF_PG_SZ_WIDTH = 12; break; case SZ_8K : NF_PG_SZ_WIDTH = 13; break; case SZ_16K : NF_PG_SZ_WIDTH = 14; break; default : goto error; } return NF_OK; error: NAND_PhyExit( ); return NF_ERROR; }