[MTD] DOC: Fixup read functions and do a little cleanup

The NAND rework resulted in non ECC based reads. Fix it up and
do a bit of cleanup while at it.

Pointed out by Adrian Bunk.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Thomas Gleixner 2006-06-28 10:11:33 +02:00
parent a39727f212
commit 7f8a894066
3 changed files with 211 additions and 319 deletions

View file

@ -55,10 +55,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf); size_t *retlen, u_char *buf);
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf); size_t *retlen, const u_char *buf);
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops); struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@ -614,18 +610,11 @@ EXPORT_SYMBOL_GPL(DoC2k_init);
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf) size_t * retlen, u_char * buf)
{
/* Just a special case of doc_read_ecc */
return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
}
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
{ {
struct DiskOnChip *this = mtd->priv; struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr; void __iomem *docptr = this->virtadr;
struct Nand *mychip; struct Nand *mychip;
unsigned char syndrome[6]; unsigned char syndrome[6], eccbuf[6];
volatile char dummy; volatile char dummy;
int i, len256 = 0, ret=0; int i, len256 = 0, ret=0;
size_t left = len; size_t left = len;
@ -673,15 +662,9 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP, DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
CDSN_CTRL_ECC_IO); CDSN_CTRL_ECC_IO);
if (eccbuf) { /* Prime the ECC engine */
/* Prime the ECC engine */ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
WriteDOC(DOC_ECC_RESET, docptr, ECCConf); WriteDOC(DOC_ECC_EN, docptr, ECCConf);
WriteDOC(DOC_ECC_EN, docptr, ECCConf);
} else {
/* disable the ECC engine */
WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
}
/* treat crossing 256-byte sector for 2M x 8bits devices */ /* treat crossing 256-byte sector for 2M x 8bits devices */
if (this->page256 && from + len > (from | 0xff) + 1) { if (this->page256 && from + len > (from | 0xff) + 1) {
@ -698,58 +681,59 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
/* Let the caller know we completed it */ /* Let the caller know we completed it */
*retlen += len; *retlen += len;
if (eccbuf) { /* Read the ECC data through the DiskOnChip ECC logic */
/* Read the ECC data through the DiskOnChip ECC logic */ /* Note: this will work even with 2M x 8bit devices as */
/* Note: this will work even with 2M x 8bit devices as */ /* they have 8 bytes of OOB per 256 page. mf. */
/* they have 8 bytes of OOB per 256 page. mf. */ DoC_ReadBuf(this, eccbuf, 6);
DoC_ReadBuf(this, eccbuf, 6);
/* Flush the pipeline */ /* Flush the pipeline */
if (DoC_is_Millennium(this)) { if (DoC_is_Millennium(this)) {
dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf);
dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf);
i = ReadDOC(docptr, ECCConf); i = ReadDOC(docptr, ECCConf);
} else { } else {
dummy = ReadDOC(docptr, 2k_ECCStatus); dummy = ReadDOC(docptr, 2k_ECCStatus);
dummy = ReadDOC(docptr, 2k_ECCStatus); dummy = ReadDOC(docptr, 2k_ECCStatus);
i = ReadDOC(docptr, 2k_ECCStatus); i = ReadDOC(docptr, 2k_ECCStatus);
} }
/* Check the ECC Status */ /* Check the ECC Status */
if (i & 0x80) { if (i & 0x80) {
int nb_errors; int nb_errors;
/* There was an ECC error */ /* There was an ECC error */
#ifdef ECC_DEBUG #ifdef ECC_DEBUG
printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif #endif
/* Read the ECC syndrom through the DiskOnChip ECC logic. /* Read the ECC syndrom through the DiskOnChip ECC
These syndrome will be all ZERO when there is no error */ logic. These syndrome will be all ZERO when there
for (i = 0; i < 6; i++) { is no error */
syndrome[i] = for (i = 0; i < 6; i++) {
ReadDOC(docptr, ECCSyndrome0 + i); syndrome[i] =
} ReadDOC(docptr, ECCSyndrome0 + i);
nb_errors = doc_decode_ecc(buf, syndrome); }
nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG #ifdef ECC_DEBUG
printk(KERN_ERR "Errors corrected: %x\n", nb_errors); printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
#endif #endif
if (nb_errors < 0) { if (nb_errors < 0) {
/* We return error, but have actually done the read. Not that /* We return error, but have actually done the
this can be told to user-space, via sys_read(), but at least read. Not that this can be told to
MTD-aware stuff can know about it by checking *retlen */ user-space, via sys_read(), but at least
ret = -EIO; MTD-aware stuff can know about it by
} checking *retlen */
ret = -EIO;
} }
}
#ifdef PSYCHO_DEBUG #ifdef PSYCHO_DEBUG
printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long)from, eccbuf[0], eccbuf[1], eccbuf[2], (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
eccbuf[3], eccbuf[4], eccbuf[5]); eccbuf[3], eccbuf[4], eccbuf[5]);
#endif #endif
/* disable the ECC engine */ /* disable the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr , ECCConf); WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
}
/* according to 11.4.1, we need to wait for the busy line /* according to 11.4.1, we need to wait for the busy line
* drop if we read to the end of the page. */ * drop if we read to the end of the page. */
@ -770,18 +754,11 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf) size_t * retlen, const u_char * buf)
{
char eccbuf[6];
return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
}
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf,
u_char * eccbuf, struct nand_oobinfo *oobsel)
{ {
struct DiskOnChip *this = mtd->priv; struct DiskOnChip *this = mtd->priv;
int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */ int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
void __iomem *docptr = this->virtadr; void __iomem *docptr = this->virtadr;
unsigned char eccbuf[6];
volatile char dummy; volatile char dummy;
int len256 = 0; int len256 = 0;
struct Nand *mychip; struct Nand *mychip;
@ -835,15 +812,9 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Command(this, NAND_CMD_SEQIN, 0);
DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO); DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
if (eccbuf) { /* Prime the ECC engine */
/* Prime the ECC engine */ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
WriteDOC(DOC_ECC_RESET, docptr, ECCConf); WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
} else {
/* disable the ECC engine */
WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
}
/* treat crossing 256-byte sector for 2M x 8bits devices */ /* treat crossing 256-byte sector for 2M x 8bits devices */
if (this->page256 && to + len > (to | 0xff) + 1) { if (this->page256 && to + len > (to | 0xff) + 1) {
@ -873,39 +844,35 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
DoC_WriteBuf(this, &buf[len256], len - len256); DoC_WriteBuf(this, &buf[len256], len - len256);
if (eccbuf) { WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, CDSNControl);
WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
CDSNControl);
if (DoC_is_Millennium(this)) { if (DoC_is_Millennium(this)) {
WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP);
} else { } else {
WriteDOC_(0, docptr, this->ioreg); WriteDOC_(0, docptr, this->ioreg);
WriteDOC_(0, docptr, this->ioreg); WriteDOC_(0, docptr, this->ioreg);
WriteDOC_(0, docptr, this->ioreg); WriteDOC_(0, docptr, this->ioreg);
}
WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
CDSNControl);
/* Read the ECC data through the DiskOnChip ECC logic */
for (di = 0; di < 6; di++) {
eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
}
/* Reset the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
#ifdef PSYCHO_DEBUG
printk
("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]);
#endif
} }
WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
CDSNControl);
/* Read the ECC data through the DiskOnChip ECC logic */
for (di = 0; di < 6; di++) {
eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
}
/* Reset the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
#ifdef PSYCHO_DEBUG
printk
("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]);
#endif
DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_PAGEPROG, 0);
DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);

View file

@ -37,12 +37,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf); size_t *retlen, u_char *buf);
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf); size_t *retlen, const u_char *buf);
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel);
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops); struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@ -396,18 +390,10 @@ EXPORT_SYMBOL_GPL(DoCMil_init);
static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{
/* Just a special case of doc_read_ecc */
return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
}
static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel)
{ {
int i, ret; int i, ret;
volatile char dummy; volatile char dummy;
unsigned char syndrome[6]; unsigned char syndrome[6], eccbuf[6];
struct DiskOnChip *this = mtd->priv; struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr; void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)]; struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@ -437,15 +423,9 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00); DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
DoC_WaitReady(docptr); DoC_WaitReady(docptr);
if (eccbuf) { /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_EN, docptr, ECCConf);
WriteDOC (DOC_ECC_EN, docptr, ECCConf);
} else {
/* disable the ECC engine */
WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
}
/* Read the data via the internal pipeline through CDSN IO register, /* Read the data via the internal pipeline through CDSN IO register,
see Pipelined Read Operations 11.3 */ see Pipelined Read Operations 11.3 */
@ -465,74 +445,65 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
*retlen = len; *retlen = len;
ret = 0; ret = 0;
if (eccbuf) { /* Read the ECC data from Spare Data Area,
/* Read the ECC data from Spare Data Area, see Reed-Solomon EDC/ECC 11.1 */
see Reed-Solomon EDC/ECC 11.1 */ dummy = ReadDOC(docptr, ReadPipeInit);
dummy = ReadDOC(docptr, ReadPipeInit);
#ifndef USE_MEMCPY #ifndef USE_MEMCPY
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
/* N.B. you have to increase the source address in this way or the /* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */ ECC logic will not work properly */
eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
} }
#else #else
memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5); memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
#endif #endif
eccbuf[5] = ReadDOC(docptr, LastDataRead); eccbuf[5] = ReadDOC(docptr, LastDataRead);
/* Flush the pipeline */ /* Flush the pipeline */
dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf);
dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf);
/* Check the ECC Status */ /* Check the ECC Status */
if (ReadDOC(docptr, ECCConf) & 0x80) { if (ReadDOC(docptr, ECCConf) & 0x80) {
int nb_errors; int nb_errors;
/* There was an ECC error */ /* There was an ECC error */
#ifdef ECC_DEBUG #ifdef ECC_DEBUG
printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif #endif
/* Read the ECC syndrom through the DiskOnChip ECC logic. /* Read the ECC syndrom through the DiskOnChip ECC logic.
These syndrome will be all ZERO when there is no error */ These syndrome will be all ZERO when there is no error */
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i); syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
}
nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG
printk("ECC Errors corrected: %x\n", nb_errors);
#endif
if (nb_errors < 0) {
/* We return error, but have actually done the read. Not that
this can be told to user-space, via sys_read(), but at least
MTD-aware stuff can know about it by checking *retlen */
ret = -EIO;
}
} }
nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG
printk("ECC Errors corrected: %x\n", nb_errors);
#endif
if (nb_errors < 0) {
/* We return error, but have actually done the read. Not that
this can be told to user-space, via sys_read(), but at least
MTD-aware stuff can know about it by checking *retlen */
ret = -EIO;
}
}
#ifdef PSYCHO_DEBUG #ifdef PSYCHO_DEBUG
printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]); eccbuf[4], eccbuf[5]);
#endif #endif
/* disable the ECC engine */ /* disable the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr , ECCConf); WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
}
return ret; return ret;
} }
static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf) size_t *retlen, const u_char *buf)
{
char eccbuf[6];
return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
}
static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel)
{ {
int i,ret = 0; int i,ret = 0;
char eccbuf[6];
volatile char dummy; volatile char dummy;
struct DiskOnChip *this = mtd->priv; struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr; void __iomem *docptr = this->virtadr;
@ -573,15 +544,9 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
DoC_Address(docptr, 3, to, 0x00, 0x00); DoC_Address(docptr, 3, to, 0x00, 0x00);
DoC_WaitReady(docptr); DoC_WaitReady(docptr);
if (eccbuf) { /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
} else {
/* disable the ECC engine */
WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
}
/* Write the data via the internal pipeline through CDSN IO register, /* Write the data via the internal pipeline through CDSN IO register,
see Pipelined Write Operations 11.2 */ see Pipelined Write Operations 11.2 */
@ -596,46 +561,44 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
#endif #endif
WriteDOC(0x00, docptr, WritePipeTerm); WriteDOC(0x00, docptr, WritePipeTerm);
if (eccbuf) { /* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
/* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
see Reed-Solomon EDC/ECC 11.1 */ WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP);
/* Read the ECC data through the DiskOnChip ECC logic */ /* Read the ECC data through the DiskOnChip ECC logic */
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i); eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
} }
/* ignore the ECC engine */ /* ignore the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr , ECCConf); WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
#ifndef USE_MEMCPY #ifndef USE_MEMCPY
/* Write the ECC data to flash */ /* Write the ECC data to flash */
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
/* N.B. you have to increase the source address in this way or the /* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */ ECC logic will not work properly */
WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i); WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
} }
#else #else
memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6); memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
#endif #endif
/* write the block status BLOCK_USED (0x5555) at the end of ECC data /* write the block status BLOCK_USED (0x5555) at the end of ECC data
FIXME: this is only a hack for programming the IPL area for LinuxBIOS FIXME: this is only a hack for programming the IPL area for LinuxBIOS
and should be replace with proper codes in user space utilities */ and should be replace with proper codes in user space utilities */
WriteDOC(0x55, docptr, Mil_CDSN_IO); WriteDOC(0x55, docptr, Mil_CDSN_IO);
WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
WriteDOC(0x00, docptr, WritePipeTerm); WriteDOC(0x00, docptr, WritePipeTerm);
#ifdef PSYCHO_DEBUG #ifdef PSYCHO_DEBUG
printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]); eccbuf[4], eccbuf[5]);
#endif #endif
}
/* Commit the Page Program command and wait for ready /* Commit the Page Program command and wait for ready
see Software Requirement 11.4 item 1.*/ see Software Requirement 11.4 item 1.*/

