/* returns 0 if block containing pos is OK: * valid erase block and * not marked bad, or no bad mark position is specified * returns 1 if marked bad or otherwise invalid */ static int check_block (struct nand_chip *nand, unsigned long pos) { size_t retlen; uint8_t oob_data; uint16_t oob_data16[6]; int page0 = pos & (-nand->erasesize); int page1 = page0 + nand->oobblock; int badpos = oob_config.badblock_pos; if (pos >= nand->totlen) return 1; if (badpos < 0) return 0; /* no way to check, assume OK */ if (nand->bus16) { if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16) || (oob_data16[2] & 0xff00) != 0xff00) return 1; if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16) || (oob_data16[2] & 0xff00) != 0xff00) return 1; } else { /* Note - bad block marker can be on first or second page */ if (nand_read_oob(nand, page0 + badpos, 1, &retlen, (unsigned char *)&oob_data) || oob_data != 0xff || nand_read_oob (nand, page1 + badpos, 1, &retlen, (unsigned char *)&oob_data) || oob_data != 0xff) return 1; } return 0; }
static int nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, uint32_t len, uint8_t *data, uint8_t write) { struct chip_geom *cg; uint8_t *buf = NULL; int ret = 0; cg = &chip->chip_geom; buf = malloc(cg->oob_size, M_NAND, M_WAITOK); if (!buf) return (ENOMEM); memset(buf, 0xff, cg->oob_size); if (!write) { ret = nand_read_oob(chip, page, buf, cg->oob_size); copyout(buf, data, len); } else { copyin(data, buf, len); ret = nand_prog_oob(chip, page, buf, cg->oob_size); } free(buf, M_NAND); return (ret); }
/***************************************************************************** * name : flash_read_ext * * description : Read data from nand * * input : ptentry *ptn: flash partition to read * : unsigned extra_per_page: * : unsigned offset: offset from partition start address * : void *data: buffer to save data * : unsigned bytes: number of bytes to read * * return : NANDF_ERROR_INIT: Init error * NANDF_ERROR_ARGS: Input error * NANDF_ERROR_READ: Read error * NANDF_OK: Read successful * * other : No *****************************************************************************/ int flash_read_ext(ptentry *ptn, unsigned extra_per_page, unsigned offset, void *data, unsigned bytes, unsigned int *skip_len) { int ret = 0; u64 src_addr = 0; src_addr = ptn->start + offset; ret = nand_read_oob((u64)src_addr, (u32)data, bytes, extra_per_page, skip_len); return ret; }
/** * 作用:读取分区相对偏移地址的标志值,主要是为NV模块用,查询此分区的偏移地址的标志位的值 * * 参数: * @partition_name ---分区名 * @partition_offset ---分区的相对偏移 * @flag ---把检测的分区的标志值存放在此flag中 * 描述:NV模块把一个分区的一个block的最后一页的OOB中存放特定标记值,读此标记值存放在flag中 */ u32 bsp_nand_read_flag_nv(const char *partition_name, u32 partition_offset, unsigned char *flag) { u32 flash_addr; u32 ret = NANDC_ERROR; static unsigned char *buffer = NULL; struct nand_spec spec; struct ST_PART_TBL * ptable = find_partition_by_name((char *)partition_name); /*参数不对*/ if(!ptable) { goto ERRO; } if(!flag) { NAND_TRACE(("argu error.\n")); goto ERRO; } /*得到此分区的nandflash的规格参数*/ ret = bsp_get_nand_info(&spec); if(ret) { goto ERRO; } /*没有内存时分配内存*/ if(!buffer) { buffer = (unsigned char *)himalloc(spec.pagesize + YAFFS_BYTES_PER_SPARE); if(!buffer) { NAND_TRACE(("get ram buffer failed!\n")); goto ERRO; } } memset(buffer, 0xFF, spec.pagesize + YAFFS_BYTES_PER_SPARE); flash_addr = ptable->offset + partition_offset; /*使能ECC功能的带OOB读数据功能*/ ret = nand_read_oob((flash_addr + spec.blocksize - spec.pagesize), (unsigned int)buffer, (spec.pagesize + YAFFS_BYTES_PER_SPARE),YAFFS_BYTES_PER_SPARE ,NULL); if(ret) { NAND_TRACE(("nand read oob failed!\n")); goto ERRO; } *flag = (*(buffer + spec.pagesize) == NV_WRITE_SUCCESS) ? NV_WRITE_SUCCESS : (~NV_WRITE_SUCCESS); return NANDC_OK; ERRO: return ret; }
static int nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, uint32_t len, uint8_t *data, uint8_t write) { struct chip_geom *cg; int ret = 0; cg = &chip->chip_geom; if (!write) ret = nand_read_oob(chip, page, data, cg->oob_size); else ret = nand_prog_oob(chip, page, data, cg->oob_size); return (ret); }
/* read a block data to buf * return 1 if the block is bad or ECC error can't be corrected for any page * return 0 on sucess */ int nand_read_block(unsigned char *buf, ulong block_addr) { int i, offset = 0; uchar oob_buf[16]; /* check bad block */ /* 0th and 5th words need be 0xffff */ if (nand_read_oob(oob_buf, block_addr) || // oob_buf[0] != 0xff || oob_buf[1] != 0xff || // oob_buf[10] != 0xff || oob_buf[11] != 0xff ){ oob_buf[5] != 0xff){ printf("Skipped bad block at 0x%x\n", block_addr); return NAND_READ_SKIPPED_BAD_BLOCK; /* skip bad block */ } /* read the block page by page*/ for (i=0; i<32; i++){ if (nand_read_page(buf+offset, block_addr + offset)) return NAND_READ_ECC_FAILURE; offset += PAGE_SIZE; } return NAND_READ_SUCCESS; }