diff options
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 147 | 
1 files changed, 125 insertions, 22 deletions
| diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 426bb95e9..7171bdd51 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -893,6 +893,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data + * @page:	page number to read + * + * Not for syndrome calculating ecc controllers, which use a special oob layout   */  static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  			      uint8_t *buf, int page) @@ -903,10 +906,53 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  }  /** + * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	buffer to store read data + * @page:	page number to read + * + * We need a special oob layout and handling even when OOB isn't used. + */ +static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, +			      uint8_t *buf, int page) +{ +	int eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	uint8_t *oob = chip->oob_poi; +	int steps, size; + +	for (steps = chip->ecc.steps; steps > 0; steps--) { +		chip->read_buf(mtd, buf, eccsize); +		buf += eccsize; + +		if (chip->ecc.prepad) { +			chip->read_buf(mtd, oob, chip->ecc.prepad); +			oob += chip->ecc.prepad; +		} + +		chip->read_buf(mtd, oob, eccbytes); +		oob += eccbytes; + +		if (chip->ecc.postpad) { +			chip->read_buf(mtd, oob, chip->ecc.postpad); +			oob += chip->ecc.postpad; +		} +	} + +	size = mtd->oobsize - (oob - chip->oob_poi); +	if (size) +		chip->read_buf(mtd, oob, size); + +	return 0; +} + +/**   * nand_read_page_swecc - [REPLACABLE] software ecc based page read function   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data + * @page:	page number to read   */  static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  				uint8_t *buf, int page) @@ -946,9 +992,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,   * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function   * @mtd:	mtd info structure   * @chip:	nand chip info structure - * @dataofs	offset of requested data within the page - * @readlen	data length - * @buf:	buffer to store read data + * @data_offs:	offset of requested data within the page + * @readlen:	data length + * @bufpoi:	buffer to store read data   */  static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)  { @@ -1015,7 +1061,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3  		int stat;  		stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); -		if (stat < 0) +		if (stat == -1)  			mtd->ecc_stats.failed++;  		else  			mtd->ecc_stats.corrected += stat; @@ -1028,6 +1074,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data + * @page:	page number to read   *   * Not for syndrome calculating ecc controllers which need a special oob layout   */ @@ -1059,7 +1106,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  		int stat;  		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); -		if (stat == -1) +		if (stat < 0)  			mtd->ecc_stats.failed++;  		else  			mtd->ecc_stats.corrected += stat; @@ -1072,6 +1119,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data + * @page:	page number to read   *   * Hardware ECC for large page chips, require OOB to be read first.   * For this ECC mode, the write_page method is re-used from ECC_HW. @@ -1120,6 +1168,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data + * @page:	page number to read   *   * The hw generator calculates the error syndrome automatically. Therefor   * we need a special oob layout and handling. @@ -1677,6 +1726,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	data buffer + * + * Not for syndrome calculating ecc controllers, which use a special oob layout   */  static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  				const uint8_t *buf) @@ -1686,6 +1737,44 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  }  /** + * nand_write_page_raw_syndrome - [Intern] raw page write function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	data buffer + * + * We need a special oob layout and handling even when ECC isn't checked. + */ +static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, +				const uint8_t *buf) +{ +	int eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	uint8_t *oob = chip->oob_poi; +	int steps, size; + +	for (steps = chip->ecc.steps; steps > 0; steps--) { +		chip->write_buf(mtd, buf, eccsize); +		buf += eccsize; + +		if (chip->ecc.prepad) { +			chip->write_buf(mtd, oob, chip->ecc.prepad); +			oob += chip->ecc.prepad; +		} + +		chip->read_buf(mtd, oob, eccbytes); +		oob += eccbytes; + +		if (chip->ecc.postpad) { +			chip->write_buf(mtd, oob, chip->ecc.postpad); +			oob += chip->ecc.postpad; +		} +	} + +	size = mtd->oobsize - (oob - chip->oob_poi); +	if (size) +		chip->write_buf(mtd, oob, size); +} +/**   * nand_write_page_swecc - [REPLACABLE] software ecc based page write function   * @mtd:	mtd info structure   * @chip:	nand chip info structure @@ -2211,13 +2300,15 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)  int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		    int allowbbt)  { -	int page, len, status, pages_per_block, ret, chipnr; +	int page, status, pages_per_block, ret, chipnr;  	struct nand_chip *chip = mtd->priv; -	int rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS]={0}; +	loff_t rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS] = {0};  	unsigned int bbt_masked_page = 0xffffffff; +	loff_t len; -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", -	          (unsigned int) instr->addr, (unsigned int) instr->len); +	MTDDEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, " +		 "len = %llu\n", (unsigned long long) instr->addr, +		 (unsigned long long) instr->len);  	/* Start address must align on block boundary */  	if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { @@ -2313,7 +2404,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  			MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "  			          "Failed erase, page 0x%08x\n", page);  			instr->state = MTD_ERASE_FAILED; -			instr->fail_addr = (page << chip->page_shift); +			instr->fail_addr = ((loff_t)page << chip->page_shift);  			goto erase_exit;  		} @@ -2323,7 +2414,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		 */  		if (bbt_masked_page != 0xffffffff &&  		    (page & BBT_PAGE_MASK) == bbt_masked_page) -			    rewrite_bbt[chipnr] = (page << chip->page_shift); +			rewrite_bbt[chipnr] = +				((loff_t)page << chip->page_shift);  		/* Increment page address and decrement length */  		len -= (1 << chip->phys_erase_shift); @@ -2370,8 +2462,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  			continue;  		/* update the BBT for chip */  		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " -		          "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr], -		          chip->bbt_td->pages[chipnr]); +			  "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr], +			  chip->bbt_td->pages[chipnr]);  		nand_update_bbt(mtd, rewrite_bbt[chipnr]);  	} @@ -2566,7 +2658,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	if (!mtd->name)  		mtd->name = type->name; -	chip->chipsize = type->chipsize << 20; +	chip->chipsize = (uint64_t)type->chipsize << 20;  	/* Newer devices have all the information in additional id bytes */  	if (!type->pagesize) { @@ -2624,7 +2716,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	chip->bbt_erase_shift = chip->phys_erase_shift =  		ffs(mtd->erasesize) - 1; -	chip->chip_shift = ffs(chip->chipsize) - 1; +	if (chip->chipsize & 0xffffffff) +		chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; +	else +		chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;  	/* Set the bad block position */  	chip->badblockpos = mtd->writesize > 512 ? @@ -2722,7 +2817,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)  /**   * nand_scan_tail - [NAND Interface] Scan for the NAND device   * @mtd:	    MTD device structure - * @maxchips:	    Number of chips to scan for   *   * This is the second phase of the normal nand_scan() function. It   * fills out all the uninitialized function pointers with the defaults @@ -2761,7 +2855,6 @@ int nand_scan_tail(struct mtd_info *mtd)  		default:  			printk(KERN_WARNING "No oob scheme defined for "  			       "oobsize %d\n", mtd->oobsize); -/*			BUG(); */  		}  	} @@ -2772,10 +2865,6 @@ int nand_scan_tail(struct mtd_info *mtd)  	 * check ECC mode, default to software if 3byte/512byte hardware ECC is  	 * selected and we have 256 byte pagesize fallback to software ECC  	 */ -	if (!chip->ecc.read_page_raw) -		chip->ecc.read_page_raw = nand_read_page_raw; -	if (!chip->ecc.write_page_raw) -		chip->ecc.write_page_raw = nand_write_page_raw;  	switch (chip->ecc.mode) {  	case NAND_ECC_HW_OOB_FIRST: @@ -2795,6 +2884,10 @@ int nand_scan_tail(struct mtd_info *mtd)  			chip->ecc.read_page = nand_read_page_hwecc;  		if (!chip->ecc.write_page)  			chip->ecc.write_page = nand_write_page_hwecc; +		if (!chip->ecc.read_page_raw) +			chip->ecc.read_page_raw = nand_read_page_raw; +		if (!chip->ecc.write_page_raw) +			chip->ecc.write_page_raw = nand_write_page_raw;  		if (!chip->ecc.read_oob)  			chip->ecc.read_oob = nand_read_oob_std;  		if (!chip->ecc.write_oob) @@ -2816,6 +2909,10 @@ int nand_scan_tail(struct mtd_info *mtd)  			chip->ecc.read_page = nand_read_page_syndrome;  		if (!chip->ecc.write_page)  			chip->ecc.write_page = nand_write_page_syndrome; +		if (!chip->ecc.read_page_raw) +			chip->ecc.read_page_raw = nand_read_page_raw_syndrome; +		if (!chip->ecc.write_page_raw) +			chip->ecc.write_page_raw = nand_write_page_raw_syndrome;  		if (!chip->ecc.read_oob)  			chip->ecc.read_oob = nand_read_oob_syndrome;  		if (!chip->ecc.write_oob) @@ -2834,6 +2931,8 @@ int nand_scan_tail(struct mtd_info *mtd)  		chip->ecc.read_page = nand_read_page_swecc;  		chip->ecc.read_subpage = nand_read_subpage;  		chip->ecc.write_page = nand_write_page_swecc; +		chip->ecc.read_page_raw = nand_read_page_raw; +		chip->ecc.write_page_raw = nand_write_page_raw;  		chip->ecc.read_oob = nand_read_oob_std;  		chip->ecc.write_oob = nand_write_oob_std;  		chip->ecc.size = 256; @@ -2846,6 +2945,8 @@ int nand_scan_tail(struct mtd_info *mtd)  		chip->ecc.read_page = nand_read_page_raw;  		chip->ecc.write_page = nand_write_page_raw;  		chip->ecc.read_oob = nand_read_oob_std; +		chip->ecc.read_page_raw = nand_read_page_raw; +		chip->ecc.write_page_raw = nand_write_page_raw;  		chip->ecc.write_oob = nand_write_oob_std;  		chip->ecc.size = mtd->writesize;  		chip->ecc.bytes = 0; @@ -2862,7 +2963,8 @@ int nand_scan_tail(struct mtd_info *mtd)  	 * the out of band area  	 */  	chip->ecc.layout->oobavail = 0; -	for (i = 0; chip->ecc.layout->oobfree[i].length; i++) +	for (i = 0; chip->ecc.layout->oobfree[i].length +			&& i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)  		chip->ecc.layout->oobavail +=  			chip->ecc.layout->oobfree[i].length;  	mtd->oobavail = chip->ecc.layout->oobavail; @@ -2890,6 +2992,7 @@ int nand_scan_tail(struct mtd_info *mtd)  			break;  		case 4:  		case 8: +		case 16:  			mtd->subpage_sft = 2;  			break;  		} |