X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmtd%2Fnand%2Fdiskonchip.c;h=677c21685218eb3f2b760029764bfc7524b6ebd6;hb=1341115471cc16954510b0e67295468f5a32b088;hp=0f7dedd6b88ecd95fd30d3ac761c11574478488d;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0f7dedd6b..677c21685 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -2,16 +2,12 @@ * drivers/mtd/nand/diskonchip.c * * (C) 2003 Red Hat, Inc. - * (C) 2004 Dan Brown - * (C) 2004 Kalev Lember * * Author: David Woodhouse - * Additional Diskonchip 2000 and Millennium support by Dan Brown - * Diskonchip Millennium Plus support by Kalev Lember * * 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 @@ -28,13 +24,13 @@ #include /* 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, @@ -88,7 +84,6 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; #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) @@ -114,7 +109,7 @@ static int inftl_bbt_write=0; #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"); @@ -126,16 +121,11 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) 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) { @@ -144,24 +134,13 @@ 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; @@ -172,21 +151,13 @@ static inline int DoC_WaitReady(struct doc_priv *doc) 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; } @@ -411,7 +382,7 @@ static void doc2001_readbuf(struct mtd_info *mtd, 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); @@ -438,120 +409,6 @@ static int doc2001_verifybuf(struct mtd_info *mtd, 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; @@ -559,6 +416,9 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) 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) @@ -567,9 +427,6 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) 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); @@ -617,140 +474,24 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) 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) { @@ -775,26 +516,7 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) 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 */ @@ -814,10 +536,6 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, 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); @@ -825,17 +543,11 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, } 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) { @@ -870,10 +582,6 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ 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); @@ -883,10 +591,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ /* 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; } @@ -918,10 +623,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ 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; @@ -949,9 +651,8 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, { 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) { @@ -992,20 +693,13 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, { 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) @@ -1020,7 +714,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, //#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: @@ -1031,7 +725,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, 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); @@ -1047,12 +741,12 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, 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. */ @@ -1073,13 +767,9 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, 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 */ @@ -1088,9 +778,8 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, { 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; @@ -1101,15 +790,8 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, 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); @@ -1126,17 +808,13 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, " 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; @@ -1144,13 +822,13 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, 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 */ @@ -1202,10 +880,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, 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) @@ -1240,9 +915,8 @@ 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; } @@ -1259,36 +933,39 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) 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))) @@ -1300,9 +977,8 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) 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; } @@ -1335,6 +1011,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd) 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); @@ -1346,39 +1023,15 @@ static inline int __init doc2001_init(struct mtd_info *mtd) 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; @@ -1428,42 +1081,6 @@ static inline int __init doc_probe(unsigned long physadr) 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; @@ -1479,35 +1096,22 @@ static inline int __init doc_probe(unsigned long physadr) } 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; } } @@ -1559,8 +1163,6 @@ static inline int __init doc_probe(unsigned long physadr) if (ChipID == DOC_ChipID_Doc2k) numchips = doc2000_init(mtd); - else if (ChipID == DOC_ChipID_DocMilPlus16) - numchips = doc2001plus_init(mtd); else numchips = doc2001_init(mtd); @@ -1626,10 +1228,10 @@ void __exit cleanup_nanddoc(void) kfree(mtd); } } - + module_init(init_nanddoc); module_exit(cleanup_nanddoc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse "); -MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n"); +MODULE_DESCRIPTION("M-Systems DiskOnChip 2000 and Millennium device driver\n");