mtd/drivers/mtd/nand diskonchip.c,1.18,1.19

dbrown at infradead.org dbrown at infradead.org
Fri Jun 25 10:39:02 EDT 2004


Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv18502

Modified Files:
	diskonchip.c 
Log Message:
Add proper probing and multiple device support.


Index: diskonchip.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/diskonchip.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- diskonchip.c	24 Jun 2004 15:02:50 -0000	1.18
+++ diskonchip.c	25 Jun 2004 14:38:59 -0000	1.19
@@ -23,6 +23,40 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/inftl.h>
 
+/* Where to look for the devices? */
+#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_DOCPROBE_HIGH
+	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
+	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
+	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
+	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 
+	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
+#else /*  CONFIG_MTD_DOCPROBE_HIGH */
+	0xc8000, 0xca000, 0xcc000, 0xce000, 
+	0xd0000, 0xd2000, 0xd4000, 0xd6000,
+	0xd8000, 0xda000, 0xdc000, 0xde000, 
+	0xe0000, 0xe2000, 0xe4000, 0xe6000, 
+	0xe8000, 0xea000, 0xec000, 0xee000,
+#endif /*  CONFIG_MTD_DOCPROBE_HIGH */
+#elif defined(__PPC__)
+	0xe4000000,
+#elif defined(CONFIG_MOMENCO_OCELOT)
+	0x2f000000,
+        0xff000000,
+#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
+        0xff000000,
+##else
+#warning Unknown architecture for DiskOnChip. No default probe locations defined
+#endif
+	0xffffffff };
+
+static struct mtd_info *doclist = NULL;
+
 struct doc_priv {
 	unsigned long virtadr;
 	unsigned long physadr;
@@ -33,6 +67,7 @@
 	int curchip;
 	int mh0_page;
 	int mh1_page;
+	struct mtd_info *nextdoc;
 };
 
 /* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
@@ -49,36 +84,6 @@
 
 #define INFTL_BBT_RESERVED_BLOCKS 4
 
-static struct nand_bbt_descr inftl_bbt_descr0 = {
-        .options =NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION,
-        .offs =8,
-        .len = 8,
-        .veroffs = 6,
-        .maxblocks = INFTL_BBT_RESERVED_BLOCKS,
-        .reserved_block_code = 0x01,
-        .pattern = "MSYS_BBT"
-};
-
-static struct nand_bbt_descr inftl_bbt_descr1 = {
-        .options =NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION,
-        .offs =8,
-        .len = 8,
-        .veroffs = 6,
-        .maxblocks = INFTL_BBT_RESERVED_BLOCKS,
-        .reserved_block_code = 0x01,
-        .pattern = "TBB_SYSM"
-};
-
-static struct nand_bbt_descr nftl_bbt_descr0 = {
-	.options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | NAND_BBT_VERSION,
-	.veroffs = 6
-};
-
-static struct nand_bbt_descr nftl_bbt_descr1 = {
-	.options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | NAND_BBT_VERSION,
-	.veroffs = 6
-};
-
 #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
 #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
 
@@ -100,6 +105,10 @@
 static int inftl_bbt_write=0;
 MODULE_PARM(inftl_bbt_write, "i");
 
+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");
+
 static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
 {
 	volatile char dummy;
@@ -480,13 +489,14 @@
 	return 1; 
 }	
 
-static int doc200x_block_bad(struct mtd_info *mtd, unsigned long block)
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 {
-	/* FIXME: Look it up in the BBT */
+	/* This is our last resort if we couldn't find or create a BBT.  Just
+	   pretend all blocks are good. */
 	return 0;
 }
 
-static int doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
+static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
 {
 	struct nand_chip *this = mtd->priv;
 	struct doc_priv *doc = (void *)this->priv;
@@ -503,7 +513,6 @@
 		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
 		break;
 	}	
-	return 0;
 }
 
 /* This code is only called on write */
@@ -618,12 +627,6 @@
 	return ret;
 }
 		
-static struct doc_priv mydoc = {
-	.physadr = 0xd0000,
-	.curfloor = -1,
-	.curchip = -1,
-};
-
 //u_char mydatabuf[528];
 
 static struct nand_oobinfo doc200x_oobinfo = {
@@ -633,27 +636,6 @@
         .oobfree = { {8, 8} }
 };
  
