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