View file

@ -41,12 +41,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf); size_t *retlen, u_char *buf);
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf); size_t *retlen, const u_char *buf);
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel);
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops); struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@ -594,19 +588,11 @@ static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{
/* Just a special case of doc_read_ecc */
return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
}
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel)
{ {
int ret, i; int ret, i;
volatile char dummy; volatile char dummy;
loff_t fofs; loff_t fofs;
unsigned char syndrome[6]; unsigned char syndrome[6], eccbuf[6];
struct DiskOnChip *this = mtd->priv; struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr; void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)]; struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@ -644,56 +630,51 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
WriteDOC(0, docptr, Mplus_FlashControl); WriteDOC(0, docptr, Mplus_FlashControl);
DoC_WaitReady(docptr); DoC_WaitReady(docptr);
if (eccbuf) { /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
} else {
/* disable the ECC engine */
WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
}
/* Let the caller know we completed it */ /* Let the caller know we completed it */
*retlen = len; *retlen = len;
ret = 0; ret = 0;
ReadDOC(docptr, Mplus_ReadPipeInit); ReadDOC(docptr, Mplus_ReadPipeInit);
ReadDOC(docptr, Mplus_ReadPipeInit); ReadDOC(docptr, Mplus_ReadPipeInit);
if (eccbuf) { /* Read the data via the internal pipeline through CDSN IO
/* Read the data via the internal pipeline through CDSN IO register, see Pipelined Read Operations 11.3 */
register, see Pipelined Read Operations 11.3 */ MemReadDOC(docptr, buf, len);
MemReadDOC(docptr, buf, len);
/* Read the ECC data following raw data */ /* Read the ECC data following raw data */
MemReadDOC(docptr, eccbuf, 4); MemReadDOC(docptr, eccbuf, 4);
eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead); eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead); eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
/* Flush the pipeline */ /* Flush the pipeline */
dummy = ReadDOC(docptr, Mplus_ECCConf); dummy = ReadDOC(docptr, Mplus_ECCConf);
dummy = ReadDOC(docptr, Mplus_ECCConf); dummy = ReadDOC(docptr, Mplus_ECCConf);
/* Check the ECC Status */ /* Check the ECC Status */
if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) { if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
int nb_errors; int nb_errors;
/* There was an ECC error */ /* There was an ECC error */
#ifdef ECC_DEBUG #ifdef ECC_DEBUG
printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif #endif
/* Read the ECC syndrom through the DiskOnChip ECC logic. /* Read the ECC syndrom through the DiskOnChip ECC logic.
These syndrome will be all ZERO when there is no error */ These syndrome will be all ZERO when there is no error */
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
nb_errors = doc_decode_ecc(buf, syndrome); nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG #ifdef ECC_DEBUG
printk("ECC Errors corrected: %x\n", nb_errors); printk("ECC Errors corrected: %x\n", nb_errors);
#endif #endif
if (nb_errors < 0) { if (nb_errors < 0) {
/* We return error, but have actually done the read. Not that /* We return error, but have actually done the
this can be told to user-space, via sys_read(), but at least read. Not that this can be told to user-space, via
MTD-aware stuff can know about it by checking *retlen */ sys_read(), but at least MTD-aware stuff can know
about it by checking *retlen */
#ifdef ECC_DEBUG #ifdef ECC_DEBUG
printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n", printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
__FILE__, __LINE__, (int)from); __FILE__, __LINE__, (int)from);
@ -707,24 +688,16 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
eccbuf[3], eccbuf[4], eccbuf[5]); eccbuf[3], eccbuf[4], eccbuf[5]);
#endif #endif
ret = -EIO; ret = -EIO;
}
} }
}
#ifdef PSYCHO_DEBUG #ifdef PSYCHO_DEBUG
printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]); eccbuf[4], eccbuf[5]);
#endif #endif
/* disable the ECC engine */
/* disable the ECC engine */ WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
} else {
/* Read the data via the internal pipeline through CDSN IO
register, see Pipelined Read Operations 11.3 */
MemReadDOC(docptr, buf, len-2);
buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
}
/* Disable flash internally */ /* Disable flash internally */
WriteDOC(0, docptr, Mplus_FlashSelect); WriteDOC(0, docptr, Mplus_FlashSelect);
@ -734,18 +707,11 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf) size_t *retlen, const u_char *buf)
{
char eccbuf[6];
return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
}
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel)
{ {
int i, before, ret = 0; int i, before, ret = 0;
loff_t fto; loff_t fto;
volatile char dummy; volatile char dummy;
char eccbuf[6];
struct DiskOnChip *this = mtd->priv; struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr; void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[to >> (this->chipshift)]; struct Nand *mychip = &this->chips[to >> (this->chipshift)];
@ -795,46 +761,42 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
/* Disable the ECC engine */ /* Disable the ECC engine */
WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
if (eccbuf) { if (before) {
if (before) { /* Write the block status BLOCK_USED (0x5555) */
/* Write the block status BLOCK_USED (0x5555) */ WriteDOC(0x55, docptr, Mil_CDSN_IO);
WriteDOC(0x55, docptr, Mil_CDSN_IO); WriteDOC(0x55, docptr, Mil_CDSN_IO);
WriteDOC(0x55, docptr, Mil_CDSN_IO);
}
/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
} }
/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
MemWriteDOC(docptr, (unsigned char *) buf, len); MemWriteDOC(docptr, (unsigned char *) buf, len);
if (eccbuf) { /* Write ECC data to flash, the ECC info is generated by
/* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */ DoC_Delay(docptr, 3);
DoC_Delay(docptr, 3);
/* Read the ECC data through the DiskOnChip ECC logic */ /* Read the ECC data through the DiskOnChip ECC logic */
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
/* disable the ECC engine */ /* disable the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
/* Write the ECC data to flash */ /* Write the ECC data to flash */
MemWriteDOC(docptr, eccbuf, 6); MemWriteDOC(docptr, eccbuf, 6);
if (!before) { if (!before) {
/* Write the block status BLOCK_USED (0x5555) */ /* Write the block status BLOCK_USED (0x5555) */
WriteDOC(0x55, docptr, Mil_CDSN_IO+6); WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
WriteDOC(0x55, docptr, Mil_CDSN_IO+7); WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
} }
#ifdef PSYCHO_DEBUG #ifdef PSYCHO_DEBUG
printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]); eccbuf[4], eccbuf[5]);
#endif #endif
}
WriteDOC(0x00, docptr, Mplus_WritePipeTerm); WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
WriteDOC(0x00, docptr, Mplus_WritePipeTerm); WriteDOC(0x00, docptr, Mplus_WritePipeTerm);