mtd/drivers/mtd/nand nand.c,1.67,1.68

gleixner at infradead.org gleixner at infradead.org
Sun Mar 28 18:34:10 EST 2004


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

Modified Files:
	nand.c 
Log Message:
select buswidth before scan, add large page command function, fix oob column masks really, fix oob write for devices which need no padding

Index: nand.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand.c,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -r1.67 -r1.68
--- nand.c	28 Mar 2004 21:02:47 -0000	1.67
+++ nand.c	28 Mar 2004 23:34:07 -0000	1.68
@@ -195,6 +195,18 @@
 	writeb(byte, this->IO_ADDR_W);
 }
 
+static u_char nand_read_byte16(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+	return (u_char) readw(this->IO_ADDR_R);
+}
+
+static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
+{
+	struct nand_chip *this = mtd->priv;
+	writew( (u16) byte, this->IO_ADDR_W);
+}
+
 static u16 nand_read_word(struct mtd_info *mtd)
 {
 	struct nand_chip *this = mtd->priv;
@@ -327,6 +339,10 @@
 {
 	register struct nand_chip *this = mtd->priv;
 
+	/* Adjust columns for 16 bit buswidth */
+	if (this->options & NAND_BUSWIDTH_16)
+		column >>= 1;
+
 	/* Begin command latch cycle */
 	this->hwcontrol(mtd, NAND_CTL_SETCLE);
 	/*
@@ -410,6 +426,100 @@
 }
 
 /*
+ * Send command to NAND device. This is the version for the new large page devices
+ * We dont have the seperate regions as we have in the small page devices.
+ * We must emulate NAND_CMD_READOOB to keep the code compatible
+ */
+static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+	register struct nand_chip *this = mtd->priv;
+
+	/* Emulate NAND_CMD_READOOB */
+	if (command == NAND_CMD_READOOB) {
+		column += mtd->oobblock;
+		command = NAND_CMD_READ0;
+	}
+	
+	/* Adjust columns for 16 bit buswidth */
+	if (this->options & NAND_BUSWIDTH_16)
+		column >>= 1;
+		
+	/* Begin command latch cycle */
+	this->hwcontrol(mtd, NAND_CTL_SETCLE);
+	/* Write out the command to the device. */
+	this->write_byte(mtd, command);
+	/* End command latch cycle */
+	this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+
+	if (column != -1 || page_addr != -1) {
+		this->hwcontrol(mtd, NAND_CTL_SETALE);
+
+		/* Serially input address */
+		if (column != -1) {
+			this->write_byte(mtd, column & 0xff);
+			this->write_byte(mtd, column >> 8);
+		}	
+		if (page_addr != -1) {
+			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
+			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+			/* One more address cycle for devices > 128MiB */
+			if (mtd->size > (128 << 20))
+				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff));
+		}
+		/* Latch in address */
+		this->hwcontrol(mtd, NAND_CTL_CLRALE);
+	}
+	
+	/* 
+	 * 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);
+		this->hwcontrol(mtd, NAND_CTL_SETCLE);
+		this->write_byte(mtd, NAND_CMD_STATUS);
+		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+		while ( !(this->read_byte(mtd) & 0x40));
+		return;
+
+	case NAND_CMD_READ0:
+		/* Begin command latch cycle */
+		this->hwcontrol(mtd, NAND_CTL_SETCLE);
+		/* Write out the start read command */
+		this->write_byte(mtd, NAND_CMD_READSTART);
+		/* End command latch cycle */
+		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+		/* Fall through into ready check */
+		
+	/* 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;
+		}	
+	}
+	
+	/* wait until command is processed */
+	while (!this->dev_ready(mtd));
+}
+
+/*
  *	Get chip for selected access
  */
 static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
@@ -873,7 +983,7 @@
 	page = ((int) from) >> this->page_shift;
 
 	/* Mask to get column */
-	col = from & (this->oobsize - 1);
+	col = from & (mtd->oobsize - 1);
 
 	/* Initialize return length value */
 	*retlen = 0;
@@ -1030,7 +1140,13 @@
 
 static u_char ffchars[] = {
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 };
 
 /*
@@ -1050,7 +1166,7 @@
 	page = ((int) to) >> this->page_shift;
 
 	/* Mask to get column */
-	column = to & (this->oobsize - 1);
+	column = to & (mtd->oobsize - 1);
 
 	/* Initialize return length value */
 	*retlen = 0;
@@ -1081,16 +1197,22 @@
 		ret = -EIO;
 		goto out;
 	}
-	/* Write out desired data */
-	this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
-
-	/* prepad 0xff for partial programming */
-	this->write_buf(mtd, ffchars, column);
-	/* write data */
-	this->write_buf(mtd, buf, len);
-	/* postpad 0xff for partial programming */
-	this->write_buf(mtd, ffchars, mtd->oobsize - (len+column));
-
+	
+	if (NAND_MUST_PAD(this)) {
+		/* Write out desired data */
+		this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
+		/* prepad 0xff for partial programming */
+		this->write_buf(mtd, ffchars, column);
+		/* write data */
+		this->write_buf(mtd, buf, len);
+		/* postpad 0xff for partial programming */
+		this->write_buf(mtd, ffchars, mtd->oobsize - (len+column));
+	} else {
+		/* Write out desired data */
+		this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page);
+		/* write data */
+		this->write_buf(mtd, buf, len);
+	}
 	/* Send command to program the OOB data */
 	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
 
@@ -1429,9 +1551,12 @@
  */
 int nand_scan (struct mtd_info *mtd, int maxchips)
 {
-	int i, nand_maf_id, nand_dev_id;
+	int i, nand_maf_id, nand_dev_id, busw;
 	struct nand_chip *this = mtd->priv;
 
+	/* Get buswidth to select the correct functions*/
+	busw = this->options & NAND_BUSWIDTH_16;
+
 	/* check for proper chip_delay setup, set 20us if not */
 	if (!this->chip_delay)
 		this->chip_delay = 20;
@@ -1447,13 +1572,21 @@
 	if (!this->select_chip)
 		this->select_chip = nand_select_chip;
 	if (!this->write_byte)
-		this->write_byte = nand_write_byte;
+		this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
 	if (!this->read_byte)
-		this->read_byte = nand_read_byte;
+		this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
 	if (!this->write_word)
 		this->write_word = nand_write_word;
 	if (!this->read_word)
 		this->read_word = nand_read_word;
+	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;
 
 	/* Select the device */
 	this->select_chip(mtd, 0);
@@ -1467,9 +1600,7 @@
 
 	/* Print and store flash device information */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		
-		int busw = 0;
-		
+				
 		if (nand_dev_id != nand_flash_ids[i].id) 
 			continue;
 			
@@ -1494,6 +1625,10 @@
 			extid >>= 2;
 			/* Get buswidth information */
 			busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+		
+			/* Do not replace user supplied command function ! */
+			if (this->cmdfunc == nand_command)
+				this->cmdfunc = nand_command_lp;
 		} else {
 			/* Old devices have this data hardcoded in the
 			 * device id table */
@@ -1503,12 +1638,14 @@
 			busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
 		}
 
-		/* Check, if buswidth has to be changed */
+		/* Check, if buswidth is correct. Hardware drivers should set
+		 * this correct ! */
 		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);
+				"NAND bus width %d instead %d bit\n", 
+					(this->options & NAND_BUSWIDTH_16) ? 16 : 8,
+					busw ? 16 : 8);
+			return 1;	
 		}
 		
 		/* Calculate the address shift from the page size */	
@@ -1518,14 +1655,11 @@
 		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;
+		/* Get chip options */
+		this->options = nand_flash_ids[i].options;
+		/* Check if this is a not a samsung device */	
+		if (nand_maf_id != NAND_MFR_SAMSUNG)
+			this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
 		
 		/* Try to identify manufacturer */
 		for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
@@ -1535,6 +1669,8 @@
 		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;
 	}
 




More information about the linux-mtd-cvs mailing list