[PATCH] nand_base fix for 2k page chips
Vitaly Wool
vwool at ru.mvista.com
Tue May 23 05:17:25 EDT 2006
Folks,
given that a) layouts stuff is not yet accepted, b) I somehow need to make my NAND driver work and c) I want it to be in sync with mainline, I made an attempt to fix (data, oob, ecc) x4 handling for 2k page NAND devices. I appreciate very much if you take a look at that before I commit it to my tree and start bugging dwmw2 to fetch it from there :)
Vitaly
Index: mtd/drivers/mtd/nand/nand_base.c
===================================================================
--- mtd.orig/drivers/mtd/nand/nand_base.c
+++ mtd/drivers/mtd/nand/nand_base.c
@@ -905,26 +905,25 @@ static int nand_write_page(struct mtd_in
default:
eccbytes = this->eccbytes;
for (; eccsteps; eccsteps--) {
+ int oobofs = mtd->oobsize / this->eccsteps * (this->eccsteps - eccsteps);
/* enable hardware ecc logic for write */
this->enable_hwecc(mtd, NAND_ECC_WRITE);
this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
- for (i = 0; i < eccbytes; i++, eccidx++)
- oob_buf[oob_config[eccidx]] = ecc_code[i];
+ for (i = 0, eccidx = 0; i < eccbytes; i++, eccidx++)
+ oob_buf[oobofs + oob_config[eccidx]] = ecc_code[i];
/* If the hardware ecc provides syndromes then
* the ecc code must be written immidiately after
* the data bytes (words) */
if (this->options & NAND_HWECC_SYNDROME)
- this->write_buf(mtd, ecc_code, eccbytes);
+ this->write_buf(mtd, &oob_buf[oobofs], mtd->oobsize / this->eccsteps);
datidx += this->eccsize;
}
break;
}
/* Write out OOB data */
- if (this->options & NAND_HWECC_SYNDROME)
- this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
- else
+ if (!(this->options & NAND_HWECC_SYNDROME))
this->write_buf(mtd, oob_buf, mtd->oobsize);
/* Send command to actually program the data */
@@ -1232,7 +1231,7 @@ int nand_do_read_ecc(struct mtd_info *mt
break;
default:
- for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
+ for (i = 0, j = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, j += mtd->oobsize / this->eccsteps, datidx += ecc) {
this->enable_hwecc(mtd, NAND_ECC_READ);
this->read_buf(mtd, &data_poi[datidx], ecc);
@@ -1242,11 +1241,11 @@ int nand_do_read_ecc(struct mtd_info *mt
/* Some hw ecc generators need to know when the
* syndrome is read from flash */
this->enable_hwecc(mtd, NAND_ECC_READSYN);
- this->read_buf(mtd, &oob_data[i], eccbytes);
+ this->read_buf(mtd, &oob_data[j], mtd->oobsize / this->eccsteps);
/* We calc error correction directly, it checks the hw
* generator for an error, reads back the syndrome and
* does the error correction on the fly */
- ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[j], &ecc_code[i]);
if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
@@ -1259,13 +1258,12 @@ int nand_do_read_ecc(struct mtd_info *mt
break;
}
- /* read oobdata */
- this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
-
/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
if (!compareecc)
goto readoob;
+ /* read oobdata */
+ this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
/* Pick the ECC bytes out of the oob data */
for (j = 0; j < oobsel->eccbytes; j++)
ecc_code[j] = oob_data[oob_config[j]];
@@ -1380,7 +1378,7 @@ int nand_do_read_ecc(struct mtd_info *mt
*/
static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
- int i, col, page, chipnr;
+ int i, col, page, chipnr, sndcmd = 1;
struct nand_chip *this = mtd->priv;
int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
@@ -1409,19 +1407,39 @@ static int nand_read_oob(struct mtd_info
/* Select the NAND device */
this->select_chip(mtd, chipnr);
- /* Send the read command */
- this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask);
/*
* Read the data, if we read more than one page
* oob data, let the device transfer the data !
*/
i = 0;
while (i < len) {
- int thislen = mtd->oobsize - col;
- thislen = min_t(int, thislen, len);
- this->read_buf(mtd, &buf[i], thislen);
- i += thislen;
+ if (this->options & NAND_HWECC_SYNDROME) {
+ int thislen;
+ int eccsteps = this->eccsteps;
+ for (; eccsteps; eccsteps--) {
+ int oobofs = (mtd->oobsize + mtd->oobblock) / this->eccsteps * (this->eccsteps - eccsteps) + this->eccsize;
+ if (col >= mtd->oobsize / this->eccsteps) {
+ col -= mtd->oobsize / this->eccsteps;
+ goto next;
+ }
+ this->cmdfunc (mtd, NAND_CMD_READ0, oobofs + col, page & this->pagemask);
+ thislen = min_t(int, mtd->oobsize / this->eccsteps - col, len);
+ this->read_buf(mtd, &buf[i], thislen);
+ i += thislen;
+ col = 0;
+ }
+ } else {
+ int thislen = mtd->oobsize - col;
+ thislen = min_t(int, thislen, len);
+ if (sndcmd) {
+ this->cmdfunc(mtd, NAND_CMD_READOOB, col, page &this->pagemask);
+ sndcmd = 0;
+ }
+ this->read_buf(mtd, &buf[i], thislen);
+ i += thislen;
+ }
+next:
/* Read more ? */
if (i < len) {
page++;
@@ -1447,10 +1465,8 @@ static int nand_read_oob(struct mtd_info
/* Check, if the chip supports auto page increment
* or if we have hit a block boundary.
*/
- if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
- /* For subsequent page reads set offset to 0 */
- this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
- }
+ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
+ sndcmd = 1;
}
}
@@ -1803,7 +1819,49 @@ static int nand_write_oob(struct mtd_inf
if (page == this->pagebuf)
this->pagebuf = -1;
- if (NAND_MUST_PAD(this)) {
+ if (this->options & NAND_HWECC_SYNDROME) {
+ int thislen, totlen = 0;
+ int eccsteps = this->eccsteps;
+ for (; eccsteps; eccsteps--) {
+ int oobofs = (mtd->oobsize + mtd->oobblock) / this->eccsteps * (this->eccsteps - eccsteps) + this->eccsize;
+ if (column >= mtd->oobsize / this->eccsteps) {
+ column -= mtd->oobsize / this->eccsteps;
+ continue;
+ }
+ if (NAND_MUST_PAD(this)) {
+ this->cmdfunc (mtd, NAND_CMD_SEQIN, oobofs, page & this->pagemask);
+ /* prepad 0xff for partial programming */
+ this->write_buf(mtd, ffchars, column);
+ thislen = min_t(int, mtd->oobsize / this->eccsteps - column, len);
+ this->write_buf(mtd, &buf[totlen], thislen);
+ totlen += thislen;
+ /* postpad 0xff for partial programming */
+ if (totlen == thislen)
+ this->write_buf(mtd, ffchars, mtd->oobsize / this->eccsteps - column - thislen);
+ column = 0;
+ } else {
+ this->cmdfunc (mtd, NAND_CMD_SEQIN, oobofs + column, page & this->pagemask);
+ thislen = min_t(int, mtd->oobsize / this->eccsteps - column, len);
+ this->write_buf(mtd, &buf[totlen], thislen);
+ totlen += thislen;
+ column = 0;
+ }
+ if (totlen == len)
+ break;
+ else {
+ /* Send command to program the OOB data */
+ this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = this->waitfunc(mtd, this, FL_WRITING);
+
+ /* See if device thinks it succeeded */
+ if (status & NAND_STATUS_FAIL) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
+ ret = -EIO;
+ goto out;
+ }
+ }
+ }
+ } else if (NAND_MUST_PAD(this)) {
/* Write out desired data */
this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
/* prepad 0xff for partial programming */
More information about the linux-mtd
mailing list