Commit 97d90da8 authored by Boris Brezillon's avatar Boris Brezillon

mtd: nand: provide several helpers to do common NAND operations

This is part of the process of removing direct calls to ->cmdfunc()
outside of the core in order to introduce a better interface to execute
NAND operations.

Here we provide several helpers and make use of them to remove all
direct calls to ->cmdfunc(). This way, we can easily modify those
helpers to make use of the new ->exec_op() interface when available.
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
[miquel.raynal@free-electrons.com: rebased and fixed some conflicts]
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@free-electrons.com>
Acked-by: default avatarMasahiro Yamada <yamada.masahiro@socionext.com>
parent eb94555e
...@@ -1000,7 +1000,7 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, ...@@ -1000,7 +1000,7 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
* to the non-optimized one. * to the non-optimized one.
*/ */
if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) { if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); nand_read_page_op(chip, page, 0, NULL, 0);
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
raw); raw);
......
...@@ -1071,7 +1071,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp) ...@@ -1071,7 +1071,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
return; return;
brcmnand_set_wp(ctrl, wp); brcmnand_set_wp(ctrl, wp);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(chip, NULL);
/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */ /* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
ret = bcmnand_ctrl_poll_status(ctrl, ret = bcmnand_ctrl_poll_status(ctrl,
NAND_CTRL_RDY | NAND_CTRL_RDY |
...@@ -1453,7 +1453,7 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd) ...@@ -1453,7 +1453,7 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
/* At FC_BYTES boundary, switch to next column */ /* At FC_BYTES boundary, switch to next column */
if (host->last_byte > 0 && offs == 0) if (host->last_byte > 0 && offs == 0)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, addr, -1); nand_change_read_column_op(chip, addr, NULL, 0, false);
ret = ctrl->flash_cache[offs]; ret = ctrl->flash_cache[offs];
break; break;
...@@ -1689,7 +1689,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, ...@@ -1689,7 +1689,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
sas = mtd->oobsize / chip->ecc.steps; sas = mtd->oobsize / chip->ecc.steps;
/* read without ecc for verification */ /* read without ecc for verification */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); nand_read_page_op(chip, page, 0, NULL, 0);
ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page); ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
if (ret) if (ret)
return ret; return ret;
...@@ -2369,12 +2369,11 @@ static int brcmnand_resume(struct device *dev) ...@@ -2369,12 +2369,11 @@ static int brcmnand_resume(struct device *dev)
list_for_each_entry(host, &ctrl->host_list, node) { list_for_each_entry(host, &ctrl->host_list, node) {
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
brcmnand_save_restore_cs_config(host, 1); brcmnand_save_restore_cs_config(host, 1);
/* Reset the chip, required by some chips after power-up */ /* Reset the chip, required by some chips after power-up */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(chip);
} }
return 0; return 0;
......
...@@ -353,23 +353,15 @@ static void cafe_nand_bug(struct mtd_info *mtd) ...@@ -353,23 +353,15 @@ static void cafe_nand_bug(struct mtd_info *mtd)
static int cafe_nand_write_oob(struct mtd_info *mtd, static int cafe_nand_write_oob(struct mtd_info *mtd,
struct nand_chip *chip, int page) struct nand_chip *chip, int page)
{ {
int status = 0; return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* Don't use -- use nand_read_oob_std for now */ /* Don't use -- use nand_read_oob_std for now */
static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
} }
/** /**
* cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
......
...@@ -645,8 +645,6 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -645,8 +645,6 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
int page, int write) int page, int write)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0;
unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT;
int writesize = mtd->writesize; int writesize = mtd->writesize;
int oobsize = mtd->oobsize; int oobsize = mtd->oobsize;
uint8_t *bufpoi = chip->oob_poi; uint8_t *bufpoi = chip->oob_poi;
...@@ -658,11 +656,11 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -658,11 +656,11 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
int i, pos, len; int i, pos, len;
/* BBM at the beginning of the OOB area */ /* BBM at the beginning of the OOB area */
chip->cmdfunc(mtd, start_cmd, writesize, page);
if (write) if (write)
chip->write_buf(mtd, bufpoi, oob_skip); nand_prog_page_begin_op(chip, page, writesize, bufpoi,
oob_skip);
else else
chip->read_buf(mtd, bufpoi, oob_skip); nand_read_page_op(chip, page, writesize, bufpoi, oob_skip);
bufpoi += oob_skip; bufpoi += oob_skip;
/* OOB ECC */ /* OOB ECC */
...@@ -675,30 +673,35 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -675,30 +673,35 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
else if (pos + len > writesize) else if (pos + len > writesize)
len = writesize - pos; len = writesize - pos;
chip->cmdfunc(mtd, rnd_cmd, pos, -1);
if (write) if (write)
chip->write_buf(mtd, bufpoi, len); nand_change_write_column_op(chip, pos, bufpoi, len,
false);
else else
chip->read_buf(mtd, bufpoi, len); nand_change_read_column_op(chip, pos, bufpoi, len,
false);
bufpoi += len; bufpoi += len;
if (len < ecc_bytes) { if (len < ecc_bytes) {
len = ecc_bytes - len; len = ecc_bytes - len;
chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1);
if (write) if (write)
chip->write_buf(mtd, bufpoi, len); nand_change_write_column_op(chip, writesize +
oob_skip, bufpoi,
len, false);
else else
chip->read_buf(mtd, bufpoi, len); nand_change_read_column_op(chip, writesize +
oob_skip, bufpoi,
len, false);
bufpoi += len; bufpoi += len;
} }
} }
/* OOB free */ /* OOB free */
len = oobsize - (bufpoi - chip->oob_poi); len = oobsize - (bufpoi - chip->oob_poi);
chip->cmdfunc(mtd, rnd_cmd, size - len, -1);
if (write) if (write)
chip->write_buf(mtd, bufpoi, len); nand_change_write_column_op(chip, size - len, bufpoi, len,
false);
else else
chip->read_buf(mtd, bufpoi, len); nand_change_read_column_op(chip, size - len, bufpoi, len,
false);
} }
static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
...@@ -788,16 +791,12 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -788,16 +791,12 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
int status;
denali_reset_irq(denali); denali_reset_irq(denali);
denali_oob_xfer(mtd, chip, page, 1); denali_oob_xfer(mtd, chip, page, 1);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
......
...@@ -448,7 +448,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this) ...@@ -448,7 +448,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
int status; int status;
DoC_WaitReady(doc); DoC_WaitReady(doc);
this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(this, NULL);
DoC_WaitReady(doc); DoC_WaitReady(doc);
status = (int)this->read_byte(mtd); status = (int)this->read_byte(mtd);
...@@ -595,7 +595,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) ...@@ -595,7 +595,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
/* Assert ChipEnable and deassert WriteProtect */ /* Assert ChipEnable and deassert WriteProtect */
WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect); WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(this);
doc->curchip = chip; doc->curchip = chip;
doc->curfloor = floor; doc->curfloor = floor;
......
...@@ -864,7 +864,7 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, ...@@ -864,7 +864,7 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
dev_dbg(doc->dev, "%s: page %x\n", __func__, page); dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page); nand_read_page_op(nand, page, nand->ecc.size, NULL, 0);
writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0); writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
write_nop(docptr); write_nop(docptr);
......
...@@ -697,7 +697,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -697,7 +697,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); nand_read_page_op(chip, page, s * eccsize, NULL, 0);
chip->ecc.hwctl(mtd, NAND_ECC_READ); chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize); chip->read_buf(mtd, p, eccsize);
...@@ -720,8 +720,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -720,8 +720,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
if (chip->options & NAND_BUSWIDTH_16) if (chip->options & NAND_BUSWIDTH_16)
len = roundup(len, 2); len = roundup(len, 2);
chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); nand_read_oob_op(chip, page, off, oob + j, len);
chip->read_buf(mtd, oob + j, len);
j += len; j += len;
} }
......
...@@ -1097,8 +1097,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1097,8 +1097,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
eccbytes = DIV_ROUND_UP(offset + eccbits, 8); eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
offset /= 8; offset /= 8;
eccbytes -= offset; eccbytes -= offset;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); nand_change_read_column_op(chip, offset, eccbuf,
chip->read_buf(mtd, eccbuf, eccbytes); eccbytes, false);
/* /*
* ECC data are not byte aligned and we may have * ECC data are not byte aligned and we may have
...@@ -1220,7 +1220,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1220,7 +1220,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
meta = geo->metadata_size; meta = geo->metadata_size;
if (first) { if (first) {
col = meta + (size + ecc_parity_size) * first; col = meta + (size + ecc_parity_size) * first;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1); nand_change_read_column_op(chip, col, NULL, 0, false);
meta = 0; meta = 0;
buf = buf + first * size; buf = buf + first * size;
...@@ -1411,7 +1411,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1411,7 +1411,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
memset(chip->oob_poi, ~0, mtd->oobsize); memset(chip->oob_poi, ~0, mtd->oobsize);
/* Read out the conventional OOB. */ /* Read out the conventional OOB. */
chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
/* /*
...@@ -1421,7 +1421,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1421,7 +1421,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
*/ */
if (GPMI_IS_MX23(this)) { if (GPMI_IS_MX23(this)) {
/* Read the block mark into the first byte of the OOB buffer. */ /* Read the block mark into the first byte of the OOB buffer. */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
chip->oob_poi[0] = chip->read_byte(mtd); chip->oob_poi[0] = chip->read_byte(mtd);
} }
...@@ -1432,7 +1432,6 @@ static int ...@@ -1432,7 +1432,6 @@ static int
gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
{ {
struct mtd_oob_region of = { }; struct mtd_oob_region of = { };
int status = 0;
/* Do we have available oob area? */ /* Do we have available oob area? */
mtd_ooblayout_free(mtd, 0, &of); mtd_ooblayout_free(mtd, 0, &of);
...@@ -1442,12 +1441,8 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) ...@@ -1442,12 +1441,8 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
if (!nand_is_slc(chip)) if (!nand_is_slc(chip))
return -EPERM; return -EPERM;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of.offset, page); return nand_prog_page_op(chip, page, mtd->writesize + of.offset,
chip->write_buf(mtd, chip->oob_poi + of.offset, of.length); chip->oob_poi + of.offset, of.length);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* /*
...@@ -1622,7 +1617,7 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, ...@@ -1622,7 +1617,7 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page); return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
} }
...@@ -1630,7 +1625,7 @@ static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1630,7 +1625,7 @@ static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page); return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
} }
...@@ -1641,7 +1636,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1641,7 +1636,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct gpmi_nand_data *this = nand_get_controller_data(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret = 0; int ret = 0;
uint8_t *block_mark; uint8_t *block_mark;
int column, page, status, chipnr; int column, page, chipnr;
chipnr = (int)(ofs >> chip->chip_shift); chipnr = (int)(ofs >> chip->chip_shift);
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
...@@ -1655,13 +1650,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1655,13 +1650,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* Shift to get page */ /* Shift to get page */
page = (int)(ofs >> chip->page_shift); page = (int)(ofs >> chip->page_shift);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); ret = nand_prog_page_op(chip, page, column, block_mark, 1);
chip->write_buf(mtd, block_mark, 1);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
ret = -EIO;
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
...@@ -1729,7 +1718,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1729,7 +1718,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
* Read the NCB fingerprint. The fingerprint is four bytes long * Read the NCB fingerprint. The fingerprint is four bytes long
* and starts in the 12th byte of the page. * and starts in the 12th byte of the page.
*/ */
chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page); nand_read_page_op(chip, page, 12, NULL, 0);
chip->read_buf(mtd, buffer, strlen(fingerprint)); chip->read_buf(mtd, buffer, strlen(fingerprint));
/* Look for the fingerprint. */ /* Look for the fingerprint. */
...@@ -1789,17 +1778,10 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1789,17 +1778,10 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
dev_dbg(dev, "Erasing the search area...\n"); dev_dbg(dev, "Erasing the search area...\n");
for (block = 0; block < search_area_size_in_blocks; block++) { for (block = 0; block < search_area_size_in_blocks; block++) {
/* Compute the page address. */
page = block * block_size_in_pages;
/* Erase this block. */ /* Erase this block. */
dev_dbg(dev, "\tErasing block 0x%x\n", block); dev_dbg(dev, "\tErasing block 0x%x\n", block);
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); status = nand_erase_op(chip, block);
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); if (status)
/* Wait for the erase to finish. */
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
dev_err(dev, "[%s] Erase failed.\n", __func__); dev_err(dev, "[%s] Erase failed.\n", __func__);
} }
...@@ -1815,13 +1797,11 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1815,13 +1797,11 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Write the first page of the current stride. */ /* Write the first page of the current stride. */
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
/* Wait for the write to finish. */ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
status = chip->waitfunc(mtd, chip); chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
if (status & NAND_STATUS_FAIL) status = nand_prog_page_end_op(chip);
if (status)
dev_err(dev, "[%s] Write failed.\n", __func__); dev_err(dev, "[%s] Write failed.\n", __func__);
} }
...@@ -1876,7 +1856,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this) ...@@ -1876,7 +1856,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
/* Send the command to read the conventional block mark. */ /* Send the command to read the conventional block mark. */
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
block_mark = chip->read_byte(mtd); block_mark = chip->read_byte(mtd);
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
......
...@@ -574,8 +574,7 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -574,8 +574,7 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
{ {
struct hinfc_host *host = nand_get_controller_data(chip); struct hinfc_host *host = nand_get_controller_data(chip);
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (host->irq_status & HINFC504_INTS_UE) { if (host->irq_status & HINFC504_INTS_UE) {
host->irq_status = 0; host->irq_status = 0;
......
...@@ -313,6 +313,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev, ...@@ -313,6 +313,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
uint32_t ctrl; uint32_t ctrl;
struct nand_chip *chip = &nand->chip; struct nand_chip *chip = &nand->chip;
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
u8 id[2];
/* Request I/O resource. */ /* Request I/O resource. */
sprintf(res_name, "bank%d", bank); sprintf(res_name, "bank%d", bank);
...@@ -335,17 +336,16 @@ static int jz_nand_detect_bank(struct platform_device *pdev, ...@@ -335,17 +336,16 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
/* Retrieve the IDs from the first chip. */ /* Retrieve the IDs from the first chip. */
chip->select_chip(mtd, 0); chip->select_chip(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(chip);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); nand_readid_op(chip, 0, id, sizeof(id));
*nand_maf_id = chip->read_byte(mtd); *nand_maf_id = id[0];
*nand_dev_id = chip->read_byte(mtd); *nand_dev_id = id[1];
} else { } else {
/* Detect additional chip. */ /* Detect additional chip. */
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(chip);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); nand_readid_op(chip, 0, id, sizeof(id));
if (*nand_maf_id != chip->read_byte(mtd) if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
|| *nand_dev_id != chip->read_byte(mtd)) {
ret = -ENODEV; ret = -ENODEV;
goto notfound_id; goto notfound_id;
} }
......
...@@ -461,7 +461,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -461,7 +461,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
} }
/* Writing Command and Address */ /* Writing Command and Address */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
/* For all sub-pages */ /* For all sub-pages */
for (i = 0; i < host->mlcsubpages; i++) { for (i = 0; i < host->mlcsubpages; i++) {
......
...@@ -399,10 +399,7 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int ...@@ -399,10 +399,7 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int
static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd, static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
struct nand_chip *chip, int page) struct nand_chip *chip, int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
} }
/* /*
...@@ -411,17 +408,8 @@ static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd, ...@@ -411,17 +408,8 @@ static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd, static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
struct nand_chip *chip, int page) struct nand_chip *chip, int page)
{ {
int status; return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* /*
...@@ -632,7 +620,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, ...@@ -632,7 +620,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE]; uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
/* Issue read command */ /* Issue read command */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
/* Read data and oob, calculate ECC */ /* Read data and oob, calculate ECC */
status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1); status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
...@@ -675,7 +663,7 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd, ...@@ -675,7 +663,7 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
int page) int page)
{ {
/* Issue read command */ /* Issue read command */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
/* Raw reads can just use the FIFO interface */ /* Raw reads can just use the FIFO interface */
chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
......
...@@ -834,16 +834,13 @@ static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -834,16 +834,13 @@ static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
{ {
int ret; int ret;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
ret = mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page); ret = mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
if (ret < 0) if (ret < 0)
return -EIO; return -EIO;
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
ret = chip->waitfunc(mtd, chip);
return ret & NAND_STATUS_FAIL ? -EIO : 0;
} }
static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors) static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
...@@ -893,7 +890,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -893,7 +890,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
buf = bufpoi + start * chip->ecc.size; buf = bufpoi + start * chip->ecc.size;
if (column != 0) if (column != 0)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1); nand_change_read_column_op(chip, column, NULL, 0, false);
addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE); addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
rc = dma_mapping_error(nfc->dev, addr); rc = dma_mapping_error(nfc->dev, addr);
...@@ -1016,7 +1013,7 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1016,7 +1013,7 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page); return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
} }
......
...@@ -561,14 +561,19 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) ...@@ -561,14 +561,19 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
static int nand_check_wp(struct mtd_info *mtd) static int nand_check_wp(struct mtd_info *mtd)
{ {
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
u8 status;
int ret;
/* Broken xD cards report WP despite being writable */ /* Broken xD cards report WP despite being writable */
if (chip->options & NAND_BROKEN_XD) if (chip->options & NAND_BROKEN_XD)
return 0; return 0;
/* Check the WP bit */ /* Check the WP bit */
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); ret = nand_status_op(chip, &status);
return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; if (ret)
return ret;
return status & NAND_STATUS_WP ? 0 : 1;
} }
/** /**
...@@ -667,10 +672,17 @@ EXPORT_SYMBOL_GPL(nand_wait_ready); ...@@ -667,10 +672,17 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
{ {
register struct nand_chip *chip = mtd_to_nand(mtd); register struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
timeo = jiffies + msecs_to_jiffies(timeo); timeo = jiffies + msecs_to_jiffies(timeo);
do { do {
if ((chip->read_byte(mtd) & NAND_STATUS_READY)) u8 status;
ret = nand_read_data_op(chip, &status, sizeof(status), true);
if (ret)
return;
if (status & NAND_STATUS_READY)
break; break;
touch_softlockup_watchdog(); touch_softlockup_watchdog();
} while (time_before(jiffies, timeo)); } while (time_before(jiffies, timeo));
...@@ -1019,7 +1031,15 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1019,7 +1031,15 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
if (chip->dev_ready(mtd)) if (chip->dev_ready(mtd))
break; break;
} else { } else {
if (chip->read_byte(mtd) & NAND_STATUS_READY) int ret;
u8 status;
ret = nand_read_data_op(chip, &status, sizeof(status),
true);
if (ret)
return;
if (status & NAND_STATUS_READY)
break; break;
} }
mdelay(1); mdelay(1);
...@@ -1036,8 +1056,9 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1036,8 +1056,9 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
{ {
int status;
unsigned long timeo = 400; unsigned long timeo = 400;
u8 status;
int ret;
/* /*
* Apply this short delay always to ensure that we do wait tWB in any * Apply this short delay always to ensure that we do wait tWB in any
...@@ -1045,7 +1066,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -1045,7 +1066,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
*/ */
ndelay(100); ndelay(100);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); ret = nand_status_op(chip, NULL);
if (ret)
return ret;
if (in_interrupt() || oops_in_progress) if (in_interrupt() || oops_in_progress)
panic_nand_wait(mtd, chip, timeo); panic_nand_wait(mtd, chip, timeo);
...@@ -1056,14 +1079,22 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -1056,14 +1079,22 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
if (chip->dev_ready(mtd)) if (chip->dev_ready(mtd))
break; break;
} else { } else {
if (chip->read_byte(mtd) & NAND_STATUS_READY) ret = nand_read_data_op(chip, &status,
sizeof(status), true);
if (ret)
return ret;
if (status & NAND_STATUS_READY)
break; break;
} }
cond_resched(); cond_resched();
} while (time_before(jiffies, timeo)); } while (time_before(jiffies, timeo));
} }
status = (int)chip->read_byte(mtd); ret = nand_read_data_op(chip, &status, sizeof(status), true);
if (ret)
return ret;
/* This can happen if in case of timeout or buggy dev_ready */ /* This can happen if in case of timeout or buggy dev_ready */
WARN_ON(!(status & NAND_STATUS_READY)); WARN_ON(!(status & NAND_STATUS_READY));
return status; return status;
...@@ -1217,6 +1248,516 @@ static void nand_release_data_interface(struct nand_chip *chip) ...@@ -1217,6 +1248,516 @@ static void nand_release_data_interface(struct nand_chip *chip)
kfree(chip->data_interface); kfree(chip->data_interface);
} }
/**
* nand_read_page_op - Do a READ PAGE operation
* @chip: The NAND chip
* @page: page to read
* @offset_in_page: offset within the page
* @buf: buffer used to store the data
* @len: length of the buffer
*
* This function issues a READ PAGE operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf, unsigned int len)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (len && !buf)
return -EINVAL;
if (offset_in_page + len > mtd->writesize + mtd->oobsize)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page);
if (len)
chip->read_buf(mtd, buf, len);
return 0;
}
EXPORT_SYMBOL_GPL(nand_read_page_op);
/**
* nand_read_param_page_op - Do a READ PARAMETER PAGE operation
* @chip: The NAND chip
* @page: parameter page to read
* @buf: buffer used to store the data
* @len: length of the buffer
*
* This function issues a READ PARAMETER PAGE operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
unsigned int len)
{
struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int i;
u8 *p = buf;
if (len && !buf)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1);
for (i = 0; i < len; i++)
p[i] = chip->read_byte(mtd);
return 0;
}
/**
* nand_change_read_column_op - Do a CHANGE READ COLUMN operation
* @chip: The NAND chip
* @offset_in_page: offset within the page
* @buf: buffer used to store the data
* @len: length of the buffer
* @force_8bit: force 8-bit bus access
*
* This function issues a CHANGE READ COLUMN operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_change_read_column_op(struct nand_chip *chip,
unsigned int offset_in_page, void *buf,
unsigned int len, bool force_8bit)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (len && !buf)
return -EINVAL;
if (offset_in_page + len > mtd->writesize + mtd->oobsize)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1);
if (len)
chip->read_buf(mtd, buf, len);
return 0;
}
EXPORT_SYMBOL_GPL(nand_change_read_column_op);
/**
* nand_read_oob_op - Do a READ OOB operation
* @chip: The NAND chip
* @page: page to read
* @offset_in_oob: offset within the OOB area
* @buf: buffer used to store the data
* @len: length of the buffer
*
* This function issues a READ OOB operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_oob, void *buf, unsigned int len)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (len && !buf)
return -EINVAL;
if (offset_in_oob + len > mtd->oobsize)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page);
if (len)
chip->read_buf(mtd, buf, len);
return 0;
}
EXPORT_SYMBOL_GPL(nand_read_oob_op);
/**
* nand_prog_page_begin_op - starts a PROG PAGE operation
* @chip: The NAND chip
* @page: page to write
* @offset_in_page: offset within the page
* @buf: buffer containing the data to write to the page
* @len: length of the buffer
*
* This function issues the first half of a PROG PAGE operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, const void *buf,
unsigned int len)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (len && !buf)
return -EINVAL;
if (offset_in_page + len > mtd->writesize + mtd->oobsize)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
if (buf)
chip->write_buf(mtd, buf, len);
return 0;
}
EXPORT_SYMBOL_GPL(nand_prog_page_begin_op);
/**
* nand_prog_page_end_op - ends a PROG PAGE operation
* @chip: The NAND chip
*
* This function issues the second half of a PROG PAGE operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_prog_page_end_op(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int status;
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
EXPORT_SYMBOL_GPL(nand_prog_page_end_op);
/**
* nand_prog_page_op - Do a full PROG PAGE operation
* @chip: The NAND chip
* @page: page to write
* @offset_in_page: offset within the page
* @buf: buffer containing the data to write to the page
* @len: length of the buffer
*
* This function issues a full PROG PAGE operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, const void *buf,
unsigned int len)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int status;
if (!len || !buf)
return -EINVAL;
if (offset_in_page + len > mtd->writesize + mtd->oobsize)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
chip->write_buf(mtd, buf, len);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
EXPORT_SYMBOL_GPL(nand_prog_page_op);
/**
* nand_change_write_column_op - Do a CHANGE WRITE COLUMN operation
* @chip: The NAND chip
* @offset_in_page: offset within the page
* @buf: buffer containing the data to send to the NAND
* @len: length of the buffer
* @force_8bit: force 8-bit bus access
*
* This function issues a CHANGE WRITE COLUMN operation.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_change_write_column_op(struct nand_chip *chip,
unsigned int offset_in_page,
const void *buf, unsigned int len,
bool force_8bit)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (len && !buf)
return -EINVAL;
if (offset_in_page + len > mtd->writesize + mtd->oobsize)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1);
if (len)
chip->write_buf(mtd, buf, len);
return 0;
}
EXPORT_SYMBOL_GPL(nand_change_write_column_op);
/**
* nand_readid_op - Do a READID operation
* @chip: The NAND chip
* @addr: address cycle to pass after the READID command
* @buf: buffer used to store the ID
* @len: length of the buffer
*
* This function sends a READID command and reads back the ID returned by the
* NAND.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
unsigned int len)
{
struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int i;
u8 *id = buf;
if (len && !buf)
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1);
for (i = 0; i < len; i++)
id[i] = chip->read_byte(mtd);
return 0;
}
EXPORT_SYMBOL_GPL(nand_readid_op);
/**
* nand_status_op - Do a STATUS operation
* @chip: The NAND chip
* @status: out variable to store the NAND status
*
* This function sends a STATUS command and reads back the status returned by
* the NAND.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_status_op(struct nand_chip *chip, u8 *status)
{
struct mtd_info *mtd = nand_to_mtd(chip);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
if (status)
*status = chip->read_byte(mtd);
return 0;
}
EXPORT_SYMBOL_GPL(nand_status_op);
/**
* nand_exit_status_op - Exit a STATUS operation
* @chip: The NAND chip
*
* This function sends a READ0 command to cancel the effect of the STATUS
* command to avoid reading only the status until a new read command is sent.
*
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_exit_status_op(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
return 0;
}
EXPORT_SYMBOL_GPL(nand_exit_status_op);
/**
* nand_erase_op - Do an erase operation
* @chip: The NAND chip
* @eraseblock: block to erase
*
* This function sends an ERASE command and waits for the NAND to be ready
* before returning.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
{
struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int page = eraseblock <<
(chip->phys_erase_shift - chip->page_shift);
int status;
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status < 0)
return status;
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
EXPORT_SYMBOL_GPL(nand_erase_op);
/**
* nand_set_features_op - Do a SET FEATURES operation
* @chip: The NAND chip
* @feature: feature id
* @data: 4 bytes of data
*
* This function sends a SET FEATURES command and waits for the NAND to be
* ready before returning.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
static int nand_set_features_op(struct nand_chip *chip, u8 feature,
const void *data)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const u8 *params = data;
int i, status;
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
chip->write_byte(mtd, params[i]);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
/**
* nand_get_features_op - Do a GET FEATURES operation
* @chip: The NAND chip
* @feature: feature id
* @data: 4 bytes of data
*
* This function sends a GET FEATURES command and waits for the NAND to be
* ready before returning.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
static int nand_get_features_op(struct nand_chip *chip, u8 feature,
void *data)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 *params = data;
int i;
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
params[i] = chip->read_byte(mtd);
return 0;
}
/**
* nand_reset_op - Do a reset operation
* @chip: The NAND chip
*
* This function sends a RESET command and waits for the NAND to be ready
* before returning.
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_reset_op(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
return 0;
}
EXPORT_SYMBOL_GPL(nand_reset_op);
/**
* nand_read_data_op - Read data from the NAND
* @chip: The NAND chip
* @buf: buffer used to store the data
* @len: length of the buffer
* @force_8bit: force 8-bit bus access
*
* This function does a raw data read on the bus. Usually used after launching
* another NAND operation like nand_read_page_op().
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
bool force_8bit)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (!len || !buf)
return -EINVAL;
if (force_8bit) {
u8 *p = buf;
unsigned int i;
for (i = 0; i < len; i++)
p[i] = chip->read_byte(mtd);
} else {
chip->read_buf(mtd, buf, len);
}
return 0;
}
EXPORT_SYMBOL_GPL(nand_read_data_op);
/**
* nand_write_data_op - Write data from the NAND
* @chip: The NAND chip
* @buf: buffer containing the data to send on the bus
* @len: length of the buffer
* @force_8bit: force 8-bit bus access
*
* This function does a raw data write on the bus. Usually used after launching
* another NAND operation like nand_write_page_begin_op().
* This function does not select/unselect the CS line.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_write_data_op(struct nand_chip *chip, const void *buf,
unsigned int len, bool force_8bit)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (!len || !buf)
return -EINVAL;
if (force_8bit) {
const u8 *p = buf;
unsigned int i;
for (i = 0; i < len; i++)
chip->write_byte(mtd, p[i]);
} else {
chip->write_buf(mtd, buf, len);
}
return 0;
}
EXPORT_SYMBOL_GPL(nand_write_data_op);
/** /**
* nand_reset - Reset and initialize a NAND device * nand_reset - Reset and initialize a NAND device
* @chip: The NAND chip * @chip: The NAND chip
...@@ -1238,8 +1779,10 @@ int nand_reset(struct nand_chip *chip, int chipnr) ...@@ -1238,8 +1779,10 @@ int nand_reset(struct nand_chip *chip, int chipnr)
* interface settings, hence this weird ->select_chip() dance. * interface settings, hence this weird ->select_chip() dance.
*/ */
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); ret = nand_reset_op(chip);
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
if (ret)
return ret;
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
ret = nand_setup_data_interface(chip, chipnr); ret = nand_setup_data_interface(chip, chipnr);
...@@ -1395,9 +1938,19 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk); ...@@ -1395,9 +1938,19 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) uint8_t *buf, int oob_required, int page)
{ {
chip->read_buf(mtd, buf, mtd->writesize); int ret;
if (oob_required)
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); ret = nand_read_data_op(chip, buf, mtd->writesize, false);
if (ret)
return ret;
if (oob_required) {
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
false);
if (ret)
return ret;
}
return 0; return 0;
} }
EXPORT_SYMBOL(nand_read_page_raw); EXPORT_SYMBOL(nand_read_page_raw);
...@@ -1419,29 +1972,46 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, ...@@ -1419,29 +1972,46 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
int eccsize = chip->ecc.size; int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes; int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi; uint8_t *oob = chip->oob_poi;
int steps, size; int steps, size, ret;
for (steps = chip->ecc.steps; steps > 0; steps--) { for (steps = chip->ecc.steps; steps > 0; steps--) {
chip->read_buf(mtd, buf, eccsize); ret = nand_read_data_op(chip, buf, eccsize, false);
if (ret)
return ret;
buf += eccsize; buf += eccsize;
if (chip->ecc.prepad) { if (chip->ecc.prepad) {
chip->read_buf(mtd, oob, chip->ecc.prepad); ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
false);
if (ret)
return ret;
oob += chip->ecc.prepad; oob += chip->ecc.prepad;
} }
chip->read_buf(mtd, oob, eccbytes); ret = nand_read_data_op(chip, oob, eccbytes, false);
if (ret)
return ret;
oob += eccbytes; oob += eccbytes;
if (chip->ecc.postpad) { if (chip->ecc.postpad) {
chip->read_buf(mtd, oob, chip->ecc.postpad); ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
false);
if (ret)
return ret;
oob += chip->ecc.postpad; oob += chip->ecc.postpad;
} }
} }
size = mtd->oobsize - (oob - chip->oob_poi); size = mtd->oobsize - (oob - chip->oob_poi);
if (size) if (size) {
chip->read_buf(mtd, oob, size); ret = nand_read_data_op(chip, oob, size, false);
if (ret)
return ret;
}
return 0; return 0;
} }
...@@ -1530,7 +2100,9 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1530,7 +2100,9 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
p = bufpoi + data_col_addr; p = bufpoi + data_col_addr;
chip->read_buf(mtd, p, datafrag_len); ret = nand_read_data_op(chip, p, datafrag_len, false);
if (ret)
return ret;
/* Calculate ECC */ /* Calculate ECC */
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
...@@ -1548,8 +2120,11 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1548,8 +2120,11 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
gaps = 1; gaps = 1;
if (gaps) { if (gaps) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); ret = nand_change_read_column_op(chip, mtd->writesize,
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->oob_poi, mtd->oobsize,
false);
if (ret)
return ret;
} else { } else {
/* /*
* Send the command to read the particular ECC bytes take care * Send the command to read the particular ECC bytes take care
...@@ -1563,9 +2138,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1563,9 +2138,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
(busw - 1)) (busw - 1))
aligned_len++; aligned_len++;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, ret = nand_change_read_column_op(chip,
mtd->writesize + aligned_pos, -1); mtd->writesize + aligned_pos,
chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); &chip->oob_poi[aligned_pos],
aligned_len, false);
if (ret)
return ret;
} }
ret = mtd_ooblayout_get_eccbytes(mtd, chip->buffers->ecccode, ret = mtd_ooblayout_get_eccbytes(mtd, chip->buffers->ecccode,
...@@ -1622,10 +2200,17 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1622,10 +2200,17 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_READ); chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
chip->ecc.calculate(mtd, p, &ecc_calc[i]); chip->ecc.calculate(mtd, p, &ecc_calc[i]);
} }
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
if (ret)
return ret;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total); chip->ecc.total);
...@@ -1684,9 +2269,13 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, ...@@ -1684,9 +2269,13 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
/* Read the OOB area first */ /* Read the OOB area first */
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); if (ret)
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); return ret;
ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
return ret;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total); chip->ecc.total);
...@@ -1697,7 +2286,11 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, ...@@ -1697,7 +2286,11 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
int stat; int stat;
chip->ecc.hwctl(mtd, NAND_ECC_READ); chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
chip->ecc.calculate(mtd, p, &ecc_calc[i]); chip->ecc.calculate(mtd, p, &ecc_calc[i]);
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
...@@ -1734,7 +2327,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, ...@@ -1734,7 +2327,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) uint8_t *buf, int oob_required, int page)
{ {
int i, eccsize = chip->ecc.size; int ret, i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes; int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps;
int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad; int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
...@@ -1746,21 +2339,36 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1746,21 +2339,36 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int stat; int stat;
chip->ecc.hwctl(mtd, NAND_ECC_READ); chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
if (chip->ecc.prepad) { if (chip->ecc.prepad) {
chip->read_buf(mtd, oob, chip->ecc.prepad); ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
false);
if (ret)
return ret;
oob += chip->ecc.prepad; oob += chip->ecc.prepad;
} }
chip->ecc.hwctl(mtd, NAND_ECC_READSYN); chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
chip->read_buf(mtd, oob, eccbytes);
ret = nand_read_data_op(chip, oob, eccbytes, false);
if (ret)
return ret;
stat = chip->ecc.correct(mtd, p, oob, NULL); stat = chip->ecc.correct(mtd, p, oob, NULL);
oob += eccbytes; oob += eccbytes;
if (chip->ecc.postpad) { if (chip->ecc.postpad) {
chip->read_buf(mtd, oob, chip->ecc.postpad); ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
false);
if (ret)
return ret;
oob += chip->ecc.postpad; oob += chip->ecc.postpad;
} }
...@@ -1784,8 +2392,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1784,8 +2392,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
/* Calculate remaining oob bytes */ /* Calculate remaining oob bytes */
i = mtd->oobsize - (oob - chip->oob_poi); i = mtd->oobsize - (oob - chip->oob_poi);
if (i) if (i) {
chip->read_buf(mtd, oob, i); ret = nand_read_data_op(chip, oob, i, false);
if (ret)
return ret;
}
return max_bitflips; return max_bitflips;
} }
...@@ -1906,8 +2517,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, ...@@ -1906,8 +2517,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
__func__, buf); __func__, buf);
read_retry: read_retry:
if (nand_standard_page_accessors(&chip->ecc)) if (nand_standard_page_accessors(&chip->ecc)) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
break;
}
/* /*
* Now read the page into the buffer. Absent an error, * Now read the page into the buffer. Absent an error,
...@@ -2066,9 +2680,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -2066,9 +2680,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
*/ */
int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
} }
EXPORT_SYMBOL(nand_read_oob_std); EXPORT_SYMBOL(nand_read_oob_std);
...@@ -2086,25 +2698,43 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2086,25 +2698,43 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size; int eccsize = chip->ecc.size;
uint8_t *bufpoi = chip->oob_poi; uint8_t *bufpoi = chip->oob_poi;
int i, toread, sndrnd = 0, pos; int i, toread, sndrnd = 0, pos, ret;
ret = nand_read_page_op(chip, page, chip->ecc.size, NULL, 0);
if (ret)
return ret;
chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
for (i = 0; i < chip->ecc.steps; i++) { for (i = 0; i < chip->ecc.steps; i++) {
if (sndrnd) { if (sndrnd) {
int ret;
pos = eccsize + i * (eccsize + chunk); pos = eccsize + i * (eccsize + chunk);
if (mtd->writesize > 512) if (mtd->writesize > 512)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1); ret = nand_change_read_column_op(chip, pos,
NULL, 0,
false);
else else
chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page); ret = nand_read_page_op(chip, page, pos, NULL,
0);
if (ret)
return ret;
} else } else
sndrnd = 1; sndrnd = 1;
toread = min_t(int, length, chunk); toread = min_t(int, length, chunk);
chip->read_buf(mtd, bufpoi, toread);
ret = nand_read_data_op(chip, bufpoi, toread, false);
if (ret)
return ret;
bufpoi += toread; bufpoi += toread;
length -= toread; length -= toread;
} }
if (length > 0) if (length > 0) {
chip->read_buf(mtd, bufpoi, length); ret = nand_read_data_op(chip, bufpoi, length, false);
if (ret)
return ret;
}
return 0; return 0;
} }
...@@ -2118,18 +2748,8 @@ EXPORT_SYMBOL(nand_read_oob_syndrome); ...@@ -2118,18 +2748,8 @@ EXPORT_SYMBOL(nand_read_oob_syndrome);
*/ */
int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
{ {
int status = 0; return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
const uint8_t *buf = chip->oob_poi; mtd->oobsize);
int length = mtd->oobsize;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, buf, length);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
EXPORT_SYMBOL(nand_write_oob_std); EXPORT_SYMBOL(nand_write_oob_std);
...@@ -2145,7 +2765,7 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2145,7 +2765,7 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
{ {
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size, length = mtd->oobsize; int eccsize = chip->ecc.size, length = mtd->oobsize;
int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps; int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps;
const uint8_t *bufpoi = chip->oob_poi; const uint8_t *bufpoi = chip->oob_poi;
/* /*
...@@ -2159,7 +2779,10 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2159,7 +2779,10 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
} else } else
pos = eccsize; pos = eccsize;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); ret = nand_prog_page_begin_op(chip, page, pos, NULL, 0);
if (ret)
return ret;
for (i = 0; i < steps; i++) { for (i = 0; i < steps; i++) {
if (sndcmd) { if (sndcmd) {
if (mtd->writesize <= 512) { if (mtd->writesize <= 512) {
...@@ -2168,28 +2791,40 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2168,28 +2791,40 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
len = eccsize; len = eccsize;
while (len > 0) { while (len > 0) {
int num = min_t(int, len, 4); int num = min_t(int, len, 4);
chip->write_buf(mtd, (uint8_t *)&fill,
num); ret = nand_write_data_op(chip, &fill,
num, false);
if (ret)
return ret;
len -= num; len -= num;
} }
} else { } else {
pos = eccsize + i * (eccsize + chunk); pos = eccsize + i * (eccsize + chunk);
chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1); ret = nand_change_write_column_op(chip, pos,
NULL, 0,
false);
if (ret)
return ret;
} }
} else } else
sndcmd = 1; sndcmd = 1;
len = min_t(int, length, chunk); len = min_t(int, length, chunk);
chip->write_buf(mtd, bufpoi, len);
ret = nand_write_data_op(chip, bufpoi, len, false);
if (ret)
return ret;
bufpoi += len; bufpoi += len;
length -= len; length -= len;
} }
if (length > 0) if (length > 0) {
chip->write_buf(mtd, bufpoi, length); ret = nand_write_data_op(chip, bufpoi, length, false);
if (ret)
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return ret;
status = chip->waitfunc(mtd, chip); }
return status & NAND_STATUS_FAIL ? -EIO : 0; return nand_prog_page_end_op(chip);
} }
EXPORT_SYMBOL(nand_write_oob_syndrome); EXPORT_SYMBOL(nand_write_oob_syndrome);
...@@ -2341,9 +2976,18 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -2341,9 +2976,18 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page) const uint8_t *buf, int oob_required, int page)
{ {
chip->write_buf(mtd, buf, mtd->writesize); int ret;
if (oob_required)
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); ret = nand_write_data_op(chip, buf, mtd->writesize, false);
if (ret)
return ret;
if (oob_required) {
ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize,
false);
if (ret)
return ret;
}
return 0; return 0;
} }
...@@ -2367,29 +3011,46 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd, ...@@ -2367,29 +3011,46 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
int eccsize = chip->ecc.size; int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes; int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi; uint8_t *oob = chip->oob_poi;
int steps, size; int steps, size, ret;
for (steps = chip->ecc.steps; steps > 0; steps--) { for (steps = chip->ecc.steps; steps > 0; steps--) {
chip->write_buf(mtd, buf, eccsize); ret = nand_write_data_op(chip, buf, eccsize, false);
if (ret)
return ret;
buf += eccsize; buf += eccsize;
if (chip->ecc.prepad) { if (chip->ecc.prepad) {
chip->write_buf(mtd, oob, chip->ecc.prepad); ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
false);
if (ret)
return ret;
oob += chip->ecc.prepad; oob += chip->ecc.prepad;
} }
chip->write_buf(mtd, oob, eccbytes); ret = nand_write_data_op(chip, oob, eccbytes, false);
if (ret)
return ret;
oob += eccbytes; oob += eccbytes;
if (chip->ecc.postpad) { if (chip->ecc.postpad) {
chip->write_buf(mtd, oob, chip->ecc.postpad); ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
false);
if (ret)
return ret;
oob += chip->ecc.postpad; oob += chip->ecc.postpad;
} }
} }
size = mtd->oobsize - (oob - chip->oob_poi); size = mtd->oobsize - (oob - chip->oob_poi);
if (size) if (size) {
chip->write_buf(mtd, oob, size); ret = nand_write_data_op(chip, oob, size, false);
if (ret)
return ret;
}
return 0; return 0;
} }
...@@ -2443,7 +3104,11 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2443,7 +3104,11 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE); chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
ret = nand_write_data_op(chip, p, eccsize, false);
if (ret)
return ret;
chip->ecc.calculate(mtd, p, &ecc_calc[i]); chip->ecc.calculate(mtd, p, &ecc_calc[i]);
} }
...@@ -2452,7 +3117,9 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2452,7 +3117,9 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
if (ret) if (ret)
return ret; return ret;
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
if (ret)
return ret;
return 0; return 0;
} }
...@@ -2488,7 +3155,9 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, ...@@ -2488,7 +3155,9 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
chip->ecc.hwctl(mtd, NAND_ECC_WRITE); chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
/* write data (untouched subpages already masked by 0xFF) */ /* write data (untouched subpages already masked by 0xFF) */
chip->write_buf(mtd, buf, ecc_size); ret = nand_write_data_op(chip, buf, ecc_size, false);
if (ret)
return ret;
/* mask ECC of un-touched subpages by padding 0xFF */ /* mask ECC of un-touched subpages by padding 0xFF */
if ((step < start_step) || (step > end_step)) if ((step < start_step) || (step > end_step))
...@@ -2515,7 +3184,9 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, ...@@ -2515,7 +3184,9 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
return ret; return ret;
/* write OOB buffer to NAND device */ /* write OOB buffer to NAND device */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
if (ret)
return ret;
return 0; return 0;
} }
...@@ -2542,31 +3213,49 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, ...@@ -2542,31 +3213,49 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps;
const uint8_t *p = buf; const uint8_t *p = buf;
uint8_t *oob = chip->oob_poi; uint8_t *oob = chip->oob_poi;
int ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE); chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
ret = nand_write_data_op(chip, p, eccsize, false);
if (ret)
return ret;
if (chip->ecc.prepad) { if (chip->ecc.prepad) {
chip->write_buf(mtd, oob, chip->ecc.prepad); ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
false);
if (ret)
return ret;
oob += chip->ecc.prepad; oob += chip->ecc.prepad;
} }
chip->ecc.calculate(mtd, p, oob); chip->ecc.calculate(mtd, p, oob);
chip->write_buf(mtd, oob, eccbytes);
ret = nand_write_data_op(chip, oob, eccbytes, false);
if (ret)
return ret;
oob += eccbytes; oob += eccbytes;
if (chip->ecc.postpad) { if (chip->ecc.postpad) {
chip->write_buf(mtd, oob, chip->ecc.postpad); ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
false);
if (ret)
return ret;
oob += chip->ecc.postpad; oob += chip->ecc.postpad;
} }
} }
/* Calculate remaining oob bytes */ /* Calculate remaining oob bytes */
i = mtd->oobsize - (oob - chip->oob_poi); i = mtd->oobsize - (oob - chip->oob_poi);
if (i) if (i) {
chip->write_buf(mtd, oob, i); ret = nand_write_data_op(chip, oob, i, false);
if (ret)
return ret;
}
return 0; return 0;
} }
...@@ -2594,8 +3283,11 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2594,8 +3283,11 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
else else
subpage = 0; subpage = 0;
if (nand_standard_page_accessors(&chip->ecc)) if (nand_standard_page_accessors(&chip->ecc)) {
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); status = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (status)
return status;
}
if (unlikely(raw)) if (unlikely(raw))
status = chip->ecc.write_page_raw(mtd, chip, buf, status = chip->ecc.write_page_raw(mtd, chip, buf,
...@@ -2610,13 +3302,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2610,13 +3302,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (status < 0) if (status < 0)
return status; return status;
if (nand_standard_page_accessors(&chip->ecc)) { if (nand_standard_page_accessors(&chip->ecc))
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
}
return 0; return 0;
} }
...@@ -2989,17 +3676,12 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -2989,17 +3676,12 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
static int single_erase(struct mtd_info *mtd, int page) static int single_erase(struct mtd_info *mtd, int page)
{ {
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
int status; unsigned int eraseblock;
/* Send commands to erase a block */ /* Send commands to erase a block */
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); eraseblock = page >> (chip->phys_erase_shift - chip->page_shift);
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
status = chip->waitfunc(mtd, chip); return nand_erase_op(chip, eraseblock);
if (status < 0)
return status;
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/** /**
...@@ -3226,22 +3908,12 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) ...@@ -3226,22 +3908,12 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param) int addr, uint8_t *subfeature_param)
{ {
int status;
int i;
if (!chip->onfi_version || if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd) !(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES)) & ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL; return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); return nand_set_features_op(chip, addr, subfeature_param);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
chip->write_byte(mtd, subfeature_param[i]);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
} }
/** /**
...@@ -3254,17 +3926,12 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -3254,17 +3926,12 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param) int addr, uint8_t *subfeature_param)
{ {
int i;
if (!chip->onfi_version || if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd) !(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES)) & ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL; return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); return nand_get_features_op(chip, addr, subfeature_param);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
*subfeature_param++ = chip->read_byte(mtd);
return 0;
} }
/** /**
...@@ -3407,12 +4074,11 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) ...@@ -3407,12 +4074,11 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
static int nand_flash_detect_ext_param_page(struct nand_chip *chip, static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
struct nand_onfi_params *p) struct nand_onfi_params *p)
{ {
struct mtd_info *mtd = nand_to_mtd(chip);
struct onfi_ext_param_page *ep; struct onfi_ext_param_page *ep;
struct onfi_ext_section *s; struct onfi_ext_section *s;
struct onfi_ext_ecc_info *ecc; struct onfi_ext_ecc_info *ecc;
uint8_t *cursor; uint8_t *cursor;
int ret = -EINVAL; int ret;
int len; int len;
int i; int i;
...@@ -3422,14 +4088,18 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip, ...@@ -3422,14 +4088,18 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
return -ENOMEM; return -ENOMEM;
/* Send our own NAND_CMD_PARAM. */ /* Send our own NAND_CMD_PARAM. */
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); ret = nand_read_param_page_op(chip, 0, NULL, 0);
if (ret)
goto ext_out;
/* Use the Change Read Column command to skip the ONFI param pages. */ /* Use the Change Read Column command to skip the ONFI param pages. */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, ret = nand_change_read_column_op(chip,
sizeof(*p) * p->num_of_param_pages , -1); sizeof(*p) * p->num_of_param_pages,
ep, len, true);
if (ret)
goto ext_out;
/* Read out the Extended Parameter Page. */ ret = -EINVAL;
chip->read_buf(mtd, (uint8_t *)ep, len);
if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
!= le16_to_cpu(ep->crc))) { != le16_to_cpu(ep->crc))) {
pr_debug("fail in the CRC.\n"); pr_debug("fail in the CRC.\n");
...@@ -3482,19 +4152,23 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) ...@@ -3482,19 +4152,23 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p = &chip->onfi_params; struct nand_onfi_params *p = &chip->onfi_params;
int i, j; char id[4];
int val; int i, ret, val;
/* Try ONFI for unknown chip or LP */ /* Try ONFI for unknown chip or LP */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); ret = nand_readid_op(chip, 0x20, id, sizeof(id));
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || if (ret || strncmp(id, "ONFI", 4))
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') return 0;
ret = nand_read_param_page_op(chip, 0, NULL, 0);
if (ret)
return 0; return 0;
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
for (j = 0; j < sizeof(*p); j++) ret = nand_read_data_op(chip, p, sizeof(*p), true);
((uint8_t *)p)[j] = chip->read_byte(mtd); if (ret)
return 0;
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
le16_to_cpu(p->crc)) { le16_to_cpu(p->crc)) {
break; break;
...@@ -3585,20 +4259,22 @@ static int nand_flash_detect_jedec(struct nand_chip *chip) ...@@ -3585,20 +4259,22 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_jedec_params *p = &chip->jedec_params; struct nand_jedec_params *p = &chip->jedec_params;
struct jedec_ecc_info *ecc; struct jedec_ecc_info *ecc;
int val; char id[5];
int i, j; int i, val, ret;
/* Try JEDEC for unknown chip or LP */ /* Try JEDEC for unknown chip or LP */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1); ret = nand_readid_op(chip, 0x40, id, sizeof(id));
if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' || if (ret || strncmp(id, "JEDEC", sizeof(id)))
chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' || return 0;
chip->read_byte(mtd) != 'C')
ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
if (ret)
return 0; return 0;
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
for (j = 0; j < sizeof(*p); j++) ret = nand_read_data_op(chip, p, sizeof(*p), true);
((uint8_t *)p)[j] = chip->read_byte(mtd); if (ret)
return 0;
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) == if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
le16_to_cpu(p->crc)) le16_to_cpu(p->crc))
...@@ -3877,8 +4553,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) ...@@ -3877,8 +4553,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
{ {
const struct nand_manufacturer *manufacturer; const struct nand_manufacturer *manufacturer;
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
int busw; int busw, ret;
int i;
u8 *id_data = chip->id.data; u8 *id_data = chip->id.data;
u8 maf_id, dev_id; u8 maf_id, dev_id;
...@@ -3886,17 +4561,21 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) ...@@ -3886,17 +4561,21 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up. * after power-up.
*/ */
nand_reset(chip, 0); ret = nand_reset(chip, 0);
if (ret)
return ret;
/* Select the device */ /* Select the device */
chip->select_chip(mtd, 0); chip->select_chip(mtd, 0);
/* Send the command for reading device ID */ /* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); ret = nand_readid_op(chip, 0, id_data, 2);
if (ret)
return ret;
/* Read manufacturer and device IDs */ /* Read manufacturer and device IDs */
maf_id = chip->read_byte(mtd); maf_id = id_data[0];
dev_id = chip->read_byte(mtd); dev_id = id_data[1];
/* /*
* Try again to make sure, as some systems the bus-hold or other * Try again to make sure, as some systems the bus-hold or other
...@@ -3905,11 +4584,10 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) ...@@ -3905,11 +4584,10 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
* not match, ignore the device completely. * not match, ignore the device completely.
*/ */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read entire ID string */ /* Read entire ID string */
for (i = 0; i < ARRAY_SIZE(chip->id.data); i++) ret = nand_readid_op(chip, 0, id_data, sizeof(chip->id.data));
id_data[i] = chip->read_byte(mtd); if (ret)
return ret;
if (id_data[0] != maf_id || id_data[1] != dev_id) { if (id_data[0] != maf_id || id_data[1] != dev_id) {
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n", pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
...@@ -4236,15 +4914,16 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, ...@@ -4236,15 +4914,16 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
/* Check for a chip array */ /* Check for a chip array */
for (i = 1; i < maxchips; i++) { for (i = 1; i < maxchips; i++) {
u8 id[2];
/* See comment in nand_get_flash_type for reset */ /* See comment in nand_get_flash_type for reset */
nand_reset(chip, i); nand_reset(chip, i);
chip->select_chip(mtd, i); chip->select_chip(mtd, i);
/* Send the command for reading device ID */ /* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); nand_readid_op(chip, 0, id, sizeof(id));
/* Read manufacturer and device IDs */ /* Read manufacturer and device IDs */
if (nand_maf_id != chip->read_byte(mtd) || if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
nand_dev_id != chip->read_byte(mtd)) {
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
break; break;
} }
......
...@@ -66,16 +66,35 @@ struct hynix_read_retry_otp { ...@@ -66,16 +66,35 @@ struct hynix_read_retry_otp {
}; };
static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip) static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
{
u8 jedecid[5] = { };
int ret;
ret = nand_readid_op(chip, 0x40, jedecid, sizeof(jedecid));
if (ret)
return false;
return !strncmp("JEDEC", jedecid, sizeof(jedecid));
}
static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
{
struct mtd_info *mtd = nand_to_mtd(chip);
chip->cmdfunc(mtd, cmd, -1, -1);
return 0;
}
static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
u8 jedecid[6] = { }; u16 column = ((u16)addr << 8) | addr;
int i = 0;
chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1); chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
for (i = 0; i < 5; i++) chip->write_byte(mtd, val);
jedecid[i] = chip->read_byte(mtd);
return !strcmp("JEDEC", jedecid); return 0;
} }
static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
...@@ -83,13 +102,15 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) ...@@ -83,13 +102,15 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
struct hynix_nand *hynix = nand_get_manufacturer_data(chip); struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
const u8 *values; const u8 *values;
int i; int i, ret;
values = hynix->read_retry->values + values = hynix->read_retry->values +
(retry_mode * hynix->read_retry->nregs); (retry_mode * hynix->read_retry->nregs);
/* Enter 'Set Hynix Parameters' mode */ /* Enter 'Set Hynix Parameters' mode */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1); ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
if (ret)
return ret;
/* /*
* Configure the NAND in the requested read-retry mode. * Configure the NAND in the requested read-retry mode.
...@@ -101,17 +122,14 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) ...@@ -101,17 +122,14 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
* probably tweaked at production in this case). * probably tweaked at production in this case).
*/ */
for (i = 0; i < hynix->read_retry->nregs; i++) { for (i = 0; i < hynix->read_retry->nregs; i++) {
int column = hynix->read_retry->regs[i]; ret = hynix_nand_reg_write_op(chip, hynix->read_retry->regs[i],
values[i]);
column |= column << 8; if (ret)
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1); return ret;
chip->write_byte(mtd, values[i]);
} }
/* Apply the new settings. */ /* Apply the new settings. */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1); return hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
return 0;
} }
/** /**
...@@ -167,40 +185,63 @@ static int hynix_read_rr_otp(struct nand_chip *chip, ...@@ -167,40 +185,63 @@ static int hynix_read_rr_otp(struct nand_chip *chip,
const struct hynix_read_retry_otp *info, const struct hynix_read_retry_otp *info,
void *buf) void *buf)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); int i, ret;
int i;
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); ret = nand_reset_op(chip);
if (ret)
return ret;
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1); ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
if (ret)
return ret;
for (i = 0; i < info->nregs; i++) { for (i = 0; i < info->nregs; i++) {
int column = info->regs[i]; ret = hynix_nand_reg_write_op(chip, info->regs[i],
info->values[i]);
column |= column << 8; if (ret)
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1); return ret;
chip->write_byte(mtd, info->values[i]);
} }
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1); ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
if (ret)
return ret;
/* Sequence to enter OTP mode? */ /* Sequence to enter OTP mode? */
chip->cmdfunc(mtd, 0x17, -1, -1); ret = hynix_nand_cmd_op(chip, 0x17);
chip->cmdfunc(mtd, 0x04, -1, -1); if (ret)
chip->cmdfunc(mtd, 0x19, -1, -1); return ret;
ret = hynix_nand_cmd_op(chip, 0x4);
if (ret)
return ret;
ret = hynix_nand_cmd_op(chip, 0x19);
if (ret)
return ret;
/* Now read the page */ /* Now read the page */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, info->page); ret = nand_read_page_op(chip, info->page, 0, buf, info->size);
chip->read_buf(mtd, buf, info->size); if (ret)
return ret;
/* Put everything back to normal */ /* Put everything back to normal */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); ret = nand_reset_op(chip);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, 0x38, -1); if (ret)
chip->write_byte(mtd, 0x0); return ret;
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, -1);
return 0; ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
if (ret)
return ret;
ret = hynix_nand_reg_write_op(chip, 0x38, 0);
if (ret)
return ret;
ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
if (ret)
return ret;
return nand_read_page_op(chip, 0, 0, NULL, 0);
} }
#define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0 #define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0
......
...@@ -117,16 +117,28 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -117,16 +117,28 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, uint8_t *buf, int oob_required,
int page) int page)
{ {
int status; u8 status;
int max_bitflips = 0; int ret, max_bitflips = 0;
micron_nand_on_die_ecc_setup(chip, true); ret = micron_nand_on_die_ecc_setup(chip, true);
if (ret)
return ret;
ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
goto out;
ret = nand_status_op(chip, &status);
if (ret)
goto out;
ret = nand_exit_status_op(chip);
if (ret)
goto out;
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
status = chip->read_byte(mtd);
if (status & NAND_STATUS_FAIL) if (status & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++; mtd->ecc_stats.failed++;
/* /*
* The internal ECC doesn't tell us the number of bitflips * The internal ECC doesn't tell us the number of bitflips
* that have been corrected, but tells us if it recommends to * that have been corrected, but tells us if it recommends to
...@@ -137,13 +149,12 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -137,13 +149,12 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
else if (status & NAND_STATUS_WRITE_RECOMMENDED) else if (status & NAND_STATUS_WRITE_RECOMMENDED)
max_bitflips = chip->ecc.strength; max_bitflips = chip->ecc.strength;
chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1); ret = nand_read_page_raw(mtd, chip, buf, oob_required, page);
nand_read_page_raw(mtd, chip, buf, oob_required, page);
out:
micron_nand_on_die_ecc_setup(chip, false); micron_nand_on_die_ecc_setup(chip, false);
return max_bitflips; return ret ? ret : max_bitflips;
} }
static int static int
...@@ -151,18 +162,26 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -151,18 +162,26 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, const uint8_t *buf, int oob_required,
int page) int page)
{ {
int status; int ret;
micron_nand_on_die_ecc_setup(chip, true); ret = micron_nand_on_die_ecc_setup(chip, true);
if (ret)
return ret;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
nand_write_page_raw(mtd, chip, buf, oob_required, page); if (ret)
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); goto out;
status = chip->waitfunc(mtd, chip);
ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
if (ret)
return ret;
ret = nand_prog_page_end_op(chip);
out:
micron_nand_on_die_ecc_setup(chip, false); micron_nand_on_die_ecc_setup(chip, false);
return status & NAND_STATUS_FAIL ? -EIO : 0; return ret;
} }
static int static int
...@@ -171,10 +190,13 @@ micron_nand_read_page_raw_on_die_ecc(struct mtd_info *mtd, ...@@ -171,10 +190,13 @@ micron_nand_read_page_raw_on_die_ecc(struct mtd_info *mtd,
uint8_t *buf, int oob_required, uint8_t *buf, int oob_required,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); int ret;
nand_read_page_raw(mtd, chip, buf, oob_required, page);
return 0; ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
return ret;
return nand_read_page_raw(mtd, chip, buf, oob_required, page);
} }
static int static int
...@@ -183,14 +205,17 @@ micron_nand_write_page_raw_on_die_ecc(struct mtd_info *mtd, ...@@ -183,14 +205,17 @@ micron_nand_write_page_raw_on_die_ecc(struct mtd_info *mtd,
const uint8_t *buf, int oob_required, const uint8_t *buf, int oob_required,
int page) int page)
{ {
int status; int ret;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
nand_write_page_raw(mtd, chip, buf, oob_required, page); if (ret)
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return ret;
status = chip->waitfunc(mtd, chip);
ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
if (ret)
return ret;
return status & NAND_STATUS_FAIL ? -EIO : 0; return nand_prog_page_end_op(chip);
} }
enum { enum {
......
...@@ -1647,10 +1647,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1647,10 +1647,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, buf, mtd->writesize);
/* Read oob bytes */ /* Read oob bytes */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(chip,
mtd->writesize + BADBLOCK_MARKER_LENGTH, -1); mtd->writesize + BADBLOCK_MARKER_LENGTH,
chip->read_buf(mtd, chip->oob_poi + BADBLOCK_MARKER_LENGTH, chip->oob_poi + BADBLOCK_MARKER_LENGTH,
chip->ecc.total); chip->ecc.total, false);
/* Calculate ecc bytes */ /* Calculate ecc bytes */
omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc); omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
......
...@@ -520,15 +520,13 @@ static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host, ...@@ -520,15 +520,13 @@ static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct pxa3xx_nand_info *info = host->info_data; struct pxa3xx_nand_info *info = host->info_data;
const struct pxa3xx_nand_flash *f = NULL; const struct pxa3xx_nand_flash *f = NULL;
struct mtd_info *mtd = nand_to_mtd(&host->chip);
int i, id, ntypes; int i, id, ntypes;
u8 idbuf[2];
ntypes = ARRAY_SIZE(builtin_flash_types); ntypes = ARRAY_SIZE(builtin_flash_types);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); nand_readid_op(chip, 0, idbuf, sizeof(idbuf));
id = idbuf[0] | (idbuf[1] << 8);
id = chip->read_byte(mtd);
id |= chip->read_byte(mtd) << 0x8;
for (i = 0; i < ntypes; i++) { for (i = 0; i < ntypes; i++) {
f = &builtin_flash_types[i]; f = &builtin_flash_types[i];
......
...@@ -1990,7 +1990,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1990,7 +1990,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_ecc_ctrl *ecc = &chip->ecc;
u8 *oob = chip->oob_poi; u8 *oob = chip->oob_poi;
int data_size, oob_size; int data_size, oob_size;
int ret, status = 0; int ret;
host->use_ecc = true; host->use_ecc = true;
...@@ -2027,11 +2027,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2027,11 +2027,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return -EIO; return -EIO;
} }
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs) static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
...@@ -2081,7 +2077,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -2081,7 +2077,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_ecc_ctrl *ecc = &chip->ecc;
int page, ret, status = 0; int page, ret;
clear_read_regs(nandc); clear_read_regs(nandc);
clear_bam_transaction(nandc); clear_bam_transaction(nandc);
...@@ -2114,11 +2110,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -2114,11 +2110,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
return -EIO; return -EIO;
} }
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* /*
......
...@@ -364,7 +364,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -364,7 +364,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
struct r852_device *dev = nand_get_controller_data(chip); struct r852_device *dev = nand_get_controller_data(chip);
unsigned long timeout; unsigned long timeout;
int status; u8 status;
timeout = jiffies + (chip->state == FL_ERASING ? timeout = jiffies + (chip->state == FL_ERASING ?
msecs_to_jiffies(400) : msecs_to_jiffies(20)); msecs_to_jiffies(400) : msecs_to_jiffies(20));
...@@ -373,8 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -373,8 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
if (chip->dev_ready(mtd)) if (chip->dev_ready(mtd))
break; break;
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(chip, &status);
status = (int)chip->read_byte(mtd);
/* Unfortunelly, no way to send detailed error status... */ /* Unfortunelly, no way to send detailed error status... */
if (dev->dma_error) { if (dev->dma_error) {
...@@ -522,9 +521,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, ...@@ -522,9 +521,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
} }
/* /*
...@@ -1046,7 +1043,7 @@ static int r852_resume(struct device *device) ...@@ -1046,7 +1043,7 @@ static int r852_resume(struct device *device)
if (dev->card_registred) { if (dev->card_registred) {
r852_engine_enable(dev); r852_engine_enable(dev);
dev->chip->select_chip(mtd, 0); dev->chip->select_chip(mtd, 0);
dev->chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(dev->chip);
dev->chip->select_chip(mtd, -1); dev->chip->select_chip(mtd, -1);
} }
......
...@@ -958,12 +958,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, ...@@ -958,12 +958,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
int ret; int ret;
if (*cur_off != data_off) if (*cur_off != data_off)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); nand_change_read_column_op(nand, data_off, NULL, 0, false);
sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page); sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
if (data_off + ecc->size != oob_off) if (data_off + ecc->size != oob_off)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); nand_change_read_column_op(nand, oob_off, NULL, 0, false);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret) if (ret)
...@@ -991,16 +991,15 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, ...@@ -991,16 +991,15 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
* Re-read the data with the randomizer disabled to identify * Re-read the data with the randomizer disabled to identify
* bitflips in erased pages. * bitflips in erased pages.
*/ */
if (nand->options & NAND_NEED_SCRAMBLING) { if (nand->options & NAND_NEED_SCRAMBLING)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); nand_change_read_column_op(nand, data_off, data,
nand->read_buf(mtd, data, ecc->size); ecc->size, false);
} else { else
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
ecc->size); ecc->size);
}
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4,
nand->read_buf(mtd, oob, ecc->bytes + 4); false);
ret = nand_check_erased_ecc_chunk(data, ecc->size, ret = nand_check_erased_ecc_chunk(data, ecc->size,
oob, ecc->bytes + 4, oob, ecc->bytes + 4,
...@@ -1011,7 +1010,8 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, ...@@ -1011,7 +1010,8 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
if (oob_required) { if (oob_required) {
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); nand_change_read_column_op(nand, oob_off, NULL, 0,
false);
sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
true, page); true, page);
...@@ -1038,8 +1038,8 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, ...@@ -1038,8 +1038,8 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
return; return;
if (!cur_off || *cur_off != offset) if (!cur_off || *cur_off != offset)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
offset + mtd->writesize, -1); false);
if (!randomize) if (!randomize)
sunxi_nfc_read_buf(mtd, oob + offset, len); sunxi_nfc_read_buf(mtd, oob + offset, len);
...@@ -1116,9 +1116,9 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf, ...@@ -1116,9 +1116,9 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
if (oob_required && !erased) { if (oob_required && !erased) {
/* TODO: use DMA to retrieve OOB */ /* TODO: use DMA to retrieve OOB */
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(nand,
mtd->writesize + oob_off, -1); mtd->writesize + oob_off,
nand->read_buf(mtd, oob, ecc->bytes + 4); oob, ecc->bytes + 4, false);
sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i, sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
!i, page); !i, page);
...@@ -1143,18 +1143,17 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf, ...@@ -1143,18 +1143,17 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
/* /*
* Re-read the data with the randomizer disabled to * Re-read the data with the randomizer disabled to
* identify bitflips in erased pages. * identify bitflips in erased pages.
* TODO: use DMA to read page in raw mode
*/ */
if (randomized) { if (randomized)
/* TODO: use DMA to read page in raw mode */ nand_change_read_column_op(nand, data_off,
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data, ecc->size,
data_off, -1); false);
nand->read_buf(mtd, data, ecc->size);
}
/* TODO: use DMA to retrieve OOB */ /* TODO: use DMA to retrieve OOB */
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(nand,
mtd->writesize + oob_off, -1); mtd->writesize + oob_off,
nand->read_buf(mtd, oob, ecc->bytes + 4); oob, ecc->bytes + 4, false);
ret = nand_check_erased_ecc_chunk(data, ecc->size, ret = nand_check_erased_ecc_chunk(data, ecc->size,
oob, ecc->bytes + 4, oob, ecc->bytes + 4,
...@@ -1187,12 +1186,12 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, ...@@ -1187,12 +1186,12 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
int ret; int ret;
if (data_off != *cur_off) if (data_off != *cur_off)
nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); nand_change_write_column_op(nand, data_off, NULL, 0, false);
sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page); sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
if (data_off + ecc->size != oob_off) if (data_off + ecc->size != oob_off)
nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1); nand_change_write_column_op(nand, oob_off, NULL, 0, false);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret) if (ret)
...@@ -1228,8 +1227,8 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, ...@@ -1228,8 +1227,8 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
return; return;
if (!cur_off || *cur_off != offset) if (!cur_off || *cur_off != offset)
nand->cmdfunc(mtd, NAND_CMD_RNDIN, nand_change_write_column_op(nand, offset + mtd->writesize,
offset + mtd->writesize, -1); NULL, 0, false);
sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page); sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
...@@ -1285,7 +1284,7 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd, ...@@ -1285,7 +1284,7 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
return ret; return ret;
/* Fallback to PIO mode */ /* Fallback to PIO mode */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); nand_change_read_column_op(chip, 0, NULL, 0, false);
return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page); return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
} }
...@@ -1335,7 +1334,7 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd, ...@@ -1335,7 +1334,7 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
return ret; return ret;
/* Fallback to PIO mode */ /* Fallback to PIO mode */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); nand_change_read_column_op(chip, 0, NULL, 0, false);
return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen, return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
buf, page); buf, page);
...@@ -1540,7 +1539,7 @@ static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd, ...@@ -1540,7 +1539,7 @@ static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd,
struct nand_chip *chip, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
chip->pagebuf = -1; chip->pagebuf = -1;
...@@ -1551,9 +1550,9 @@ static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd, ...@@ -1551,9 +1550,9 @@ static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
struct nand_chip *chip, struct nand_chip *chip,
int page) int page)
{ {
int ret, status; int ret;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
chip->pagebuf = -1; chip->pagebuf = -1;
...@@ -1563,11 +1562,7 @@ static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd, ...@@ -1563,11 +1562,7 @@ static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
return ret; return ret;
/* Send command to program the OOB data */ /* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
static const s32 tWB_lut[] = {6, 12, 16, 20}; static const s32 tWB_lut[] = {6, 12, 16, 20};
......
...@@ -329,7 +329,7 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) ...@@ -329,7 +329,7 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
if (!*buf) { if (!*buf) {
/* skip over "len" bytes */ /* skip over "len" bytes */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1); nand_change_read_column_op(chip, *pos, NULL, 0, false);
} else { } else {
tango_read_buf(mtd, *buf, len); tango_read_buf(mtd, *buf, len);
*buf += len; *buf += len;
...@@ -344,7 +344,7 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) ...@@ -344,7 +344,7 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
if (!*buf) { if (!*buf) {
/* skip over "len" bytes */ /* skip over "len" bytes */
chip->cmdfunc(mtd, NAND_CMD_RNDIN, *pos, -1); nand_change_write_column_op(chip, *pos, NULL, 0, false);
} else { } else {
tango_write_buf(mtd, *buf, len); tango_write_buf(mtd, *buf, len);
*buf += len; *buf += len;
...@@ -427,7 +427,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) ...@@ -427,7 +427,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf, int oob_required, int page) u8 *buf, int oob_required, int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, buf, chip->oob_poi); raw_read(chip, buf, chip->oob_poi);
return 0; return 0;
} }
...@@ -435,23 +435,15 @@ static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -435,23 +435,15 @@ static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const u8 *buf, int oob_required, int page) const u8 *buf, int oob_required, int page)
{ {
int status; nand_prog_page_begin_op(chip, page, 0, NULL, 0);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
raw_write(chip, buf, chip->oob_poi); raw_write(chip, buf, chip->oob_poi);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
} }
static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, NULL, chip->oob_poi); raw_read(chip, NULL, chip->oob_poi);
return 0; return 0;
} }
...@@ -459,11 +451,9 @@ static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -459,11 +451,9 @@ static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, NULL, chip->oob_poi); raw_write(chip, NULL, chip->oob_poi);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
chip->waitfunc(mtd, chip);
return 0;
} }
static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res) static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
......
...@@ -192,6 +192,7 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) ...@@ -192,6 +192,7 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
{ {
struct tmio_nand *tmio = mtd_to_tmio(mtd); struct tmio_nand *tmio = mtd_to_tmio(mtd);
long timeout; long timeout;
u8 status;
/* enable RDYREQ interrupt */ /* enable RDYREQ interrupt */
tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
...@@ -212,8 +213,8 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) ...@@ -212,8 +213,8 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n"); dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
} }
nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(nand_chip, &status);
return nand_chip->read_byte(mtd); return status;
} }
/* /*
......
...@@ -1316,6 +1316,35 @@ int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1316,6 +1316,35 @@ int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
/* Reset and initialize a NAND device */ /* Reset and initialize a NAND device */
int nand_reset(struct nand_chip *chip, int chipnr); int nand_reset(struct nand_chip *chip, int chipnr);
/* NAND operation helpers */
int nand_reset_op(struct nand_chip *chip);
int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
unsigned int len);
int nand_status_op(struct nand_chip *chip, u8 *status);
int nand_exit_status_op(struct nand_chip *chip);
int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock);
int nand_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf, unsigned int len);
int nand_change_read_column_op(struct nand_chip *chip,
unsigned int offset_in_page, void *buf,
unsigned int len, bool force_8bit);
int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf, unsigned int len);
int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, const void *buf,
unsigned int len);
int nand_prog_page_end_op(struct nand_chip *chip);
int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, const void *buf,
unsigned int len);
int nand_change_write_column_op(struct nand_chip *chip,
unsigned int offset_in_page, const void *buf,
unsigned int len, bool force_8bit);
int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
bool force_8bit);
int nand_write_data_op(struct nand_chip *chip, const void *buf,
unsigned int len, bool force_8bit);
/* Free resources held by the NAND device */ /* Free resources held by the NAND device */
void nand_cleanup(struct nand_chip *chip); void nand_cleanup(struct nand_chip *chip);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment