mtd/drivers/mtd/nand nand.c,1.65,1.66

gleixner at infradead.org gleixner at infradead.org
Sun Mar 28 14:50:01 EST 2004


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

Modified Files:
	nand.c 
Log Message:
identify new devices, basic functions for 16 bit buswidth

Index: nand.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -r1.65 -r1.66
--- nand.c	28 Mar 2004 19:08:34 -0000	1.65
+++ nand.c	28 Mar 2004 19:49:58 -0000	1.66
@@ -157,6 +157,7 @@
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/compatmac.h>
 #include <linux/interrupt.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
 
 /*
@@ -194,6 +195,18 @@
 	writeb(byte, this->IO_ADDR_W);
 }
 
+static u16 nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+	return readw(this->IO_ADDR_R);
+}
+
+static void nand_write_word(struct mtd_info *mtd, u16 word)
+{
+	struct nand_chip *this = mtd->priv;
+	writew(word, this->IO_ADDR_W);
+}
+
 static void nand_select_chip(struct mtd_info *mtd, int chip)
 {
 	struct nand_chip *this = mtd->priv;
@@ -240,18 +253,73 @@
 	return 0;
 }
 
+static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd->priv;
+	u16 *p = (u16 *) buf;
+	len >>= 1;
+	
+	for (i=0; i<len; i++)
+		writew(p[i], this->IO_ADDR_W);
+		
+}
+
+static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd->priv;
+	u16 *p = (u16 *) buf;
+	len >>= 1;
+
+	for (i=0; i<len; i++)
+		p[i] = readw(this->IO_ADDR_R);
+}
+
+static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd->priv;
+	u16 *p = (u16 *) buf;
+	len >>= 1;
+
+	for (i=0; i<len; i++)
+		if (p[i] != readw(this->IO_ADDR_R))
+			return -EFAULT;
+
+	return 0;
+}
+
 /* Appropriate chip should already be selected */
 static int nand_block_bad(struct mtd_info *mtd, unsigned long page)
 {
 	struct nand_chip *this = mtd->priv;
 	
-	this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
+	this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page);
 	if (this->read_byte(mtd) != 0xff)
 		return 1;
 
 	return 0;
 }
 
+/* Appropriate chip should already be selected */
+static int nand_block_bad16(struct mtd_info *mtd, unsigned long page)
+{
+	struct nand_chip *this = mtd->priv;
+	u16 bad;
+	
+	this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page);
+
+	bad = this->read_word(mtd);
+	if (this->badblockpos & 0x1)
+		bad >>= 1;
+
+	if ((bad & 0xFF) != 0xff)
+		return 1;
+
+	return 0;
+}
+
 /*
  * Send command to NAND device
  */
@@ -1376,20 +1444,16 @@
 	if (this->waitfunc == NULL)
 		this->waitfunc = nand_wait;
 
-	if (!this->block_bad)
-		this->block_bad = nand_block_bad;
 	if (!this->select_chip)
 		this->select_chip = nand_select_chip;
 	if (!this->write_byte)
 		this->write_byte = nand_write_byte;
 	if (!this->read_byte)
 		this->read_byte = nand_read_byte;
-	if (!this->write_buf)
-		this->write_buf = nand_write_buf;
-	if (!this->read_buf)
-		this->read_buf = nand_read_buf;
-	if (!this->verify_buf)
-		this->verify_buf = nand_verify_buf;
+	if (!this->write_word)
+		this->write_word = nand_write_word;
+	if (!this->read_word)
+		this->read_word = nand_read_word;
 
 	/* Select the device */
 	this->select_chip(mtd, 0);
@@ -1403,30 +1467,75 @@
 
 	/* Print and store flash device information */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {
-			mtd->name = nand_flash_ids[i].name;
+		
+		int busw = 0;
+		
+		if (nand_dev_id != nand_flash_ids[i].id) 
+			continue;
+			
+		mtd->name = nand_flash_ids[i].name;
+		mtd->size = nand_flash_ids[i].chipsize << 20;
+		
+		/* New devices have all the information in additional id bytes */
+		if (!nand_flash_ids[i].pagesize) {
+			int extid;
+			/* The 3rd id byte contains non relevant data ATM */
+			extid = this->read_byte(mtd);
+			/* The 4th id byte is the important one */
+			extid = this->read_byte(mtd);
+			/* Calc pagesize */
+			mtd->oobblock = 1024 << (extid & 0x3);
+			extid >>= 2;
+			/* Calc oobsize */
+			mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512);
+			extid >>= 2;
+			/* Calc blocksize. Blocksize is multiples of 64KiB */
+			mtd->erasesize = (64 * 1024)  << (extid & 0x03);
+			extid >>= 2;
+			/* Get buswidth information */
+			busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+		} else {
+			/* Old devices have this data hardcoded in the
+			 * device id table */
 			mtd->erasesize = nand_flash_ids[i].erasesize;
-			mtd->eccsize = 256;
-			this->chipshift = nand_flash_ids[i].chipshift;
-			if (nand_flash_ids[i].page256) {
-				mtd->oobblock = 256;
-				mtd->oobsize = 8;
-				this->page_shift = 8;
-			} else {
-				mtd->oobblock = 512;
-				mtd->oobsize = 16;
-				this->page_shift = 9;
-			}
-			/* Try to identify manufacturer */
-			for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
-				if (nand_manuf_ids[i].id == nand_maf_id)
-					break;
-			}	
-			printk (KERN_INFO "NAND device: Manufacturer ID:"
-				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-				nand_manuf_ids[i].name , mtd->name);
-			break;
+			mtd->oobblock = nand_flash_ids[i].pagesize;
+			mtd->oobsize = mtd->oobblock / 32;
+			busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
+		}
+
+		/* Check, if buswidth has to be changed */
+		if (busw != (this->options & NAND_BUSWIDTH_16)) {
+			this->options &= ~NAND_BUSWIDTH_16;
+			this->options |= busw;
+			printk (KERN_WARNING 
+				"NAND bus width switched to %d bit\n", busw ? 16 : 8);
 		}
+		
+		/* Calculate the address shift from the page size */	
+		this->page_shift = ffs(mtd->oobblock) - 1;
+
+		/* Set the bad block position */
+		this->badblockpos = mtd->oobblock > 512 ? 
+			NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
+
+		if (!this->block_bad)
+			this->block_bad = busw ? nand_block_bad16 : nand_block_bad;
+		if (!this->write_buf)
+			this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
+		if (!this->read_buf)
+			this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
+		if (!this->verify_buf)
+			this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
+		
+		/* Try to identify manufacturer */
+		for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
+			if (nand_manuf_ids[i].id == nand_maf_id)
+				break;
+		}	
+		printk (KERN_INFO "NAND device: Manufacturer ID:"
+			" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+			nand_manuf_ids[i].name , mtd->name);
+		break;
 	}
 
 	if (!mtd->name) {
@@ -1447,8 +1556,6 @@
 	}
 	if (i > 1)
 		printk(KERN_INFO "%d NAND chips detected\n", i);
-
-	mtd->size = (1 << this->chipshift) /* * i when we fix the rest of the code */;
 
 	/* 
 	 * check ECC mode, default to software




More information about the linux-mtd-cvs mailing list