-static struct nand_chip mynand = {
-	.priv = (void *)&mydoc,
-	.select_chip = doc200x_select_chip,
-	.hwcontrol = doc200x_hwcontrol,
-	.dev_ready = doc200x_dev_ready,
-	.waitfunc = doc200x_wait,
-	.block_bad = doc200x_block_bad,
-	.eccmode = NAND_ECC_HW6_512,
-	//.data_buf = mydatabuf,
-	.options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME,
-	.autooob = &doc200x_oobinfo,
-	.correct_data = doc200x_correct_data,
-	.enable_hwecc = doc200x_enable_hwecc,
-	.calculate_ecc = doc200x_calculate_ecc
-};
-
-static struct mtd_info mymtd = {
-	.priv = (void *)&mynand,
-	.owner = THIS_MODULE,
-};
-
 /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
    On sucessful return, buf will contain a copy of the media header for
    further processing.  id is the string to scan for, and will presumably be
@@ -702,7 +684,7 @@
 	return 1;
 }
 
-static int __init nftl_partscan(struct mtd_info *mtd,
+static inline int __init nftl_partscan(struct mtd_info *mtd,
 				struct mtd_partition *parts)
 {
 	struct nand_chip *this = mtd->priv;
@@ -768,17 +750,17 @@
 	offs <<= this->page_shift;
 	offs += mtd->erasesize;
 
-	//parts[0].name = "DiskOnChip Boot / Media Header partition";
+	//parts[0].name = " DiskOnChip Boot / Media Header partition";
 	//parts[0].offset = 0;
 	//parts[0].size = offs;
 
-	parts[0].name = "DiskOnChip BDTL partition";
+	parts[0].name = " DiskOnChip BDTL partition";
 	parts[0].offset = offs;
 	parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
 
 	offs += parts[0].size;
 	if (offs < mtd->size) {
-		parts[1].name = "DiskOnChip Remainder partition";
+		parts[1].name = " DiskOnChip Remainder partition";
 		parts[1].offset = offs;
 		parts[1].size = mtd->size - offs;
 		return 2;
@@ -787,7 +769,7 @@
 }
 
 /* This is a stripped-down copy of the code in inftlmount.c */
-static int __init inftl_partscan(struct mtd_info *mtd,
+static inline int __init inftl_partscan(struct mtd_info *mtd,
 				 struct mtd_partition *parts)
 {
 	struct nand_chip *this = mtd->priv;
@@ -870,7 +852,7 @@
 
 /*
 		if ((i == 0) && (ip->firstUnit > 0)) {
-			parts[0].name = "DiskOnChip IPL / Media Header partition";
+			parts[0].name = " DiskOnChip IPL / Media Header partition";
 			parts[0].offset = 0;
 			parts[0].size = mtd->erasesize * ip->firstUnit;
 			numparts = 1;
@@ -878,9 +860,9 @@
 */
 
 		if (ip->flags & INFTL_BINARY)
-			parts[numparts].name = "DiskOnChip BDK partition";
+			parts[numparts].name = " DiskOnChip BDK partition";
 		else
-			parts[numparts].name = "DiskOnChip BDTL partition";
+			parts[numparts].name = " DiskOnChip BDTL partition";
 		parts[numparts].offset = ip->firstUnit << vshift;
 		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
 		numparts++;
@@ -889,7 +871,7 @@
 	}
 	lastvunit++;
 	if ((lastvunit << vshift) < end) {
-		parts[numparts].name = "DiskOnChip Remainder partition";
+		parts[numparts].name = " DiskOnChip Remainder partition";
 		parts[numparts].offset = lastvunit << vshift;
 		parts[numparts].size = end - parts[numparts].offset;
 		numparts++;
@@ -897,7 +879,7 @@
 	return numparts;
 }
 
-int __init nftl_scan_bbt(struct mtd_info *mtd)
+static int __init nftl_scan_bbt(struct mtd_info *mtd)
 {
 	int ret, numparts;
 	struct nand_chip *this = mtd->priv;
@@ -909,14 +891,25 @@
 	   BBTs, since they're stored in the media header eraseblocks. */
 	numparts = nftl_partscan(mtd, parts);
 	if (!numparts) return -EIO;
+	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+				NAND_BBT_VERSION;
+	this->bbt_td->veroffs = 6;
 	this->bbt_td->pages[0] = doc->mh0_page + 1;
-	if (doc->mh1_page == -1)
-		this->bbt_md = NULL;
-	else
+	if (doc->mh1_page != -1) {
+		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+					NAND_BBT_VERSION;
+		this->bbt_md->veroffs = 6;
 		this->bbt_md->pages[0] = doc->mh1_page + 1;
+	} else {
+		this->bbt_md = NULL;
+	}
+
 	/* 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)) return ret;
+	if ((ret = nand_scan_bbt(mtd, NULL)))
+		return ret;
 	add_mtd_device(mtd);
 #if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
 	if (!no_autopart) add_mtd_partitions(mtd, parts, numparts);
@@ -924,7 +917,7 @@
 	return 0;
 }
 
-int __init inftl_scan_bbt(struct mtd_info *mtd)
+static int __init inftl_scan_bbt(struct mtd_info *mtd)
 {
 	int ret, numparts;
 	struct nand_chip *this = mtd->priv;
@@ -935,13 +928,33 @@
 		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
 		return -EIO;
 	}
-	if (inftl_bbt_write) {
+
+	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 = 6;
+	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 = 6;
+	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)) return ret;
+	if ((ret = nand_scan_bbt(mtd, NULL)))
+		return ret;
 	memset((char *) parts, 0, sizeof(parts));
 	numparts = inftl_partscan(mtd, parts);
 	/* At least for now, require the INFTL Media Header.  We could probably
@@ -955,92 +968,250 @@
 	return 0;
 }
 
-int __init init_nanddoc(void)
+static inline int __init doc2000_init(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+	struct doc_priv *doc = (void *)this->priv;
+
+	this->write_byte = doc2000_write_byte;
+	this->read_byte = doc2000_read_byte;
+	this->write_buf = doc2000_writebuf;
+	this->read_buf = doc2000_readbuf;
+	this->verify_buf = doc2000_verifybuf;
+	this->scan_bbt = nftl_scan_bbt;
+
+	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
+	doc2000_count_chips(mtd);
+	mtd->name = "DiskOnChip 2000 (NFTL Model)";
+	return (4 * doc->chips_per_floor);
+}
+
+static inline int __init doc2001_init(struct mtd_info *mtd)
 {
-	int ret;
-	int nrchips = 1;
-	mydoc.virtadr = (unsigned long)ioremap(mydoc.physadr, DOC_IOREMAP_LEN);
-	mydoc.mh0_page = mydoc.mh1_page = -1;
+	struct nand_chip *this = mtd->priv;
+	struct doc_priv *doc = (void *)this->priv;
 
+	this->write_byte = doc2001_write_byte;
+	this->read_byte = doc2001_read_byte;
+	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);
+	ReadDOC(doc->virtadr, ChipID);
+	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
+		/* It's not a Millennium; it's one of the newer
+		   DiskOnChip 2000 units with a similar ASIC. 
+		   Treat it like a Millennium, except that it
+		   can have multiple chips. */
+		doc2000_count_chips(mtd);
+		mtd->name = "DiskOnChip 2000 (INFTL Model)";
+		return (4 * doc->chips_per_floor);
+	} else {
+		/* Bog-standard Millennium */
+		doc->chips_per_floor = 1;
+		mtd->name = "DiskOnChip Millennium";
+		return 1;
+	}
+}
+
+static inline int __init doc_probe(unsigned long physadr)
+{
+	unsigned char ChipID;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	struct doc_priv *doc;
+	unsigned long virtadr;
+	unsigned char save_control;
+	unsigned char tmp, tmpb, tmpc;
+	int reg, len, numchips;
+	int ret = 0;
+
+	virtadr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
+	if (!virtadr) {
+		printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
+		return -EIO;
+	}
+
+	/* It's not possible to cleanly detect the DiskOnChip - the
+	 * bootup procedure will put the device into reset mode, and
+	 * it's not possible to talk to it without actually writing
+	 * to the DOCControl register. So we store the current contents
+	 * of the DOCControl register's location, in case we later decide
+	 * that it's not a DiskOnChip, and want to put it back how we
+	 * found it. 
+	 */
+	save_control = ReadDOC(virtadr, DOCControl);
+
+	/* Reset the DiskOnChip ASIC */
 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
-		 mydoc.virtadr, DOCControl);
+		 virtadr, DOCControl);
 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
-		 mydoc.virtadr, DOCControl);
+		 virtadr, DOCControl);
 
