/******************************************************************************* *函数名称: NF_read *函数原型:int32 NF_read( __u32 sector_num, void *buffer, __u32 N ) *函数功能: 读取nand flash中的数据放入内存中。 *入口参数: sector_num flash中起始sector number * buffer 内存中的起始地址 * N 读取的sector个数(以sector为单位) *返 回 值: NF_OK 正确读取 * NF_OVERTIME_ERR 操作超时 * NF_ERROR 读取有误 *备 注: sector_num必须是某个page内的第一个sector. 不能跨块操作。 *******************************************************************************/ __s32 NF_read( __u32 sector_num, void *buffer, __u32 N ) { struct boot_physical_param para; __u8 oob_buf[MAX_PAGE_SIZE/NF_SECTOR_SIZE * OOB_BUF_SIZE_PER_SECTOR]; __u32 page_nr; __u32 scts_per_page = NF_PAGE_SIZE >> NF_SCT_SZ_WIDTH; __u32 residue; __u32 start_page; __u32 start_sct; __u32 i; __u32 blk_num; para.chip = 0; start_sct = nand_g_mod( sector_num, NF_BLOCK_SIZE >> NF_SCT_SZ_WIDTH, &blk_num ); para.block = blk_num; if( nand_g_mod( start_sct, NF_PAGE_SIZE >> NF_SCT_SZ_WIDTH, &start_page ) != 0 ) return NF_ERROR; para.oobbuf = oob_buf; residue = nand_g_mod( N, scts_per_page, &page_nr ); for( i = 0; i < page_nr; i++ ) { para.mainbuf = (__u8 *)buffer + NF_PAGE_SIZE * i; para.page = start_page + i; if( NAND_PhyRead( ¶ ) == FAIL ) return NF_ERROR; } if( residue != 0 ) { __u8 page_buf[MAX_PAGE_SIZE]; __u32 j; __u32 word_nr; __u32 *p; __u32 *q; para.mainbuf = page_buf; para.page = page_nr; if( NAND_PhyRead( ¶ ) == FAIL ) return NF_ERROR; for( j = 0, p = (__u32 *)( (__u32)buffer + NF_PAGE_SIZE * page_nr ), word_nr = residue * NF_SECTOR_SIZE >> 2, q = (__u32 *)page_buf; j < word_nr; j++ ) *p++ = *q++; }
/******************************************************************************* *函数名称: 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; }
/* ************************************************************************************************************************ * 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; }
/******************************************************************************* *函数名称: 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; }