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