+	/* Enable the DiskOnChip ASIC */
 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
-		 mydoc.virtadr, DOCControl);
+		 virtadr, DOCControl);
 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
-		 mydoc.virtadr, DOCControl);
+		 virtadr, DOCControl);
 
-	mydoc.ChipID = ReadDOC(mydoc.virtadr, ChipID);
+	ChipID = ReadDOC(virtadr, ChipID);
 
-	switch(mydoc.ChipID) {
+	switch(ChipID) {
+	case DOC_ChipID_Doc2k:
+		reg = DoC_2k_ECCStatus;
+		break;
 	case DOC_ChipID_DocMil:
-		mynand.write_byte = doc2001_write_byte;
-		mynand.read_byte = doc2001_read_byte;
-		mynand.write_buf = doc2001_writebuf;
-		mynand.read_buf = doc2001_readbuf;
-		mynand.verify_buf = doc2001_verifybuf;
-                mynand.bbt_td = &inftl_bbt_descr0;
-                mynand.bbt_md = &inftl_bbt_descr1;
-		mynand.scan_bbt = inftl_scan_bbt;
-
-		ReadDOC(mydoc.virtadr, ChipID);
-		ReadDOC(mydoc.virtadr, ChipID);
-		if (ReadDOC(mydoc.virtadr, ChipID) != DOC_ChipID_DocMil) {
-			/* It's not a Millennium; it's one of the newer
-			   DiskOnChip 2000 units with a similar ASIC. 
-			   Treat it like a Millennium, except that it
-			   can have multiple chips. */
-			doc2000_count_chips(&mymtd);
-			nrchips = 4 * mydoc.chips_per_floor;
-			mymtd.name = "DiskOnChip 2000 (INFTL Model)";
-		} else {
-			/* Bog-standard Millennium */
-			mydoc.chips_per_floor = 1;
-			nrchips = 1;
-			mymtd.name = "DiskOnChip Millennium";
-		}
+		reg = DoC_ECCConf;
 		break;
+	default:
+		ret = -ENODEV;
+		goto notfound;
+	}
+	/* Check the TOGGLE bit in the ECC register */
+	tmp  = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+	if ((tmp == tmpb) || (tmp != tmpc)) {
+		printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
+		ret = -ENODEV;
+		goto notfound;
+	}
+
+	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
+		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. */
+		unsigned char oldval = ReadDOC(doc->virtadr, AliasResolution);
+		unsigned char newval = ReadDOC(virtadr, AliasResolution);
+		if (oldval != newval)
+			continue;
+		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);
+			goto notfound;
+		}
+	}
 
