summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/nand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r--drivers/mtd/nand/nand_base.c147
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;
}