X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmtd%2Fdevices%2Fdoc2001plus.c;h=d30ba118f9201f73ad9e9e36369ebbf8b299e563;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=e5e5fdaeb32d01e9e5de7ee794c242b62abeac49;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index e5e5fdaeb..d30ba118f 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -6,7 +6,9 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2001plus.c,v 1.5 2003/06/11 09:45:19 dwmw2 Exp $ + * $Id: doc2001plus.c,v 1.9 2004/08/09 13:19:44 dwmw2 Exp $ + * + * Released under GPL */ #include @@ -21,6 +23,7 @@ #include #include #include +#include #include #include @@ -183,24 +186,35 @@ static int DoC_SelectFloor(unsigned long docptr, int floor) * | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB 1 + 2 | * +-----------+-------+-------+-------+--------------+---------+-----------+ */ +/* FIXME: This lives in INFTL not here. Other users of flash devices + may not want it */ static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from) { - unsigned int ofs = *from & 0x3ff; - unsigned int cmd; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; - if (ofs < 512) { - cmd = NAND_CMD_READ0; - ofs &= 0x1ff; - } else if (ofs < 1014) { - cmd = NAND_CMD_READ1; - ofs = (ofs & 0x1ff) + 10; + if (this->interleave) { + unsigned int ofs = *from & 0x3ff; + unsigned int cmd; + + if (ofs < 512) { + cmd = NAND_CMD_READ0; + ofs &= 0x1ff; + } else if (ofs < 1014) { + cmd = NAND_CMD_READ1; + ofs = (ofs & 0x1ff) + 10; + } else { + cmd = NAND_CMD_READOOB; + ofs = ofs - 1014; + } + + *from = (*from & ~0x3ff) | ofs; + return cmd; } else { - cmd = NAND_CMD_READOOB; - ofs = ofs - 1014; + /* No interleave */ + if ((*from) & 0x100) + return NAND_CMD_READ1; + return NAND_CMD_READ0; } - - *from = (*from & ~0x3ff) | ofs; - return cmd; } static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from) @@ -294,10 +308,12 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) dummy = ReadDOC(docptr, Mplus_ReadPipeInit); mfr = ReadDOC(docptr, Mil_CDSN_IO); - dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ + if (doc->interleave) + dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ id = ReadDOC(docptr, Mil_CDSN_IO); - dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ + if (doc->interleave) + dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ dummy = ReadDOC(docptr, Mplus_LastDataRead); dummy = ReadDOC(docptr, Mplus_LastDataRead); @@ -321,10 +337,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) nand_manuf_ids[j].name, nand_flash_ids[i].name); doc->mfr = mfr; doc->id = id; - doc->interleave = 0; - if (doc->ChipID == DOC_ChipID_DocMilPlus32) - doc->interleave = 1; - doc->chipshift = nand_flash_ids[i].chipshift; + doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1; doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave; break; } @@ -346,6 +359,21 @@ static void DoC_ScanChips(struct DiskOnChip *this) this->mfr = 0; this->id = 0; + /* Work out the intended interleave setting */ + this->interleave = 0; + if (this->ChipID == DOC_ChipID_DocMilPlus32) + this->interleave = 1; + + /* Check the ASIC agrees */ + if ( (this->interleave << 2) != + (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { + u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); + printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", + this->interleave?"on (16-bit)":"off (8-bit)"); + conf ^= 4; + WriteDOC(this->virtadr, conf, Mplus_Configuration); + } + /* For each floor, find the number of valid chips it contains */ for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) { numchips[floor] = 0; @@ -739,7 +767,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; /* Determine position of OOB flags, before or after data */ - before = to & 0x200; + before = (this->interleave && (to & 0x200)); DoC_CheckASIC(docptr); @@ -886,7 +914,10 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, /* Figure out which region we are accessing... */ fofs = ofs; base = ofs & 0xf; - if (base < 6) { + if (!this->interleave) { + DoC_Command(docptr, NAND_CMD_READOOB, 0); + size = 16 - base; + } else if (base < 6) { DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0); size = 6 - base; } else if (base < 8) { @@ -963,7 +994,10 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, /* Figure out which region we are accessing... */ fofs = ofs; base = ofs & 0x0f; - if (base < 6) { + if (!this->interleave) { + WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd); + size = 16 - base; + } else if (base < 6) { WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd); size = 6 - base; } else if (base < 8) { @@ -1077,8 +1111,7 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr) /* Disable flash internally */ WriteDOC(0, docptr, Mplus_FlashSelect); - if (instr->callback) - instr->callback(instr); + mtd_erase_callback(instr); return 0; }