-	case DOC_ChipID_Doc2k:
-		mynand.write_byte = doc2000_write_byte;
-		mynand.read_byte = doc2000_read_byte;
-		mynand.write_buf = doc2000_writebuf;
-		mynand.read_buf = doc2000_readbuf;
-		mynand.verify_buf = doc2000_verifybuf;
-                mynand.bbt_td = &nftl_bbt_descr0;
-                mynand.bbt_md = &nftl_bbt_descr1;
-		mynand.scan_bbt = nftl_scan_bbt;
-
-		mydoc.CDSNControl |= CDSN_CTRL_FLASH_IO|CDSN_CTRL_ECC_IO;
-		doc2000_count_chips(&mymtd);
-		nrchips = 4 * mydoc.chips_per_floor;
-		mymtd.name = "DiskOnChip 2000 (NFTL Model)";
+	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
 
-		break;
+	len = sizeof(struct mtd_info) +
+	      sizeof(struct nand_chip) +
+	      sizeof(struct doc_priv) +
+	      (2 * sizeof(struct nand_bbt_descr));
+	mtd = kmalloc(len, GFP_KERNEL);
+	if (!mtd) {
+		printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
+		ret = -ENOMEM;
+		goto fail;
+	}
+	memset(mtd, 0, len);
+
+	nand			= (struct nand_chip *) (mtd + 1);
+	doc			= (struct doc_priv *) (nand + 1);
+	nand->bbt_td		= (struct nand_bbt_descr *) (doc + 1);
+	nand->bbt_md		= nand->bbt_td + 1;
+
+	mtd->priv		= (void *) nand;
+	mtd->owner		= THIS_MODULE;
+
+	nand->priv		= (void *) doc;
+	nand->select_chip	= doc200x_select_chip;
+	nand->hwcontrol		= doc200x_hwcontrol;
+	nand->dev_ready		= doc200x_dev_ready;
+	nand->waitfunc		= doc200x_wait;
+	nand->block_bad		= doc200x_block_bad;
+	nand->enable_hwecc	= doc200x_enable_hwecc;
+	nand->calculate_ecc	= doc200x_calculate_ecc;
+	nand->correct_data	= doc200x_correct_data;
+	//nand->data_buf
+	nand->autooob		= &doc200x_oobinfo;
+	nand->eccmode		= NAND_ECC_HW6_512;
+	nand->options		= NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
+
+	doc->physadr		= physadr;
+	doc->virtadr		= virtadr;
+	doc->ChipID		= ChipID;
+	doc->curfloor		= -1;
+	doc->curchip		= -1;
+	doc->mh0_page		= -1;
+	doc->mh1_page		= -1;
+	doc->nextdoc		= doclist;
 
