[MTD] NAND modularize ECC
First step of modularizing ECC support. - Move ECC related functionality into a seperate embedded data structure - Get rid of the hardware dependend constants to simplify new ECC models Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
7aa65bfd67
commit
6dfc6d250d
|
@ -192,7 +192,7 @@ static int __init ams_delta_init(void)
|
||||||
}
|
}
|
||||||
/* 25 us command delay time */
|
/* 25 us command delay time */
|
||||||
this->chip_delay = 30;
|
this->chip_delay = 30;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Set chip enabled, but */
|
/* Set chip enabled, but */
|
||||||
ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
|
ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
|
||||||
|
|
|
@ -578,7 +578,7 @@ static int __init au1xxx_nand_init(void)
|
||||||
|
|
||||||
/* 30 us command delay time */
|
/* 30 us command delay time */
|
||||||
this->chip_delay = 30;
|
this->chip_delay = 30;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
this->options = NAND_NO_AUTOINCR;
|
this->options = NAND_NO_AUTOINCR;
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ static int __init autcpu12_init(void)
|
||||||
this->dev_ready = autcpu12_device_ready;
|
this->dev_ready = autcpu12_device_ready;
|
||||||
/* 20 us command delay time */
|
/* 20 us command delay time */
|
||||||
this->chip_delay = 20;
|
this->chip_delay = 20;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Enable the following for a flash based bad block table */
|
/* Enable the following for a flash based bad block table */
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -242,10 +242,12 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
|
||||||
|
|
||||||
this->chip_delay = 0;
|
this->chip_delay = 0;
|
||||||
|
|
||||||
this->eccmode = NAND_ECC_HW3_256;
|
this->ecc.mode = NAND_ECC_HW;
|
||||||
this->enable_hwecc = cs_enable_hwecc;
|
this->ecc.size = 256;
|
||||||
this->calculate_ecc = cs_calculate_ecc;
|
this->ecc.bytes = 3;
|
||||||
this->correct_data = nand_correct_data;
|
this->ecc.hwctl = cs_enable_hwecc;
|
||||||
|
this->ecc.calculate = cs_calculate_ecc;
|
||||||
|
this->ecc.correct = nand_correct_data;
|
||||||
|
|
||||||
/* Enable the following for a flash based bad block table */
|
/* Enable the following for a flash based bad block table */
|
||||||
this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR;
|
this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR;
|
||||||
|
|
|
@ -1674,12 +1674,14 @@ static int __init doc_probe(unsigned long physadr)
|
||||||
nand->dev_ready = doc200x_dev_ready;
|
nand->dev_ready = doc200x_dev_ready;
|
||||||
nand->waitfunc = doc200x_wait;
|
nand->waitfunc = doc200x_wait;
|
||||||
nand->block_bad = doc200x_block_bad;
|
nand->block_bad = doc200x_block_bad;
|
||||||
nand->enable_hwecc = doc200x_enable_hwecc;
|
nand->ecc.hwctl = doc200x_enable_hwecc;
|
||||||
nand->calculate_ecc = doc200x_calculate_ecc;
|
nand->ecc.calculate = doc200x_calculate_ecc;
|
||||||
nand->correct_data = doc200x_correct_data;
|
nand->ecc.correct = doc200x_correct_data;
|
||||||
|
|
||||||
nand->autooob = &doc200x_oobinfo;
|
nand->autooob = &doc200x_oobinfo;
|
||||||
nand->eccmode = NAND_ECC_HW6_512;
|
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||||
|
nand->ecc.size = 512;
|
||||||
|
nand->ecc.bytes = 6;
|
||||||
nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
|
nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
|
||||||
|
|
||||||
doc->physadr = physadr;
|
doc->physadr = physadr;
|
||||||
|
|
|
@ -149,7 +149,7 @@ static int __init h1910_init(void)
|
||||||
this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */
|
this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */
|
||||||
/* 15 us command delay time */
|
/* 15 us command delay time */
|
||||||
this->chip_delay = 50;
|
this->chip_delay = 50;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
this->options = NAND_NO_AUTOINCR;
|
this->options = NAND_NO_AUTOINCR;
|
||||||
|
|
||||||
/* Scan to find existence of the device */
|
/* Scan to find existence of the device */
|
||||||
|
|
|
@ -879,9 +879,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
|
||||||
{
|
{
|
||||||
int i, status;
|
int i, status;
|
||||||
uint8_t ecc_code[32];
|
uint8_t ecc_code[32];
|
||||||
int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
|
int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
|
||||||
int *oob_config = oobsel->eccpos;
|
int *oob_config = oobsel->eccpos;
|
||||||
int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
|
int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps;
|
||||||
int eccbytes = 0;
|
int eccbytes = 0;
|
||||||
|
|
||||||
/* FIXME: Enable cached programming */
|
/* FIXME: Enable cached programming */
|
||||||
|
@ -901,20 +901,20 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
|
||||||
/* Software ecc 3/256, write all */
|
/* Software ecc 3/256, write all */
|
||||||
case NAND_ECC_SOFT:
|
case NAND_ECC_SOFT:
|
||||||
for (; eccsteps; eccsteps--) {
|
for (; eccsteps; eccsteps--) {
|
||||||
this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
|
this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
|
||||||
for (i = 0; i < 3; i++, eccidx++)
|
for (i = 0; i < 3; i++, eccidx++)
|
||||||
oob_buf[oob_config[eccidx]] = ecc_code[i];
|
oob_buf[oob_config[eccidx]] = ecc_code[i];
|
||||||
datidx += this->eccsize;
|
datidx += this->ecc.size;
|
||||||
}
|
}
|
||||||
this->write_buf(mtd, this->data_poi, mtd->oobblock);
|
this->write_buf(mtd, this->data_poi, mtd->oobblock);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
eccbytes = this->eccbytes;
|
eccbytes = this->ecc.bytes;
|
||||||
for (; eccsteps; eccsteps--) {
|
for (; eccsteps; eccsteps--) {
|
||||||
/* enable hardware ecc logic for write */
|
/* enable hardware ecc logic for write */
|
||||||
this->enable_hwecc(mtd, NAND_ECC_WRITE);
|
this->ecc.hwctl(mtd, NAND_ECC_WRITE);
|
||||||
this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
|
this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
|
||||||
this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
|
this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
|
||||||
for (i = 0; i < eccbytes; i++, eccidx++)
|
for (i = 0; i < eccbytes; i++, eccidx++)
|
||||||
oob_buf[oob_config[eccidx]] = ecc_code[i];
|
oob_buf[oob_config[eccidx]] = ecc_code[i];
|
||||||
/* If the hardware ecc provides syndromes then
|
/* If the hardware ecc provides syndromes then
|
||||||
|
@ -922,7 +922,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
|
||||||
* the data bytes (words) */
|
* the data bytes (words) */
|
||||||
if (this->options & NAND_HWECC_SYNDROME)
|
if (this->options & NAND_HWECC_SYNDROME)
|
||||||
this->write_buf(mtd, ecc_code, eccbytes);
|
this->write_buf(mtd, ecc_code, eccbytes);
|
||||||
datidx += this->eccsize;
|
datidx += this->ecc.size;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1155,7 +1155,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
|
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
|
||||||
oobsel = this->autooob;
|
oobsel = this->autooob;
|
||||||
|
|
||||||
eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
|
eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
|
||||||
oob_config = oobsel->eccpos;
|
oob_config = oobsel->eccpos;
|
||||||
|
|
||||||
/* Select the NAND device */
|
/* Select the NAND device */
|
||||||
|
@ -1170,8 +1170,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
col = from & (mtd->oobblock - 1);
|
col = from & (mtd->oobblock - 1);
|
||||||
|
|
||||||
end = mtd->oobblock;
|
end = mtd->oobblock;
|
||||||
ecc = this->eccsize;
|
ecc = this->ecc.size;
|
||||||
eccbytes = this->eccbytes;
|
eccbytes = this->ecc.bytes;
|
||||||
|
|
||||||
if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
|
if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
|
||||||
compareecc = 0;
|
compareecc = 0;
|
||||||
|
@ -1216,7 +1216,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
|
oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
|
||||||
oob_data = &this->data_buf[end];
|
oob_data = &this->data_buf[end];
|
||||||
|
|
||||||
eccsteps = this->eccsteps;
|
eccsteps = this->ecc.steps;
|
||||||
|
|
||||||
switch (eccmode) {
|
switch (eccmode) {
|
||||||
case NAND_ECC_NONE:{
|
case NAND_ECC_NONE:{
|
||||||
|
@ -1234,12 +1234,12 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
|
case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
|
||||||
this->read_buf(mtd, data_poi, end);
|
this->read_buf(mtd, data_poi, end);
|
||||||
for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
|
for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
|
||||||
this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
|
this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
|
for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
|
||||||
this->enable_hwecc(mtd, NAND_ECC_READ);
|
this->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||||
this->read_buf(mtd, &data_poi[datidx], ecc);
|
this->read_buf(mtd, &data_poi[datidx], ecc);
|
||||||
|
|
||||||
/* HW ecc with syndrome calculation must read the
|
/* HW ecc with syndrome calculation must read the
|
||||||
|
@ -1247,19 +1247,19 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
if (!compareecc) {
|
if (!compareecc) {
|
||||||
/* Some hw ecc generators need to know when the
|
/* Some hw ecc generators need to know when the
|
||||||
* syndrome is read from flash */
|
* syndrome is read from flash */
|
||||||
this->enable_hwecc(mtd, NAND_ECC_READSYN);
|
this->ecc.hwctl(mtd, NAND_ECC_READSYN);
|
||||||
this->read_buf(mtd, &oob_data[i], eccbytes);
|
this->read_buf(mtd, &oob_data[i], eccbytes);
|
||||||
/* We calc error correction directly, it checks the hw
|
/* We calc error correction directly, it checks the hw
|
||||||
* generator for an error, reads back the syndrome and
|
* generator for an error, reads back the syndrome and
|
||||||
* does the error correction on the fly */
|
* 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->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
|
||||||
if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
|
if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
|
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
|
||||||
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
|
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
|
||||||
ecc_failed++;
|
ecc_failed++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
|
this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1277,8 +1277,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
ecc_code[j] = oob_data[oob_config[j]];
|
ecc_code[j] = oob_data[oob_config[j]];
|
||||||
|
|
||||||
/* correct data, if necessary */
|
/* correct data, if necessary */
|
||||||
for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
|
for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) {
|
||||||
ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
|
ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
|
||||||
|
|
||||||
/* Get next chunk of ecc bytes */
|
/* Get next chunk of ecc bytes */
|
||||||
j += eccbytes;
|
j += eccbytes;
|
||||||
|
@ -1315,7 +1315,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
break;
|
break;
|
||||||
case MTD_NANDECC_PLACE:
|
case MTD_NANDECC_PLACE:
|
||||||
/* YAFFS1 legacy mode */
|
/* YAFFS1 legacy mode */
|
||||||
oob_data += this->eccsteps * sizeof(int);
|
oob_data += this->ecc.steps * sizeof(int);
|
||||||
default:
|
default:
|
||||||
oob_data += mtd->oobsize;
|
oob_data += mtd->oobsize;
|
||||||
}
|
}
|
||||||
|
@ -2648,99 +2648,49 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
|
||||||
* check ECC mode, default to software if 3byte/512byte hardware ECC is
|
* check ECC mode, default to software if 3byte/512byte hardware ECC is
|
||||||
* selected and we have 256 byte pagesize fallback to software ECC
|
* selected and we have 256 byte pagesize fallback to software ECC
|
||||||
*/
|
*/
|
||||||
this->eccsize = 256;
|
switch (this->ecc.mode) {
|
||||||
this->eccbytes = 3;
|
case NAND_ECC_HW:
|
||||||
|
case NAND_ECC_HW_SYNDROME:
|
||||||
switch (this->eccmode) {
|
if (!this->ecc.calculate || !this->ecc.correct ||
|
||||||
case NAND_ECC_HW12_2048:
|
!this->ecc.hwctl) {
|
||||||
if (mtd->oobblock < 2048) {
|
printk(KERN_WARNING "No ECC functions supplied, "
|
||||||
printk(KERN_WARNING "2048 byte HW ECC not possible on "
|
"Hardware ECC not possible\n");
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
if (mtd->oobblock >= this->ecc.size)
|
||||||
|
break;
|
||||||
|
printk(KERN_WARNING "%d byte HW ECC not possible on "
|
||||||
"%d byte page size, fallback to SW ECC\n",
|
"%d byte page size, fallback to SW ECC\n",
|
||||||
mtd->oobblock);
|
this->ecc.size, mtd->oobblock);
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
this->calculate_ecc = nand_calculate_ecc;
|
|
||||||
this->correct_data = nand_correct_data;
|
|
||||||
} else
|
|
||||||
this->eccsize = 2048;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NAND_ECC_HW3_512:
|
case NAND_ECC_SOFT:
|
||||||
case NAND_ECC_HW6_512:
|
this->ecc.calculate = nand_calculate_ecc;
|
||||||
case NAND_ECC_HW8_512:
|
this->ecc.correct = nand_correct_data;
|
||||||
if (mtd->oobblock == 256) {
|
this->ecc.size = 256;
|
||||||
printk(KERN_WARNING "512 byte HW ECC not possible on "
|
this->ecc.bytes = 3;
|
||||||
"256 Byte pagesize, fallback to SW ECC \n");
|
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
|
||||||
this->calculate_ecc = nand_calculate_ecc;
|
|
||||||
this->correct_data = nand_correct_data;
|
|
||||||
} else
|
|
||||||
this->eccsize = 512; /* set eccsize to 512 */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NAND_ECC_HW3_256:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_ECC_NONE:
|
case NAND_ECC_NONE:
|
||||||
printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
|
printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
|
||||||
"This is not recommended !!\n");
|
"This is not recommended !!\n");
|
||||||
this->eccmode = NAND_ECC_NONE;
|
this->ecc.size = mtd->oobblock;
|
||||||
|
this->ecc.bytes = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_ECC_SOFT:
|
|
||||||
this->calculate_ecc = nand_calculate_ecc;
|
|
||||||
this->correct_data = nand_correct_data;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
|
printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
|
||||||
this->eccmode);
|
this->ecc.mode);
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check hardware ecc function availability and adjust number of ecc
|
|
||||||
* bytes per calculation step
|
|
||||||
*/
|
|
||||||
switch (this->eccmode) {
|
|
||||||
case NAND_ECC_HW12_2048:
|
|
||||||
this->eccbytes += 4;
|
|
||||||
case NAND_ECC_HW8_512:
|
|
||||||
this->eccbytes += 2;
|
|
||||||
case NAND_ECC_HW6_512:
|
|
||||||
this->eccbytes += 3;
|
|
||||||
case NAND_ECC_HW3_512:
|
|
||||||
case NAND_ECC_HW3_256:
|
|
||||||
if (this->calculate_ecc && this->correct_data &&
|
|
||||||
this->enable_hwecc)
|
|
||||||
break;
|
|
||||||
printk(KERN_WARNING "No ECC functions supplied, "
|
|
||||||
"Hardware ECC not possible\n");
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
|
|
||||||
mtd->eccsize = this->eccsize;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the number of read / write steps for one page depending on ECC
|
* Set the number of read / write steps for one page depending on ECC
|
||||||
* mode
|
* mode
|
||||||
*/
|
*/
|
||||||
switch (this->eccmode) {
|
this->ecc.steps = mtd->oobblock / this->ecc.size;
|
||||||
case NAND_ECC_HW12_2048:
|
if(this->ecc.steps * this->ecc.size != mtd->oobblock) {
|
||||||
this->eccsteps = mtd->oobblock / 2048;
|
printk(KERN_WARNING "Invalid ecc parameters\n");
|
||||||
break;
|
BUG();
|
||||||
case NAND_ECC_HW3_512:
|
|
||||||
case NAND_ECC_HW6_512:
|
|
||||||
case NAND_ECC_HW8_512:
|
|
||||||
this->eccsteps = mtd->oobblock / 512;
|
|
||||||
break;
|
|
||||||
case NAND_ECC_HW3_256:
|
|
||||||
case NAND_ECC_SOFT:
|
|
||||||
this->eccsteps = mtd->oobblock / 256;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NAND_ECC_NONE:
|
|
||||||
this->eccsteps = 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize state, waitqueue and spinlock */
|
/* Initialize state, waitqueue and spinlock */
|
||||||
|
|
|
@ -1523,7 +1523,7 @@ static int __init ns_init_module(void)
|
||||||
chip->verify_buf = ns_nand_verify_buf;
|
chip->verify_buf = ns_nand_verify_buf;
|
||||||
chip->write_word = ns_nand_write_word;
|
chip->write_word = ns_nand_write_word;
|
||||||
chip->read_word = ns_nand_read_word;
|
chip->read_word = ns_nand_read_word;
|
||||||
chip->eccmode = NAND_ECC_SOFT;
|
chip->ecc.mode = NAND_ECC_SOFT;
|
||||||
chip->options |= NAND_SKIP_BBTSCAN;
|
chip->options |= NAND_SKIP_BBTSCAN;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -168,10 +168,12 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
|
||||||
chip->read_buf = ndfc_read_buf;
|
chip->read_buf = ndfc_read_buf;
|
||||||
chip->write_buf = ndfc_write_buf;
|
chip->write_buf = ndfc_write_buf;
|
||||||
chip->verify_buf = ndfc_verify_buf;
|
chip->verify_buf = ndfc_verify_buf;
|
||||||
chip->correct_data = nand_correct_data;
|
chip->ecc.correct = nand_correct_data;
|
||||||
chip->enable_hwecc = ndfc_enable_hwecc;
|
chip->ecc.hwctl = ndfc_enable_hwecc;
|
||||||
chip->calculate_ecc = ndfc_calculate_ecc;
|
chip->ecc.calculate = ndfc_calculate_ecc;
|
||||||
chip->eccmode = NAND_ECC_HW3_256;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
|
chip->ecc.size = 256;
|
||||||
|
chip->ecc.bytes = 3;
|
||||||
chip->autooob = mtd->pl_chip->autooob;
|
chip->autooob = mtd->pl_chip->autooob;
|
||||||
mtd->mtd.priv = chip;
|
mtd->mtd.priv = chip;
|
||||||
mtd->mtd.owner = THIS_MODULE;
|
mtd->mtd.owner = THIS_MODULE;
|
||||||
|
|
|
@ -257,7 +257,7 @@ static int __init ppchameleonevb_init(void)
|
||||||
#endif
|
#endif
|
||||||
this->chip_delay = NAND_BIG_DELAY_US;
|
this->chip_delay = NAND_BIG_DELAY_US;
|
||||||
/* ECC mode */
|
/* ECC mode */
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Scan to find existence of the device (it could not be mounted) */
|
/* Scan to find existence of the device (it could not be mounted) */
|
||||||
if (nand_scan(ppchameleon_mtd, 1)) {
|
if (nand_scan(ppchameleon_mtd, 1)) {
|
||||||
|
@ -358,7 +358,7 @@ static int __init ppchameleonevb_init(void)
|
||||||
this->chip_delay = NAND_SMALL_DELAY_US;
|
this->chip_delay = NAND_SMALL_DELAY_US;
|
||||||
|
|
||||||
/* ECC mode */
|
/* ECC mode */
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Scan to find existence of the device */
|
/* Scan to find existence of the device */
|
||||||
if (nand_scan(ppchameleonevb_mtd, 1)) {
|
if (nand_scan(ppchameleonevb_mtd, 1)) {
|
||||||
|
|
|
@ -570,19 +570,21 @@ static int __init rtc_from4_init(void)
|
||||||
#ifdef RTC_FROM4_HWECC
|
#ifdef RTC_FROM4_HWECC
|
||||||
printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
|
printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
|
||||||
|
|
||||||
this->eccmode = NAND_ECC_HW8_512;
|
this->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||||
|
this->ecc.size = 512;
|
||||||
|
this->ecc.bytes = 8;
|
||||||
this->options |= NAND_HWECC_SYNDROME;
|
this->options |= NAND_HWECC_SYNDROME;
|
||||||
/* return the status of extra status and ECC checks */
|
/* return the status of extra status and ECC checks */
|
||||||
this->errstat = rtc_from4_errstat;
|
this->errstat = rtc_from4_errstat;
|
||||||
/* set the nand_oobinfo to support FPGA H/W error detection */
|
/* set the nand_oobinfo to support FPGA H/W error detection */
|
||||||
this->autooob = &rtc_from4_nand_oobinfo;
|
this->autooob = &rtc_from4_nand_oobinfo;
|
||||||
this->enable_hwecc = rtc_from4_enable_hwecc;
|
this->ecc.hwctl = rtc_from4_enable_hwecc;
|
||||||
this->calculate_ecc = rtc_from4_calculate_ecc;
|
this->ecc.calculate = rtc_from4_calculate_ecc;
|
||||||
this->correct_data = rtc_from4_correct_data;
|
this->ecc.correct = rtc_from4_correct_data;
|
||||||
#else
|
#else
|
||||||
printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
|
printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
|
||||||
|
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* set the bad block tables to support debugging */
|
/* set the bad block tables to support debugging */
|
||||||
|
|
|
@ -520,18 +520,20 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
|
||||||
nmtd->set = set;
|
nmtd->set = set;
|
||||||
|
|
||||||
if (hardware_ecc) {
|
if (hardware_ecc) {
|
||||||
chip->correct_data = s3c2410_nand_correct_data;
|
chip->ecc.correct = s3c2410_nand_correct_data;
|
||||||
chip->enable_hwecc = s3c2410_nand_enable_hwecc;
|
chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
|
||||||
chip->calculate_ecc = s3c2410_nand_calculate_ecc;
|
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
|
||||||
chip->eccmode = NAND_ECC_HW3_512;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
|
chip->ecc.size = 512;
|
||||||
|
chip->ecc.bytes = 3;
|
||||||
chip->autooob = &nand_hw_eccoob;
|
chip->autooob = &nand_hw_eccoob;
|
||||||
|
|
||||||
if (info->is_s3c2440) {
|
if (info->is_s3c2440) {
|
||||||
chip->enable_hwecc = s3c2440_nand_enable_hwecc;
|
chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
|
||||||
chip->calculate_ecc = s3c2440_nand_calculate_ecc;
|
chip->ecc.calculate = s3c2440_nand_calculate_ecc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
chip->eccmode = NAND_ECC_SOFT;
|
chip->ecc.mode = NAND_ECC_SOFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,15 +201,17 @@ static int __init sharpsl_nand_init(void)
|
||||||
/* 15 us command delay time */
|
/* 15 us command delay time */
|
||||||
this->chip_delay = 15;
|
this->chip_delay = 15;
|
||||||
/* set eccmode using hardware ECC */
|
/* set eccmode using hardware ECC */
|
||||||
this->eccmode = NAND_ECC_HW3_256;
|
this->ecc.mode = NAND_ECC_HW;
|
||||||
|
this->ecc.size = 256;
|
||||||
|
this->ecc.bytes = 3;
|
||||||
this->badblock_pattern = &sharpsl_bbt;
|
this->badblock_pattern = &sharpsl_bbt;
|
||||||
if (machine_is_akita() || machine_is_borzoi()) {
|
if (machine_is_akita() || machine_is_borzoi()) {
|
||||||
this->badblock_pattern = &sharpsl_akita_bbt;
|
this->badblock_pattern = &sharpsl_akita_bbt;
|
||||||
this->autooob = &akita_oobinfo;
|
this->autooob = &akita_oobinfo;
|
||||||
}
|
}
|
||||||
this->enable_hwecc = sharpsl_nand_enable_hwecc;
|
this->ecc.hwctl = sharpsl_nand_enable_hwecc;
|
||||||
this->calculate_ecc = sharpsl_nand_calculate_ecc;
|
this->ecc.calculate = sharpsl_nand_calculate_ecc;
|
||||||
this->correct_data = nand_correct_data;
|
this->ecc.correct = nand_correct_data;
|
||||||
|
|
||||||
/* Scan to find existence of the device */
|
/* Scan to find existence of the device */
|
||||||
err = nand_scan(sharpsl_mtd, 1);
|
err = nand_scan(sharpsl_mtd, 1);
|
||||||
|
|
|
@ -146,7 +146,7 @@ static int __init toto_init(void)
|
||||||
this->dev_ready = NULL;
|
this->dev_ready = NULL;
|
||||||
/* 25 us command delay time */
|
/* 25 us command delay time */
|
||||||
this->chip_delay = 30;
|
this->chip_delay = 30;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Scan to find existance of the device */
|
/* Scan to find existance of the device */
|
||||||
if (nand_scan(toto_mtd, 1)) {
|
if (nand_scan(toto_mtd, 1)) {
|
||||||
|
|
|
@ -155,7 +155,7 @@ static int __init ts7250_init(void)
|
||||||
this->hwcontrol = ts7250_hwcontrol;
|
this->hwcontrol = ts7250_hwcontrol;
|
||||||
this->dev_ready = ts7250_device_ready;
|
this->dev_ready = ts7250_device_ready;
|
||||||
this->chip_delay = 15;
|
this->chip_delay = 15;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
printk("Searching for NAND flash...\n");
|
printk("Searching for NAND flash...\n");
|
||||||
/* Scan to find existence of the device */
|
/* Scan to find existence of the device */
|
||||||
|
|
|
@ -113,21 +113,12 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from,
|
||||||
/*
|
/*
|
||||||
* Constants for ECC_MODES
|
* Constants for ECC_MODES
|
||||||
*/
|
*/
|
||||||
|
typedef enum {
|
||||||
/* No ECC. Usage is not recommended ! */
|
NAND_ECC_NONE,
|
||||||
#define NAND_ECC_NONE 0
|
NAND_ECC_SOFT,
|
||||||
/* Software ECC 3 byte ECC per 256 Byte data */
|
NAND_ECC_HW,
|
||||||
#define NAND_ECC_SOFT 1
|
NAND_ECC_HW_SYNDROME,
|
||||||
/* Hardware ECC 3 byte ECC per 256 Byte data */
|
} nand_ecc_modes_t;
|
||||||
#define NAND_ECC_HW3_256 2
|
|
||||||
/* Hardware ECC 3 byte ECC per 512 Byte data */
|
|
||||||
#define NAND_ECC_HW3_512 3
|
|
||||||
/* Hardware ECC 3 byte ECC per 512 Byte data */
|
|
||||||
#define NAND_ECC_HW6_512 4
|
|
||||||
/* Hardware ECC 8 byte ECC per 512 Byte data */
|
|
||||||
#define NAND_ECC_HW8_512 6
|
|
||||||
/* Hardware ECC 12 byte ECC per 2048 Byte data */
|
|
||||||
#define NAND_ECC_HW12_2048 7
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constants for Hardware ECC
|
* Constants for Hardware ECC
|
||||||
|
@ -230,6 +221,31 @@ struct nand_hw_control {
|
||||||
wait_queue_head_t wq;
|
wait_queue_head_t wq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct nand_ecc_ctrl - Control structure for ecc
|
||||||
|
* @mode: ecc mode
|
||||||
|
* @steps: number of ecc steps per page
|
||||||
|
* @size: data bytes per ecc step
|
||||||
|
* @bytes: ecc bytes per step
|
||||||
|
* @hwctl: function to control hardware ecc generator. Must only
|
||||||
|
* be provided if an hardware ECC is available
|
||||||
|
* @calculate: function for ecc calculation or readback from ecc hardware
|
||||||
|
* @correct: function for ecc correction, matching to ecc generator (sw/hw)
|
||||||
|
*/
|
||||||
|
struct nand_ecc_ctrl {
|
||||||
|
nand_ecc_modes_t mode;
|
||||||
|
int steps;
|
||||||
|
int size;
|
||||||
|
int bytes;
|
||||||
|
int (*hwctl)(struct mtd_info *mtd, int mode);
|
||||||
|
int (*calculate)(struct mtd_info *mtd,
|
||||||
|
const uint8_t *dat,
|
||||||
|
uint8_t *ecc_code);
|
||||||
|
int (*correct)(struct mtd_info *mtd, uint8_t *dat,
|
||||||
|
uint8_t *read_ecc,
|
||||||
|
uint8_t *calc_ecc);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_chip - NAND Private Flash Chip Data
|
* struct nand_chip - NAND Private Flash Chip Data
|
||||||
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
|
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
|
||||||
|
@ -250,16 +266,9 @@ struct nand_hw_control {
|
||||||
* is read from the chip status register
|
* is read from the chip status register
|
||||||
* @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
|
* @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
|
||||||
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
|
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
|
||||||
* @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware
|
* @ecc: [BOARDSPECIFIC] ecc control ctructure
|
||||||
* @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
|
|
||||||
* @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
|
|
||||||
* be provided if a hardware ECC is available
|
|
||||||
* @erase_cmd: [INTERN] erase command write function, selectable due to AND support
|
* @erase_cmd: [INTERN] erase command write function, selectable due to AND support
|
||||||
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
||||||
* @eccmode: [BOARDSPECIFIC] mode of ecc, see defines
|
|
||||||
* @eccsize: [INTERN] databytes used per ecc-calculation
|
|
||||||
* @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
|
|
||||||
* @eccsteps: [INTERN] number of ecc calculation steps per page
|
|
||||||
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
|
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
|
||||||
* @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
|
* @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
|
||||||
* @state: [INTERN] the current state of the NAND device
|
* @state: [INTERN] the current state of the NAND device
|
||||||
|
@ -309,15 +318,9 @@ struct nand_chip {
|
||||||
int (*dev_ready)(struct mtd_info *mtd);
|
int (*dev_ready)(struct mtd_info *mtd);
|
||||||
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
|
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
|
||||||
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
|
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
|
||||||
int (*calculate_ecc)(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code);
|
|
||||||
int (*correct_data)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc);
|
|
||||||
void (*enable_hwecc)(struct mtd_info *mtd, int mode);
|
|
||||||
void (*erase_cmd)(struct mtd_info *mtd, int page);
|
void (*erase_cmd)(struct mtd_info *mtd, int page);
|
||||||
int (*scan_bbt)(struct mtd_info *mtd);
|
int (*scan_bbt)(struct mtd_info *mtd);
|
||||||
int eccmode;
|
struct nand_ecc_ctrl ecc;
|
||||||
int eccsize;
|
|
||||||
int eccbytes;
|
|
||||||
int eccsteps;
|
|
||||||
int chip_delay;
|
int chip_delay;
|
||||||
wait_queue_head_t wq;
|
wait_queue_head_t wq;
|
||||||
nand_state_t state;
|
nand_state_t state;
|
||||||
|
|
Loading…
Reference in New Issue