void get_partition_badblock(struct ptentry *ptn, struct nand_spec *spec) { unsigned i = 0; unsigned block_start = 0; unsigned block_end= 0; unsigned bad_flag; unsigned bad_block_num =0; unsigned ret; block_start = (ptn->start + spec->blocksize- 1) / spec->blocksize; block_end = (ptn->start + ptn->length + spec->blocksize - 1) / spec->blocksize; for (i = block_start; i < block_end; i++) { ret = nand_isbad(i, &bad_flag); if(ret) { cprintf("ERROR: check flash bad failed\n"); return; } if(NANDC_BAD_BLOCK == bad_flag) { cprintf("\nBad block found, partition: %s, address: 0x%x", ptn->name, i * spec->blocksize); bad_block_num++; } } if(0 == bad_block_num) { cprintf("\nNo bad block found, partition: %s", ptn->name); } return; }
/** * 作用:nandc模块按分区名和分区相对偏移来确定此块是不是坏块 * * 参数: * @partition_name ---查询数据块的分区名 * @partition_offset ---查询数据块的分区相对偏移地址 * * 描述:根据分区名和分区的偏移地址来确定Flash的地址,再来判断此block是不是坏块 返回值: * 0表示此块是好块 * 1表示是坏块 * 其他的表示有错误 */ int bsp_nand_isbad(const char *partition_name, u32 partition_offset) { u32 flash_addr; u32 bad_flag; u32 ret = NANDC_ERROR; struct nandc_host * host = NULL; struct ST_PART_TBL * ptable = find_partition_by_name(partition_name); if(!ptable) { goto ERRO; } /*得到Flash地址*/ flash_addr = ptable->offset + partition_offset; host = nandc_nand_host; if(!host) { NAND_TRACE(("ERROR: function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } /*判断此block是否是坏块*/ ret = nand_isbad(flash_addr / host->nandchip->spec.blocksize, &bad_flag); if(ret == 1) { return -6; } else if(ret > 1) { return ret; } if(bad_flag == 1) /* bad block */ { return 1; } else /* good block */ { return 0; } ERRO: return ret; }
/** * 作用:nandc模块按分区名和分区偏移地址来擦除flash操作 * * 参数: * @partition_name ---要擦除的分区名 * @partition_offset ---要擦除的相对偏移地址 * * * 描述:根据分区名和分区的偏移地址来确定Flash的地址,再来擦除一个block,注意是擦除一个block数据块 */ int bsp_nand_erase(const char *partition_name, u32 partition_offset) { u32 flash_addr; u32 block_id, bad_flag; u32 ret = NANDC_ERROR; struct nandc_host * host = NULL; struct ST_PART_TBL * ptable = find_partition_by_name(partition_name); /*参数不正确*/ if(!ptable) { goto ERRO; } /*得到flash的地址信息*/ flash_addr = ptable->offset + partition_offset; host = nandc_nand_host; if(!host) { NAND_TRACE(("ERROR: function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } /*得到块号并判断是否是坏块*/ block_id = flash_addr / host->nandchip->spec.blocksize; ret = nand_isbad(block_id, &bad_flag); if(ret) { NAND_TRACE(("ERROR: nand quary bad failed, function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } if(NANDC_BAD_BLOCK == bad_flag) { NAND_TRACE(("ERROR: try to erase a bad block, function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } /*擦除flash操作*/ return nand_erase(block_id); ERRO: return ret; }
/** * 作用:对nand标坏块 * * 参数: * @blockid ---block块的字符串 * * * 描述:nand标坏块 */ void bsp_nand_markbad(char *blockid) { int ret = NANDC_ERROR; unsigned int id, bad_flag; char *blk_id = bsp_nand_argument_check(blockid); /* string to int */ ret= str2ul(blk_id, &id); if(ret) { NAND_TRACE(("ERROR: string to integer failed, ret = 0x%x.\n", ret)); goto EXIT; } /* check block bad. if good, mark bad; else return */ ret = nand_isbad(id, &bad_flag); if(ret) { NAND_TRACE(("[%s]ERROR: nand check bad failed, ret = 0x%x.\n", __FUNCTION__, ret)); goto EXIT; } if(NANDC_GOOD_BLOCK == bad_flag) { ret = nand_bad(id); if(ret) { NAND_TRACE(("[%s]ERROR: nand mark bad failed, ret = 0x%x.\n", __FUNCTION__, ret)); goto EXIT; } } else { NAND_TRACE(("[%s]WARNING: block 0x%x is already bad.\n", __FUNCTION__)); goto EXIT; } return; EXIT: return; }
/***************************************************************************** * name : flash_erase * * description : Erase nand block * * input : ptentry *ptn: partition to be erase * * return : NANDF_OK: erase OK * NANDF_ERROR_INIT: Init failed * NANDF_ERROR_ARGS: Input error * NANDF_BAD_BLOCK: the block to be erase is a bad block * NANDF_ERROR_ERASE: erase failed, and mark the block as a bad block * NANDF_ERROR_ERASE_MARKBAD: erase failed, and mark bad block failed * NANDF_ERROR_SEMTAKE: apply semphore failed * NANDF_ERROR_SEMGIVE: release semphore failed * * other : No *****************************************************************************/ int flash_erase(ptentry *ptn) { int ret = ERROR; unsigned i = 0; unsigned block_start = 0; unsigned block_end= 0; unsigned bad_flag; struct nand_spec spec; ret = nand_get_spec(&spec); if(ret) { cprintf("ERROR: nand get spec failed!\n"); return ERROR; } /* coverity[uninit_use] */ block_start = (ptn->start + spec.blocksize- 1) / spec.blocksize; block_end = (ptn->start + ptn->length + spec.blocksize - 1) / spec.blocksize; for (i = block_start; i < block_end; i++) { ret = (s32)nand_isbad(i, &bad_flag); if(NANDC_OK != ret || NANDC_BAD_BLOCK == bad_flag) { cprintf("block %d is bad, not erase, ret=%x\n", i, ret); continue; } ret = (s32)nand_erase(i); if(ret) { cprintf("erase block %d failed, ret=%x\n", i, ret); } } return OK; }
/** * 作用:nandc模块提供对外扫描坏块的函数接口 * * 参数: * @start ---flash开始的地址 * @length ---扫描的长度 * @if_erase ---如果检测是好块根据此参数来决定是否擦除此块 * 描述:扫描flash是否是坏块,根据参数来决定是否擦除 */ u32 nand_scan_bad(FSZ start, FSZ length, u32 if_erase) { u32 addr_block_align; u32 length_block_align; u32 blk_id, is_bad, times, ret; struct nand_spec spec; /*因为是在fastboot中实现,内存的释放是没有实现的,使用静态变量表示一次分配以后都不分配了*/ static u32 block_buf = 0 ; memset(&spec, 0, sizeof(struct nand_spec)); /*通过此函数得到nandflash的规格参数,知道blocksize的大小*/ if(NAND_OK != nand_get_spec(&spec)) { NAND_TRACE(("nand_scan_bad: nand_get_spec failed\n")); return NAND_ERROR; } /*扫描块时要块对齐*/ addr_block_align = start - start%(spec.blocksize); /*得到要扫描的块长度*/ length_block_align = nandc_alige_size(start + length, spec.blocksize) - addr_block_align; /*如果没有分配内存就分配内存*/ if(!block_buf) { block_buf = (u32)himalloc(spec.blocksize); if(NULL == (void*)block_buf)//pclint 58 { NAND_TRACE(("nand_scan_bad: himalloc failed\n")); goto ERRO; } } /*还有块长度需要扫描*/ while(length_block_align > 0) { /*得到块号地址*/ blk_id = addr_block_align/spec.blocksize; if(NAND_OK != nand_isbad(blk_id, &is_bad)) { NAND_TRACE(("nand_scan_bad: nand_isbad failed\n")); goto ERRO; } if(NANDC_GOOD_BLOCK == is_bad) { times = 1; /*读整块数据如果没有出错的话表示是好坏*/ while((NANDC_E_READ == nand_read((FSZ)addr_block_align, block_buf, spec.blocksize, 0)) && (times)) { times--; } if(0 == times) { NAND_TRACE(("nand_scan_bad: find and read error, address:0x%x\n",addr_block_align)); ret = nand_bad(blk_id); if(ret) { NAND_TRACE(("nand_scan_bad:nand check bad failed, ret = 0x%x\n",ret)); } } /*是好块如果要擦除的话就擦除*/ else if(NANDC_TRUE == if_erase) { ret = nand_erase(blk_id); if(ret) { NAND_TRACE(("nand_scan_bad:nand erase failed, ret = 0x%x\n",ret)); } } else { } } else { NAND_TRACE(("nand_scan_bad:find bad block: 0x%x\n",addr_block_align)); } length_block_align -= spec.blocksize; addr_block_align += spec.blocksize; } return NAND_OK; ERRO: return NAND_ERROR; }