-	default:
-		return -EIO;
-	}
-	if (ret = nand_scan(&mymtd, nrchips)) {
+	if (ChipID == DOC_ChipID_Doc2k)
+		numchips = doc2000_init(mtd);
+	else
+		numchips = doc2001_init(mtd);
+
+	if ((ret = nand_scan(mtd, numchips))) {
 		/* DBB note: i believe nand_release is necessary here, as
 		   buffers may have been allocated in nand_base.  Check with
 		   Thomas. FIX ME! */
 		/* nand_release will call del_mtd_device, but we haven't yet
 		   added it.  This is handled without incident by
 		   del_mtd_device, as far as I can tell. */
-		nand_release(&mymtd);
-		iounmap((void *)mydoc.virtadr);
+		nand_release(mtd);
+		kfree(mtd);
+		goto fail;
 	}
 
+	/* Success! */
+	doclist = mtd;
+	return 0;
+
+notfound:
+	/* Put back the contents of the DOCControl register, in case it's not
+	   actually a DiskOnChip.  */
+	WriteDOC(save_control, virtadr, DOCControl);
+fail:
+	iounmap((void *)virtadr);
 	return ret;
 }
 
+int __init init_nanddoc(void)
+{
+	int i;
+
+	if (doc_config_location) {
+		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
+		return doc_probe(doc_config_location);
+	} else {
+		for (i=0; (doc_locations[i] != 0xffffffff); i++) {
+			doc_probe(doc_locations[i]);
+		}
+	}
+	/* No banner message any more. Print a message if no DiskOnChip
+	   found, so the user knows we at least tried. */
+	if (!doclist) {
+		printk(KERN_INFO "No valid DiskOnChip devices found\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
 void __exit cleanup_nanddoc(void)
 {
-	nand_release(&mymtd);
-	iounmap((void *)mydoc.virtadr);
+	struct mtd_info *mtd, *nextmtd;
+	struct nand_chip *nand;
+	struct doc_priv *doc;
+
+	for (mtd = doclist; mtd; mtd = nextmtd) {
+		nand = mtd->priv;
+		doc = (void *)nand->priv;
+
+		nextmtd = doc->nextdoc;
+		nand_release(mtd);
+		iounmap((void *)doc->virtadr);
+		kfree(mtd);
+	}
 }
 	
 module_init(init_nanddoc);





More information about the linux-mtd-cvs mailing list