* drivers/mtd/nand/diskonchip.c
*
* (C) 2003 Red Hat, Inc.
- * (C) 2004 Dan Brown <dan_brown@ieee.org>
- * (C) 2004 Kalev Lember <kalev@smartlink.ee>
*
* Author: David Woodhouse <dwmw2@infradead.org>
- * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
- * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
*
* Interface to generic NAND code for M-Systems DiskOnChip devices
*
- * $Id: diskonchip.c,v 1.34 2004/08/09 19:41:12 dbrown Exp $
+ * $Id: diskonchip.c,v 1.23 2004/07/13 00:14:35 dbrown Exp $
*/
#include <linux/kernel.h>
#include <linux/mtd/inftl.h>
/* Where to look for the devices? */
-#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#ifndef CONFIG_MTD_DOCPROBE_ADDRESS
+#define CONFIG_MTD_DOCPROBE_ADDRESS 0
#endif
static unsigned long __initdata doc_locations[] = {
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+#ifdef CONFIG_MTD_DOCPROBE_HIGH
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
#define INFTL_BBT_RESERVED_BLOCKS 4
-#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
#endif
MODULE_PARM(inftl_bbt_write, "i");
-static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
MODULE_PARM(doc_config_location, "l");
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
for (i = 0; i < cycles; i++) {
if (DoC_is_Millennium(doc))
dummy = ReadDOC(doc->virtadr, NOP);
- else if (DoC_is_MillenniumPlus(doc))
- dummy = ReadDOC(doc->virtadr, Mplus_NOP);
else
dummy = ReadDOC(doc->virtadr, DOCStatus);
}
}
-
-#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
-
/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
static int _DoC_WaitReady(struct doc_priv *doc)
{
if(debug) printk("_DoC_WaitReady...\n");
/* Out-of-line routine to wait for chip response */
- if (DoC_is_MillenniumPlus(doc)) {
- while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
- if (time_after(jiffies, timeo)) {
- printk("_DoC_WaitReady timed out.\n");
- return -EIO;
- }
- udelay(1);
- cond_resched();
- }
- } else {
- while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
- if (time_after(jiffies, timeo)) {
- printk("_DoC_WaitReady timed out.\n");
- return -EIO;
- }
- udelay(1);
- cond_resched();
+ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+ if (time_after(jiffies, timeo)) {
+ printk("_DoC_WaitReady timed out.\n");
+ return -EIO;
}
+ udelay(1);
+ cond_resched();
}
return 0;
unsigned long docptr = doc->virtadr;
int ret = 0;
- if (DoC_is_MillenniumPlus(doc)) {
- DoC_Delay(doc, 4);
-
- if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
- /* Call the out-of-line routine to wait */
- ret = _DoC_WaitReady(doc);
- } else {
- DoC_Delay(doc, 4);
+ DoC_Delay(doc, 4);
- if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
- /* Call the out-of-line routine to wait */
- ret = _DoC_WaitReady(doc);
- DoC_Delay(doc, 2);
- }
+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+ /* Call the out-of-line routine to wait */
+ ret = _DoC_WaitReady(doc);
+ DoC_Delay(doc, 2);
if(debug) printk("DoC_WaitReady OK\n");
return ret;
}
ReadDOC(docptr, ReadPipeInit);
for (i=0; i < len-1; i++)
- buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
+ buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
/* Terminate read pipeline */
buf[i] = ReadDOC(docptr, LastDataRead);
return 0;
}
-static u_char doc2001plus_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
- unsigned long docptr = doc->virtadr;
- u_char ret;
-
- ReadDOC(docptr, Mplus_ReadPipeInit);
- ReadDOC(docptr, Mplus_ReadPipeInit);
- ret = ReadDOC(docptr, Mplus_LastDataRead);
- if (debug) printk("read_byte returns %02x\n", ret);
- return ret;
-}
-
-static void doc2001plus_writebuf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
- unsigned long docptr = doc->virtadr;
- int i;
-
- if (debug)printk("writebuf of %d bytes: ", len);
- for (i=0; i < len; i++) {
- WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
- if (debug && i < 16)
- printk("%02x ", buf[i]);
- }
- if (debug) printk("\n");
-}
-
-static void doc2001plus_readbuf(struct mtd_info *mtd,
- u_char *buf, int len)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
- unsigned long docptr = doc->virtadr;
- int i;
-
- if (debug)printk("readbuf of %d bytes: ", len);
-
- /* Start read pipeline */
- ReadDOC(docptr, Mplus_ReadPipeInit);
- ReadDOC(docptr, Mplus_ReadPipeInit);
-
- for (i=0; i < len-2; i++) {
- buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
- if (debug && i < 16)
- printk("%02x ", buf[i]);
- }
-
- /* Terminate read pipeline */
- buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
- if (debug && i < 16)
- printk("%02x ", buf[len-2]);
- buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
- if (debug && i < 16)
- printk("%02x ", buf[len-1]);
- if (debug) printk("\n");
-}
-
-static int doc2001plus_verifybuf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
- unsigned long docptr = doc->virtadr;
- int i;
-
- if (debug)printk("verifybuf of %d bytes: ", len);
-
- /* Start read pipeline */
- ReadDOC(docptr, Mplus_ReadPipeInit);
- ReadDOC(docptr, Mplus_ReadPipeInit);
-
- for (i=0; i < len-2; i++)
- if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
- ReadDOC(docptr, Mplus_LastDataRead);
- ReadDOC(docptr, Mplus_LastDataRead);
- return i;
- }
- if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead))
- return len-2;
- if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead))
- return len-1;
- return 0;
-}
-
-static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
- unsigned long docptr = doc->virtadr;
- int floor = 0;
-
- if(debug)printk("select chip (%d)\n", chip);
-
- if (chip == -1) {
- /* Disable flash internally */
- WriteDOC(0, docptr, Mplus_FlashSelect);
- return;
- }
-
- floor = chip / doc->chips_per_floor;
- chip -= (floor * doc->chips_per_floor);
-
- /* Assert ChipEnable and deassert WriteProtect */
- WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
- this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
- doc->curchip = chip;
- doc->curfloor = floor;
-}
-
static void doc200x_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
unsigned long docptr = doc->virtadr;
int floor = 0;
+ /* 11.4.4 -- deassert CE before changing chip */
+ doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
+
if(debug)printk("select chip (%d)\n", chip);
if (chip == -1)
floor = chip / doc->chips_per_floor;
chip -= (floor * doc->chips_per_floor);
- /* 11.4.4 -- deassert CE before changing chip */
- doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
-
WriteDOC(floor, docptr, FloorSelect);
WriteDOC(chip, docptr, CDSNDeviceSelect);
DoC_Delay(doc, 4);
}
-static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
- unsigned long docptr = doc->virtadr;
-
- /*
- * Must terminate write pipeline before sending any commands
- * to the device.
- */
- if (command == NAND_CMD_PAGEPROG) {
- WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
- WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
- }
-
- /*
- * Write out the command to the device.
- */
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->oobblock) {
- /* OOB area */
- column -= mtd->oobblock;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
- WriteDOC(readcmd, docptr, Mplus_FlashCmd);
- }
- WriteDOC(command, docptr, Mplus_FlashCmd);
- WriteDOC(0, docptr, Mplus_WritePipeTerm);
- WriteDOC(0, docptr, Mplus_WritePipeTerm);
-
- if (column != -1 || page_addr != -1) {
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (this->options & NAND_BUSWIDTH_16)
- column >>= 1;
- WriteDOC(column, docptr, Mplus_FlashAddress);
- }
- if (page_addr != -1) {
- WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress);
- WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
- /* One more address cycle for higher density devices */
- if (this->chipsize & 0x0c000000) {
- WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
- printk("high density\n");
- }
- }
- WriteDOC(0, docptr, Mplus_WritePipeTerm);
- WriteDOC(0, docptr, Mplus_WritePipeTerm);
- /* deassert ALE */
- if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID)
- WriteDOC(0, docptr, Mplus_FlashControl);
- }
-
- /*
- * program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- return;
-
- case NAND_CMD_RESET:
- if (this->dev_ready)
- break;
- udelay(this->chip_delay);
- WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
- WriteDOC(0, docptr, Mplus_WritePipeTerm);
- WriteDOC(0, docptr, Mplus_WritePipeTerm);
- while ( !(this->read_byte(mtd) & 0x40));
- return;
-
- /* This applies to read commands */
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
- return;
- }
- }
-
- /* Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine. */
- ndelay (100);
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
-}
-
static int doc200x_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = (void *)this->priv;
unsigned long docptr = doc->virtadr;
- if (DoC_is_MillenniumPlus(doc)) {
- /* 11.4.2 -- must NOP four times before checking FR/B# */
- DoC_Delay(doc, 4);
- if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
- if(debug)
- printk("not ready\n");
- return 0;
- }
- if (debug)printk("was ready\n");
- return 1;
- } else {
- /* 11.4.2 -- must NOP four times before checking FR/B# */
- DoC_Delay(doc, 4);
- if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
- if(debug)
- printk("not ready\n");
- return 0;
- }
- /* 11.4.2 -- Must NOP twice if it's ready */
- DoC_Delay(doc, 2);
- if (debug)printk("was ready\n");
- return 1;
+ /* 11.4.2 -- must NOP four times before checking FR/B# */
+ DoC_Delay(doc, 4);
+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+ if(debug)
+ printk("not ready\n");
+ return 0;
}
-}
+ /* 11.4.2 -- Must NOP twice if it's ready */
+ DoC_Delay(doc, 2);
+ if (debug)printk("was ready\n");
+ return 1;
+}
static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
{
WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
break;
- }
-}
-
-static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
- unsigned long docptr = doc->virtadr;
-
- /* Prime the ECC engine */
- switch(mode) {
- case NAND_ECC_READ:
- WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
- WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
- break;
- case NAND_ECC_WRITE:
- WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
- WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
- break;
- }
+ }
}
/* This code is only called on write */
WriteDOC(0, docptr, 2k_CDSN_IO);
WriteDOC(0, docptr, 2k_CDSN_IO);
WriteDOC(doc->CDSNControl, docptr, CDSNControl);
- } else if (DoC_is_MillenniumPlus(doc)) {
- WriteDOC(0, docptr, Mplus_NOP);
- WriteDOC(0, docptr, Mplus_NOP);
- WriteDOC(0, docptr, Mplus_NOP);
} else {
WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP);
}
for (i = 0; i < 6; i++) {
- if (DoC_is_MillenniumPlus(doc))
- ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
- else
- ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+ ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
if (ecc_code[i] != empty_write_ecc[i])
emptymatch = 0;
}
- if (DoC_is_MillenniumPlus(doc))
- WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
- else
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
#if 0
/* If emptymatch=1, we might have an all-0xff data buffer. Check. */
if (emptymatch) {
dummy = ReadDOC(docptr, 2k_ECCStatus);
dummy = ReadDOC(docptr, 2k_ECCStatus);
dummy = ReadDOC(docptr, 2k_ECCStatus);
- } else if (DoC_is_MillenniumPlus(doc)) {
- dummy = ReadDOC(docptr, Mplus_ECCConf);
- dummy = ReadDOC(docptr, Mplus_ECCConf);
- dummy = ReadDOC(docptr, Mplus_ECCConf);
} else {
dummy = ReadDOC(docptr, ECCConf);
dummy = ReadDOC(docptr, ECCConf);
/* Error occured ? */
if (dummy & 0x80) {
for (i = 0; i < 6; i++) {
- if (DoC_is_MillenniumPlus(doc))
- calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
- else
- calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+ calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
if (calc_ecc[i] != empty_read_syndrome[i])
emptymatch = 0;
}
if (ret > 0)
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
}
- if (DoC_is_MillenniumPlus(doc))
- WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
- else
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
if (no_ecc_failures && (ret == -1)) {
printk(KERN_ERR "suppressing ECC failure\n");
ret = 0;
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = (void *)this->priv;
- unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
- int ret;
- size_t retlen;
+ int offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
+ int ret, retlen;
end = min(end, mtd->size); // paranoia
for (offs = 0; offs < end; offs += mtd->erasesize) {
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = (void *)this->priv;
- int ret = 0;
- u_char *buf;
- struct NFTLMediaHeader *mh;
- const unsigned psize = 1 << this->page_shift;
- unsigned blocks, maxblocks;
+ u_char *buf = this->data_buf;
+ struct NFTLMediaHeader *mh = (struct NFTLMediaHeader *) buf;
+ const int psize = 1 << this->page_shift;
+ int blocks, maxblocks;
int offs, numheaders;
- buf = kmalloc(mtd->oobblock, GFP_KERNEL);
- if (!buf) {
- printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
- return 0;
- }
- if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
- mh = (struct NFTLMediaHeader *) buf;
+ if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) return 0;
//#ifdef CONFIG_MTD_DEBUG_VERBOSE
// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
//#endif
blocks = mtd->size >> this->phys_erase_shift;
- maxblocks = min(32768U, mtd->erasesize - psize);
+ maxblocks = min(32768, mtd->erasesize - psize);
if (mh->UnitSizeFactor == 0x00) {
/* Auto-determine UnitSizeFactor. The constraints are:
mh->UnitSizeFactor = 0xff;
while (blocks > maxblocks) {
blocks >>= 1;
- maxblocks = min(32768U, (maxblocks << 1) + psize);
+ maxblocks = min(32768, (maxblocks << 1) + psize);
mh->UnitSizeFactor--;
}
printk(KERN_WARNING "UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
blocks = mtd->size >> this->bbt_erase_shift;
- maxblocks = min(32768U, mtd->erasesize - psize);
+ maxblocks = min(32768, mtd->erasesize - psize);
}
if (blocks > maxblocks) {
printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor);
- goto out;
+ return 0;
}
/* Skip past the media headers. */
parts[1].name = " DiskOnChip Remainder partition";
parts[1].offset = offs;
parts[1].size = mtd->size - offs;
- ret = 2;
- goto out;
+ return 2;
}
- ret = 1;
-out:
- kfree(buf);
- return ret;
+ return 1;
}
/* This is a stripped-down copy of the code in inftlmount.c */
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = (void *)this->priv;
- int ret = 0;
- u_char *buf;
- struct INFTLMediaHeader *mh;
+ u_char *buf = this->data_buf;
+ struct INFTLMediaHeader *mh = (struct INFTLMediaHeader *) buf;
struct INFTLPartition *ip;
int numparts = 0;
int blocks;
if (inftl_bbt_write)
end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
- buf = kmalloc(mtd->oobblock, GFP_KERNEL);
- if (!buf) {
- printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
- return 0;
- }
-
- if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out;
+ if (!find_media_headers(mtd, buf, "BNAND", 0)) return 0;
doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
- mh = (struct INFTLMediaHeader *) buf;
mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
" NoOfBDTLPartitions = %d\n"
" BlockMultiplerBits = %d\n"
" FormatFlgs = %d\n"
- " OsakVersion = %d.%d.%d.%d\n"
+ " OsakVersion = 0x%x\n"
" PercentUsed = %d\n",
mh->bootRecordID, mh->NoOfBootImageBlocks,
mh->NoOfBinaryPartitions,
mh->NoOfBDTLPartitions,
mh->BlockMultiplierBits, mh->FormatFlags,
- ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
- ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
- ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
- ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
- mh->PercentUsed);
+ mh->OsakVersion, mh->PercentUsed);
//#endif
vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
blocks = mtd->size >> vshift;
if (blocks > 32768) {
printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits);
- goto out;
+ return 0;
}
blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
if (inftl_bbt_write && (blocks > mtd->erasesize)) {
printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n");
- goto out;
+ return 0;
}
/* Scan the partitions */
parts[numparts].size = end - parts[numparts].offset;
numparts++;
}
- ret = numparts;
-out:
- kfree(buf);
- return ret;
+ return numparts;
}
static int __init nftl_scan_bbt(struct mtd_info *mtd)
if ((ret = nand_scan_bbt(mtd, NULL)))
return ret;
add_mtd_device(mtd);
-#ifdef CONFIG_MTD_PARTITIONS
- if (!no_autopart)
- add_mtd_partitions(mtd, parts, numparts);
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ if (!no_autopart) add_mtd_partitions(mtd, parts, numparts);
#endif
return 0;
}
return -EIO;
}
- if (DoC_is_MillenniumPlus(doc)) {
- this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
- if (inftl_bbt_write)
- this->bbt_td->options |= NAND_BBT_WRITE;
- this->bbt_td->pages[0] = 2;
- this->bbt_md = NULL;
- } else {
- this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
- NAND_BBT_VERSION;
- if (inftl_bbt_write)
- this->bbt_td->options |= NAND_BBT_WRITE;
- this->bbt_td->offs = 8;
- this->bbt_td->len = 8;
- this->bbt_td->veroffs = 7;
- this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
- this->bbt_td->reserved_block_code = 0x01;
- this->bbt_td->pattern = "MSYS_BBT";
-
- this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
- NAND_BBT_VERSION;
- if (inftl_bbt_write)
- this->bbt_md->options |= NAND_BBT_WRITE;
- this->bbt_md->offs = 8;
- this->bbt_md->len = 8;
- this->bbt_md->veroffs = 7;
- this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
- this->bbt_md->reserved_block_code = 0x01;
- this->bbt_md->pattern = "TBB_SYSM";
+ if (mtd->size == (8<<20)) {
+#if 0
+/* This doesn't seem to work for me. I get ECC errors on every page. */
+ /* The Millennium 8MiB is actually an NFTL device! */
+ mtd->name = "DiskOnChip Millennium 8MiB (NFTL)";
+ return nftl_scan_bbt(mtd);
+#endif
+ printk(KERN_ERR "DiskOnChip Millennium 8MiB is not supported.\n");
+ return -EIO;
}
+ this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
+ NAND_BBT_VERSION;
+ if (inftl_bbt_write)
+ this->bbt_td->options |= NAND_BBT_WRITE;
+ this->bbt_td->offs = 8;
+ this->bbt_td->len = 8;
+ this->bbt_td->veroffs = 7;
+ this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+ this->bbt_td->reserved_block_code = 0x01;
+ this->bbt_td->pattern = "MSYS_BBT";
+
+ this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
+ NAND_BBT_VERSION;
+ if (inftl_bbt_write)
+ this->bbt_md->options |= NAND_BBT_WRITE;
+ this->bbt_md->offs = 8;
+ this->bbt_md->len = 8;
+ this->bbt_md->veroffs = 7;
+ this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+ this->bbt_md->reserved_block_code = 0x01;
+ this->bbt_md->pattern = "TBB_SYSM";
+
/* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.
At least as nand_bbt.c is currently written. */
if ((ret = nand_scan_bbt(mtd, NULL)))
autopartitioning, but I want to give it more thought. */
if (!numparts) return -EIO;
add_mtd_device(mtd);
-#ifdef CONFIG_MTD_PARTITIONS
- if (!no_autopart)
- add_mtd_partitions(mtd, parts, numparts);
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ if (!no_autopart) add_mtd_partitions(mtd, parts, numparts);
#endif
return 0;
}
this->write_buf = doc2001_writebuf;
this->read_buf = doc2001_readbuf;
this->verify_buf = doc2001_verifybuf;
+ this->scan_bbt = inftl_scan_bbt;
ReadDOC(doc->virtadr, ChipID);
ReadDOC(doc->virtadr, ChipID);
can have multiple chips. */
doc2000_count_chips(mtd);
mtd->name = "DiskOnChip 2000 (INFTL Model)";
- this->scan_bbt = inftl_scan_bbt;
return (4 * doc->chips_per_floor);
} else {
/* Bog-standard Millennium */
doc->chips_per_floor = 1;
mtd->name = "DiskOnChip Millennium";
- this->scan_bbt = nftl_scan_bbt;
return 1;
}
}
-static inline int __init doc2001plus_init(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
-
- this->write_byte = NULL;
- this->read_byte = doc2001plus_read_byte;
- this->write_buf = doc2001plus_writebuf;
- this->read_buf = doc2001plus_readbuf;
- this->verify_buf = doc2001plus_verifybuf;
- this->scan_bbt = inftl_scan_bbt;
- this->hwcontrol = NULL;
- this->select_chip = doc2001plus_select_chip;
- this->cmdfunc = doc2001plus_command;
- this->enable_hwecc = doc2001plus_enable_hwecc;
-
- doc->chips_per_floor = 1;
- mtd->name = "DiskOnChip Millennium Plus";
-
- return 1;
-}
-
static inline int __init doc_probe(unsigned long physadr)
{
unsigned char ChipID;
case DOC_ChipID_DocMil:
reg = DoC_ECCConf;
break;
- case DOC_ChipID_DocMilPlus16:
- case DOC_ChipID_DocMilPlus32:
- case 0:
- /* Possible Millennium Plus, need to do more checks */
- /* Possibly release from power down mode */
- for (tmp = 0; (tmp < 4); tmp++)
- ReadDOC(virtadr, Mplus_Power);
-
- /* Reset the Millennium Plus ASIC */
- tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
- DOC_MODE_BDECT;
- WriteDOC(tmp, virtadr, Mplus_DOCControl);
- WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
-
- mdelay(1);
- /* Enable the Millennium Plus ASIC */
- tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
- DOC_MODE_BDECT;
- WriteDOC(tmp, virtadr, Mplus_DOCControl);
- WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
- mdelay(1);
-
- ChipID = ReadDOC(virtadr, ChipID);
-
- switch (ChipID) {
- case DOC_ChipID_DocMilPlus16:
- reg = DoC_Mplus_Toggle;
- break;
- case DOC_ChipID_DocMilPlus32:
- printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
- default:
- ret = -ENODEV;
- goto notfound;
- }
- break;
-
default:
ret = -ENODEV;
goto notfound;
}
for (mtd = doclist; mtd; mtd = doc->nextdoc) {
- unsigned char oldval;
- unsigned char newval;
nand = mtd->priv;
doc = (void *)nand->priv;
/* Use the alias resolution register to determine if this is
in fact the same DOC aliased to a new address. If writes
to one chip's alias resolution register change the value on
the other chip, they're the same chip. */
- if (ChipID == DOC_ChipID_DocMilPlus16) {
- oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
- newval = ReadDOC(virtadr, Mplus_AliasResolution);
- } else {
- oldval = ReadDOC(doc->virtadr, AliasResolution);
- newval = ReadDOC(virtadr, AliasResolution);
- }
+ unsigned char oldval = ReadDOC(doc->virtadr, AliasResolution);
+ unsigned char newval = ReadDOC(virtadr, AliasResolution);
if (oldval != newval)
continue;
- if (ChipID == DOC_ChipID_DocMilPlus16) {
- WriteDOC(~newval, virtadr, Mplus_AliasResolution);
- oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
- WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
- } else {
- WriteDOC(~newval, virtadr, AliasResolution);
- oldval = ReadDOC(doc->virtadr, AliasResolution);
- WriteDOC(newval, virtadr, AliasResolution); // restore it
- }
+ WriteDOC(~newval, virtadr, AliasResolution);
+ oldval = ReadDOC(doc->virtadr, AliasResolution);
+ WriteDOC(newval, virtadr, AliasResolution); // restore it
newval = ~newval;
if (oldval == newval) {
- printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
+ //printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
goto notfound;
}
}
if (ChipID == DOC_ChipID_Doc2k)
numchips = doc2000_init(mtd);
- else if (ChipID == DOC_ChipID_DocMilPlus16)
- numchips = doc2001plus_init(mtd);
else
numchips = doc2001_init(mtd);
kfree(mtd);
}
}
-
+
module_init(init_nanddoc);
module_exit(cleanup_nanddoc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n");
+MODULE_DESCRIPTION("M-Systems DiskOnChip 2000 and Millennium device driver\n");