From 3f90fc9d3ec1f729ce7fb464829391bf91b94aad Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 20 Oct 2007 01:13:46 +0200 Subject: [PATCH] NAND support work in progress --- drivers/nand/Makefile | 1 + drivers/nand/nand.c | 59 +-- drivers/nand/nand_base.c | 998 +++++++++++------------------------ drivers/nand/nand_bbt.c | 155 +++--- drivers/nand/nand_ecc.c | 4 +- drivers/nand/nand_ids.c | 155 +++--- include/linux/mtd/mtd.h | 88 +-- include/linux/mtd/nand.h | 118 ++++- include/linux/mtd/nand_ecc.h | 4 +- include/nand.h | 124 ----- 10 files changed, 585 insertions(+), 1121 deletions(-) delete mode 100644 include/nand.h diff --git a/drivers/nand/Makefile b/drivers/nand/Makefile index f5cfacf06..0d82aca74 100644 --- a/drivers/nand/Makefile +++ b/drivers/nand/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_NAND) += nand_bbt.o obj-$(CONFIG_NAND) += nand.o obj-$(CONFIG_NAND) += nand_ecc.o obj-$(CONFIG_NAND) += nand_ids.o +obj-$(CONFIG_NAND) += imx_nand.o #obj-$(CONFIG_NAND) += nand_util.o diff --git a/drivers/nand/nand.c b/drivers/nand/nand.c index 18f90a035..6700655d9 100644 --- a/drivers/nand/nand.c +++ b/drivers/nand/nand.c @@ -22,59 +22,50 @@ */ #include -#include +#include #include #include #include -char *default_nand_name = "huhu"; - -static inline int board_nand_init(struct nand_chip *nand) +static ssize_t nand_read(struct device_d *dev, void* buf, size_t count, ulong offset, ulong flags) { - return 0; + struct nand_chip *nand = dev->priv; + size_t retlen; + int ret; + char oobuf[NAND_MAX_OOBSIZE]; + + printf("%s\n", __FUNCTION__); + + ret = nand->read_ecc(nand, offset, count, &retlen, buf, oobuf, &nand->oobinfo); + + if(ret) + return ret; + return retlen; } -static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, - ulong base_addr) +static ssize_t nand_write(struct device_d* dev, const void* buf, size_t count, ulong offset, ulong flags) { - mtd->priv = nand; - - nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; - if (board_nand_init(nand) == 0) { - if (nand_scan(mtd, 1) == 0) { - if (!mtd->name) - mtd->name = (char *)default_nand_name; - } else - mtd->name = NULL; - } else { - mtd->name = NULL; - mtd->size = 0; - } + struct nand_chip *nand = dev->priv; + size_t retlen; + int ret; + ret = nand->write_ecc(nand, offset, count, &retlen, buf, NULL, &nand->oobinfo); + if (ret) + return ret; + return retlen; } -struct nand_host { - struct mtd_info info; - struct nand_chip chip; - struct device_d *dev; -}; - static int nand_probe (struct device_d *dev) { - struct nand_host *host; - - host = xzalloc(sizeof(*host)); - - nand_init_chip(&host->info, &host->chip, dev->map_base); - + printf("%s\n", __FUNCTION__); return 0; } static struct driver_d nand_driver = { .name = "nand_flash", .probe = nand_probe, -// .read = nand_read, -// .write = nand_write, + .read = nand_read, + .write = nand_write, // .erase = nand_erase, // .protect= nand_protect, // .memmap = generic_memmap_ro, diff --git a/drivers/nand/nand_base.c b/drivers/nand/nand_base.c index 4969a447d..ab1003f63 100644 --- a/drivers/nand/nand_base.c +++ b/drivers/nand/nand_base.c @@ -127,73 +127,35 @@ static u_char ffchars[] = { /* * NAND low-level MTD interface functions */ -static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); -static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); -static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); +static void nand_write_buf(struct nand_chip *this, const u_char *buf, int len); +static void nand_read_buf(struct nand_chip *this, u_char *buf, int len); +static int nand_verify_buf(struct nand_chip *this, const u_char *buf, int len); -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, +static int nand_read (struct nand_chip *this, loff_t from, size_t len, size_t * retlen, u_char * buf); +static int nand_read_ecc (struct nand_chip *this, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf); -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, +static int nand_read_oob (struct nand_chip *this, loff_t from, size_t len, size_t * retlen, u_char * buf); +static int nand_write (struct nand_chip *this, loff_t to, size_t len, size_t * retlen, const u_char * buf); +static int nand_write_ecc (struct nand_chip *this, loff_t to, size_t len, size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf); -/* XXX U-BOOT XXX */ -#if 0 -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t * retlen); -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); -#endif -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); -static void nand_sync (struct mtd_info *mtd); +static int nand_write_oob (struct nand_chip *this, loff_t to, size_t len, size_t * retlen, const u_char *buf); +static int nand_erase (struct nand_chip *this, struct erase_info *instr); +static void nand_sync (struct nand_chip *this); /* Some internal functions */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, +static int nand_write_page (struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int mode); #ifdef CONFIG_MTD_NAND_VERIFY_WRITE -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); #else #define nand_verify_pages(...) (0) #endif -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); - -/** - * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure - * - * Deselect, release chip lock and wake up anyone waiting on the device - */ -/* XXX U-BOOT XXX */ -#if 0 -static void nand_release_device (struct mtd_info *mtd) +static void nand_release_device (struct nand_chip *this) { - struct nand_chip *this = mtd->priv; - - /* De-select the NAND device */ - this->select_chip(mtd, -1); - /* Do we have a hardware controller ? */ - if (this->controller) { - spin_lock(&this->controller->lock); - this->controller->active = NULL; - spin_unlock(&this->controller->lock); - } - /* Release the chip */ - spin_lock (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock (&this->chip_lock); + this->select_chip(this, -1); /* De-select the NAND device */ } -#else -static void nand_release_device (struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - this->select_chip(mtd, -1); /* De-select the NAND device */ -} -#endif /** * nand_read_byte - [DEFAULT] read one byte from the chip @@ -201,9 +163,8 @@ static void nand_release_device (struct mtd_info *mtd) * * Default read function for 8bit buswith */ -static u_char nand_read_byte(struct mtd_info *mtd) +static u_char nand_read_byte(struct nand_chip *this) { - struct nand_chip *this = mtd->priv; return readb(this->IO_ADDR_R); } @@ -214,9 +175,8 @@ static u_char nand_read_byte(struct mtd_info *mtd) * * Default write function for 8it buswith */ -static void nand_write_byte(struct mtd_info *mtd, u_char byte) +static void nand_write_byte(struct nand_chip *this, u_char byte) { - struct nand_chip *this = mtd->priv; writeb(byte, this->IO_ADDR_W); } @@ -227,9 +187,8 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) * Default read function for 16bit buswith with * endianess conversion */ -static u_char nand_read_byte16(struct mtd_info *mtd) +static u_char nand_read_byte16(struct nand_chip *this) { - struct nand_chip *this = mtd->priv; return (u_char) cpu_to_le16(readw(this->IO_ADDR_R)); } @@ -241,9 +200,8 @@ static u_char nand_read_byte16(struct mtd_info *mtd) * Default write function for 16bit buswith with * endianess conversion */ -static void nand_write_byte16(struct mtd_info *mtd, u_char byte) +static void nand_write_byte16(struct nand_chip *this, u_char byte) { - struct nand_chip *this = mtd->priv; writew(le16_to_cpu((u16) byte), this->IO_ADDR_W); } @@ -254,9 +212,8 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte) * Default read function for 16bit buswith without * endianess conversion */ -static u16 nand_read_word(struct mtd_info *mtd) +static u16 nand_read_word(struct nand_chip *this) { - struct nand_chip *this = mtd->priv; return readw(this->IO_ADDR_R); } @@ -268,9 +225,8 @@ static u16 nand_read_word(struct mtd_info *mtd) * Default write function for 16bit buswith without * endianess conversion */ -static void nand_write_word(struct mtd_info *mtd, u16 word) +static void nand_write_word(struct nand_chip *this, u16 word) { - struct nand_chip *this = mtd->priv; writew(word, this->IO_ADDR_W); } @@ -281,15 +237,14 @@ static void nand_write_word(struct mtd_info *mtd, u16 word) * * Default select function for 1 chip devices. */ -static void nand_select_chip(struct mtd_info *mtd, int chip) +static void nand_select_chip(struct nand_chip *this, int chip) { - struct nand_chip *this = mtd->priv; switch(chip) { case -1: - this->hwcontrol(mtd, NAND_CTL_CLRNCE); + this->hwcontrol(this, NAND_CTL_CLRNCE); break; case 0: - this->hwcontrol(mtd, NAND_CTL_SETNCE); + this->hwcontrol(this, NAND_CTL_SETNCE); break; default: @@ -305,10 +260,9 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) * * Default write function for 8bit buswith */ -static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void nand_write_buf(struct nand_chip *this, const u_char *buf, int len) { int i; - struct nand_chip *this = mtd->priv; for (i=0; iIO_ADDR_W); @@ -322,10 +276,9 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) * * Default read function for 8bit buswith */ -static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void nand_read_buf(struct nand_chip *this, u_char *buf, int len) { int i; - struct nand_chip *this = mtd->priv; for (i=0; iIO_ADDR_R); @@ -339,10 +292,9 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) * * Default verify function for 8bit buswith */ -static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +static int nand_verify_buf(struct nand_chip *this, const u_char *buf, int len) { int i; - struct nand_chip *this = mtd->priv; for (i=0; iIO_ADDR_R)) @@ -359,10 +311,9 @@ static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) * * Default write function for 16bit buswith */ -static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) +static void nand_write_buf16(struct nand_chip *this, const u_char *buf, int len) { int i; - struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; @@ -379,10 +330,9 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) * * Default read function for 16bit buswith */ -static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) +static void nand_read_buf16(struct nand_chip *this, u_char *buf, int len) { int i; - struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; @@ -398,10 +348,9 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) * * Default verify function for 16bit buswith */ -static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) +static int nand_verify_buf16(struct nand_chip *this, const u_char *buf, int len) { int i; - struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; @@ -420,40 +369,36 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) * * Check, if the block is bad. */ -static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) +static int nand_block_bad(struct nand_chip *this, loff_t ofs, int getchip) { int page, chipnr, res = 0; - struct nand_chip *this = mtd->priv; u16 bad; if (getchip) { page = (int)(ofs >> this->page_shift); chipnr = (int)(ofs >> this->chip_shift); - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_READING); - /* Select the NAND device */ - this->select_chip(mtd, chipnr); + this->select_chip(this, chipnr); } else page = (int) ofs; if (this->options & NAND_BUSWIDTH_16) { - this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); - bad = cpu_to_le16(this->read_word(mtd)); + this->cmdfunc (this, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); + bad = cpu_to_le16(this->read_word(this)); if (this->badblockpos & 0x1) bad >>= 1; if ((bad & 0xFF) != 0xff) res = 1; } else { - this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); - if (this->read_byte(mtd) != 0xff) + this->cmdfunc (this, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); + if (this->read_byte(this) != 0xff) res = 1; } if (getchip) { /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + nand_release_device(this); } return res; @@ -467,9 +412,8 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) * This is the default implementation, which can be overridden by * a hardware specific driver. */ -static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) +static int nand_default_block_markbad(struct nand_chip *this, loff_t ofs) { - struct nand_chip *this = mtd->priv; u_char buf[2] = {0, 0}; size_t retlen; int block; @@ -480,11 +424,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) - return nand_update_bbt (mtd, ofs); + return nand_update_bbt (this, ofs); /* We write two bytes, so we dont have to mess with 16 bit access */ - ofs += mtd->oobsize + (this->badblockpos & ~0x01); - return nand_write_oob (mtd, ofs , 2, &retlen, buf); + ofs += this->oobsize + (this->badblockpos & ~0x01); + return nand_write_oob (this, ofs , 2, &retlen, buf); } /** @@ -494,12 +438,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) * * The function expects, that the device is already selected */ -static int nand_check_wp (struct mtd_info *mtd) +static int nand_check_wp (struct nand_chip *this) { - struct nand_chip *this = mtd->priv; /* Check the WP bit */ - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - return (this->read_byte(mtd) & 0x80) ? 0 : 1; + this->cmdfunc (this, NAND_CMD_STATUS, -1, -1); + return (this->read_byte(this) & 0x80) ? 0 : 1; } /** @@ -512,15 +455,13 @@ static int nand_check_wp (struct mtd_info *mtd) * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */ -static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) +static int nand_block_checkbad (struct nand_chip *this, loff_t ofs, int getchip, int allowbbt) { - struct nand_chip *this = mtd->priv; - if (!this->bbt) - return this->block_bad(mtd, ofs, getchip); + return this->block_bad(this, ofs, getchip); /* Return info from the table */ - return nand_isbad_bbt (mtd, ofs, allowbbt); + return nand_isbad_bbt (this, ofs, allowbbt); } /** @@ -533,21 +474,19 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */ -static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void nand_command (struct nand_chip *this, unsigned command, int column, int page_addr) { - register struct nand_chip *this = mtd->priv; - /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); + this->hwcontrol(this, NAND_CTL_SETCLE); /* * Write out the command to the device. */ if (command == NAND_CMD_SEQIN) { int readcmd; - if (column >= mtd->oobblock) { + if (column >= this->oobblock) { /* OOB area */ - column -= mtd->oobblock; + column -= this->oobblock; readcmd = NAND_CMD_READOOB; } else if (column < 256) { /* First 256 bytes --> READ0 */ @@ -556,32 +495,32 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in column -= 256; readcmd = NAND_CMD_READ1; } - this->write_byte(mtd, readcmd); + this->write_byte(this, readcmd); } - this->write_byte(mtd, command); + this->write_byte(this, command); /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + this->hwcontrol(this, NAND_CTL_CLRCLE); if (column != -1 || page_addr != -1) { - this->hwcontrol(mtd, NAND_CTL_SETALE); + this->hwcontrol(this, NAND_CTL_SETALE); /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; - this->write_byte(mtd, column); + this->write_byte(this, column); } if (page_addr != -1) { - this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); - this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); + this->write_byte(this, (unsigned char) (page_addr & 0xff)); + this->write_byte(this, (unsigned char) ((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 32MiB */ if (this->chipsize > (32 << 20)) - this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); + this->write_byte(this, (unsigned char) ((page_addr >> 16) & 0x0f)); } /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); + this->hwcontrol(this, NAND_CTL_CLRALE); } /* @@ -601,10 +540,10 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in 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)); + this->hwcontrol(this, NAND_CTL_SETCLE); + this->write_byte(this, NAND_CMD_STATUS); + this->hwcontrol(this, NAND_CTL_CLRCLE); + while ( !(this->read_byte(this) & 0x40)); return; /* This applies to read commands */ @@ -623,7 +562,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in * any case on any machine. */ ndelay (100); /* wait until command is processed */ - while (!this->dev_ready(mtd)); + while (!this->dev_ready(this)); } /** @@ -638,44 +577,42 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in * 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) +static void nand_command_lp (struct nand_chip *this, 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; + column += this->oobblock; command = NAND_CMD_READ0; } /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); + this->hwcontrol(this, NAND_CTL_SETCLE); /* Write out the command to the device. */ - this->write_byte(mtd, command); + this->write_byte(this, command); /* End command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + this->hwcontrol(this, NAND_CTL_CLRCLE); if (column != -1 || page_addr != -1) { - this->hwcontrol(mtd, NAND_CTL_SETALE); + this->hwcontrol(this, NAND_CTL_SETALE); /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; - this->write_byte(mtd, column & 0xff); - this->write_byte(mtd, column >> 8); + this->write_byte(this, column & 0xff); + this->write_byte(this, 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)); + this->write_byte(this, (unsigned char) (page_addr & 0xff)); + this->write_byte(this, (unsigned char) ((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 128MiB */ if (this->chipsize > (128 << 20)) - this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff)); + this->write_byte(this, (unsigned char) ((page_addr >> 16) & 0xff)); } /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); + this->hwcontrol(this, NAND_CTL_CLRALE); } /* @@ -697,19 +634,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, 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)); + this->hwcontrol(this, NAND_CTL_SETCLE); + this->write_byte(this, NAND_CMD_STATUS); + this->hwcontrol(this, NAND_CTL_CLRCLE); + while ( !(this->read_byte(this) & 0x40)); return; case NAND_CMD_READ0: /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); + this->hwcontrol(this, NAND_CTL_SETCLE); /* Write out the start read command */ - this->write_byte(mtd, NAND_CMD_READSTART); + this->write_byte(this, NAND_CMD_READSTART); /* End command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + this->hwcontrol(this, NAND_CTL_CLRCLE); /* Fall through into ready check */ /* This applies to read commands */ @@ -728,111 +665,10 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, * any case on any machine. */ ndelay (100); /* wait until command is processed */ - while (!this->dev_ready(mtd)); + while (!this->dev_ready(this)); } -/** - * nand_get_device - [GENERIC] Get chip for selected access - * @this: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested - * - * Get the device and lock it for exclusive access - */ -/* XXX U-BOOT XXX */ -#if 0 -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) -{ - struct nand_chip *active = this; - - DECLARE_WAITQUEUE (wait, current); - - /* - * Grab the lock and see if the device is available - */ -retry: - /* Hardware controller shared among independend devices */ - if (this->controller) { - spin_lock (&this->controller->lock); - if (this->controller->active) - active = this->controller->active; - else - this->controller->active = this; - spin_unlock (&this->controller->lock); - } - - if (active == this) { - spin_lock (&this->chip_lock); - if (this->state == FL_READY) { - this->state = new_state; - spin_unlock (&this->chip_lock); - return; - } - } - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&active->wq, &wait); - spin_unlock (&active->chip_lock); - schedule (); - remove_wait_queue (&active->wq, &wait); - goto retry; -} -#else -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) {} -#endif - -/** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @this: NAND chip structure - * @state: state to select the max. timeout value - * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs - * -*/ -/* XXX U-BOOT XXX */ -#if 0 -static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) -{ - unsigned long timeo = jiffies; - int status; - - if (state == FL_ERASING) - timeo += (HZ * 400) / 1000; - else - timeo += (HZ * 20) / 1000; - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay (100); - - if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) - this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - - while (time_before(jiffies, timeo)) { - /* Check, if we were interrupted */ - if (this->state != state) - return 0; - - if (this->dev_ready) { - if (this->dev_ready(mtd)) - break; - } else { - if (this->read_byte(mtd) & NAND_STATUS_READY) - break; - } - yield (); - } - status = (int) this->read_byte(mtd); - return status; - - return 0; -} -#else -static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) +static int nand_wait(struct nand_chip *this, int state) { uint64_t timeo, start; @@ -842,9 +678,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) timeo = 20 * MSECOND; if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) - this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); + this->cmdfunc(this, NAND_CMD_STATUS_MULTI, -1, -1); else - this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + this->cmdfunc(this, NAND_CMD_STATUS, -1, -1); start = get_time_ns(); @@ -855,10 +691,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) } if (this->dev_ready) { - if (this->dev_ready(mtd)) + if (this->dev_ready(this)) break; } else { - if (this->read_byte(mtd) & NAND_STATUS_READY) + if (this->read_byte(this) & NAND_STATUS_READY) break; } } @@ -867,9 +703,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) while (get_timer(0) < 10); #endif /* PPCHAMELON_NAND_TIMER_HACK */ - return this->read_byte(mtd); + return this->read_byte(this); } -#endif + /** * nand_write_page - [GENERIC] write one page @@ -886,7 +722,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) * * Cached programming is not supported yet. */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, +static int nand_write_page (struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; @@ -900,40 +736,40 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa cached = 0; /* Send command to begin auto page programming */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); + this->cmdfunc (this, NAND_CMD_SEQIN, 0x00, page); /* Write out complete page of data, take care of eccmode */ switch (eccmode) { /* No ecc, write all */ case NAND_ECC_NONE: printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); - this->write_buf(mtd, this->data_poi, mtd->oobblock); + this->write_buf(this, this->data_poi, this->oobblock); break; /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { - this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); + this->calculate_ecc(this, &this->data_poi[datidx], ecc_code); for (i = 0; i < 3; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; datidx += this->eccsize; } - this->write_buf(mtd, this->data_poi, mtd->oobblock); + this->write_buf(this, this->data_poi, this->oobblock); break; default: eccbytes = this->eccbytes; for (; eccsteps; eccsteps--) { /* enable hardware ecc logic for write */ - this->enable_hwecc(mtd, NAND_ECC_WRITE); - this->write_buf(mtd, &this->data_poi[datidx], this->eccsize); - this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); + this->enable_hwecc(this, NAND_ECC_WRITE); + this->write_buf(this, &this->data_poi[datidx], this->eccsize); + this->calculate_ecc(this, &this->data_poi[datidx], ecc_code); for (i = 0; i < eccbytes; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; /* If the hardware ecc provides syndromes then * the ecc code must be written immidiately after * the data bytes (words) */ if (this->options & NAND_HWECC_SYNDROME) - this->write_buf(mtd, ecc_code, eccbytes); + this->write_buf(this, ecc_code, eccbytes); datidx += this->eccsize; } break; @@ -941,16 +777,16 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa /* Write out OOB data */ if (this->options & NAND_HWECC_SYNDROME) - this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); + this->write_buf(this, &oob_buf[oobsel->eccbytes], this->oobsize - oobsel->eccbytes); else - this->write_buf(mtd, oob_buf, mtd->oobsize); + this->write_buf(this, oob_buf, this->oobsize); /* Send command to actually program the data */ - this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1); + this->cmdfunc (this, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1); if (!cached) { /* call wait ready function */ - status = this->waitfunc (mtd, this, FL_WRITING); + status = this->waitfunc (this, FL_WRITING); /* See if device thinks it succeeded */ if (status & 0x01) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); @@ -959,7 +795,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa } else { /* FIXME: Implement cached programming ! */ /* wait until cache is ready*/ - /* status = this->waitfunc (mtd, this, FL_CACHEDRPG); */ + /* status = this->waitfunc (this, this, FL_CACHEDRPG); */ } return 0; } @@ -984,7 +820,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa * the error later when the ECC page check fails, but we would rather catch * it early in the page write stage. Better to write no data than invalid data. */ -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) { int i, j, datidx = 0, oobofs = 0, res = -EIO; @@ -995,20 +831,20 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; /* Send command to read back the first page */ - this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); + this->cmdfunc (this, NAND_CMD_READ0, 0, page); for(;;) { for (j = 0; j < eccsteps; j++) { /* Loop through and verify the data */ - if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) { + if (this->verify_buf(this, &this->data_poi[datidx], this->eccsize)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } - datidx += mtd->eccsize; + datidx += this->eccsize; /* Have we a hw generator layout ? */ if (!hweccbytes) continue; - if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) { + if (this->verify_buf(this, &this->oob_buf[oobofs], hweccbytes)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } @@ -1019,13 +855,13 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int * compare the ecc bytes */ if (oobmode) { - if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) { + if (this->verify_buf(this, &oob_buf[oobofs], this->oobsize - hweccbytes * eccsteps)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } } else { /* Read always, else autoincrement fails */ - this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps); + this->read_buf(this, oobdata, this->oobsize - hweccbytes * eccsteps); if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { int ecccnt = oobsel->eccbytes; @@ -1041,7 +877,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int } } } - oobofs += mtd->oobsize - hweccbytes * eccsteps; + oobofs += this->oobsize - hweccbytes * eccsteps; page++; numpages--; @@ -1055,7 +891,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + while (!this->dev_ready(this)); /* All done, return happy */ if (!numpages) @@ -1064,14 +900,14 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this)) - this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); + this->cmdfunc (this, NAND_CMD_READ0, 0x00, page); } /* * Terminate the read command. We come here in case of an error * So we must issue a reset command. */ out: - this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); + this->cmdfunc (this, NAND_CMD_RESET, -1, -1); return res; } #endif @@ -1086,9 +922,9 @@ out: * * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) +static int nand_read (struct nand_chip *this, loff_t from, size_t len, size_t * retlen, u_char * buf) { - return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); + return nand_read_ecc (this, from, len, retlen, buf, NULL, NULL); } @@ -1104,12 +940,11 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re * * NAND read with ECC */ -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, +static int nand_read_ecc (struct nand_chip *this, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) { int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; - struct nand_chip *this = mtd->priv; u_char *data_poi, *oob_data = oob_buf; u_char ecc_calc[32]; u_char ecc_code[32]; @@ -1125,18 +960,15 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) { + if ((from + len) > this->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd ,FL_READING); - /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) - oobsel = &mtd->oobinfo; + oobsel = &this->oobinfo; /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) @@ -1147,23 +979,23 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Select the NAND device */ chipnr = (int)(from >> this->chip_shift); - this->select_chip(mtd, chipnr); + this->select_chip(this, chipnr); /* First we calculate the starting page */ realpage = (int) (from >> this->page_shift); page = realpage & this->pagemask; /* Get raw starting column */ - col = from & (mtd->oobblock - 1); + col = from & (this->oobblock - 1); - end = mtd->oobblock; + end = this->oobblock; ecc = this->eccsize; eccbytes = this->eccbytes; if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) compareecc = 0; - oobreadlen = mtd->oobsize; + oobreadlen = this->oobsize; if (this->options & NAND_HWECC_SYNDROME) oobreadlen -= oobsel->eccbytes; @@ -1194,7 +1026,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Check, if we must send the read command */ if (sndcmd) { - this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); + this->cmdfunc (this, NAND_CMD_READ0, 0x00, page); sndcmd = 0; } @@ -1217,45 +1049,45 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, #else puts("Reading data from NAND FLASH without ECC is not recommended\n"); #endif - this->read_buf(mtd, data_poi, end); + this->read_buf(this, data_poi, end); break; } case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ - this->read_buf(mtd, data_poi, end); + this->read_buf(this, data_poi, end); for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) - this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); + this->calculate_ecc(this, &data_poi[datidx], &ecc_calc[i]); break; default: for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { - this->enable_hwecc(mtd, NAND_ECC_READ); - this->read_buf(mtd, &data_poi[datidx], ecc); + this->enable_hwecc(this, NAND_ECC_READ); + this->read_buf(this, &data_poi[datidx], ecc); /* HW ecc with syndrome calculation must read the * syndrome from flash immidiately after the data */ if (!compareecc) { /* Some hw ecc generators need to know when the * syndrome is read from flash */ - this->enable_hwecc(mtd, NAND_ECC_READSYN); - this->read_buf(mtd, &oob_data[i], eccbytes); + this->enable_hwecc(this, NAND_ECC_READSYN); + this->read_buf(this, &oob_data[i], eccbytes); /* We calc error correction directly, it checks the hw * generator for an error, reads back the syndrome and * does the error correction on the fly */ - if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { + if (this->correct_data(this, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; } } else { - this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); + this->calculate_ecc(this, &data_poi[datidx], &ecc_calc[i]); } } break; } /* read oobdata */ - this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen); + this->read_buf(this, &oob_data[this->oobsize - oobreadlen], oobreadlen); /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ if (!compareecc) @@ -1267,7 +1099,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* correct data, if neccecary */ for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { - ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); + ecc_status = this->correct_data(this, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); /* Get next chunk of ecc bytes */ j += eccbytes; @@ -1277,7 +1109,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * Should go away some day */ if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { - int *p = (int *)(&oob_data[mtd->oobsize]); + int *p = (int *)(&oob_data[this->oobsize]); p[i] = ecc_status; } @@ -1295,19 +1127,19 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, case MTD_NANDECC_AUTOPLACE: case MTD_NANDECC_AUTOPL_USR: /* Walk through the autoplace chunks */ - for (i = 0, j = 0; j < mtd->oobavail; i++) { + for (i = 0, j = 0; j < this->oobavail; i++) { int from = oobsel->oobfree[i][0]; int num = oobsel->oobfree[i][1]; memcpy(&oob_buf[oob], &oob_data[from], num); j+= num; } - oob += mtd->oobavail; + oob += this->oobavail; break; case MTD_NANDECC_PLACE: /* YAFFS1 legacy mode */ oob_data += this->eccsteps * sizeof (int); default: - oob_data += mtd->oobsize; + oob_data += this->oobsize; } } readdata: @@ -1317,7 +1149,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, buf[read++] = data_poi[j]; this->pagebuf = realpage; } else - read += mtd->oobblock; + read += this->oobblock; /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems @@ -1327,7 +1159,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + while (!this->dev_ready(this)); if (read == len) break; @@ -1341,8 +1173,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - this->select_chip(mtd, -1); - this->select_chip(mtd, chipnr); + this->select_chip(this, -1); + this->select_chip(this, chipnr); } /* Check, if the chip supports auto page increment * or if we have hit a block boundary. @@ -1352,7 +1184,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + nand_release_device(this); /* * Return success, if no ECC failures, else -EBADMSG @@ -1373,10 +1205,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * * NAND read out-of-band data from the spare area */ -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) +static int nand_read_oob (struct nand_chip *this, loff_t from, size_t len, size_t * retlen, u_char * buf) { int i, col, page, chipnr; - struct nand_chip *this = mtd->priv; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); @@ -1386,35 +1217,32 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t chipnr = (int)(from >> this->chip_shift); /* Mask to get column */ - col = from & (mtd->oobsize - 1); + col = from & (this->oobsize - 1); /* Initialize return length value */ *retlen = 0; /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) { + if ((from + len) > this->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd , FL_READING); - /* Select the NAND device */ - this->select_chip(mtd, chipnr); + this->select_chip(this, chipnr); /* Send the read command */ - this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); + this->cmdfunc (this, NAND_CMD_READOOB, col, page & this->pagemask); /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ i = 0; while (i < len) { - int thislen = mtd->oobsize - col; + int thislen = this->oobsize - col; thislen = min_t(int, thislen, len); - this->read_buf(mtd, &buf[i], thislen); + this->read_buf(this, &buf[i], thislen); i += thislen; /* Apply delay or wait for ready/busy pin @@ -1425,7 +1253,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + while (!this->dev_ready(this)); /* Read more ? */ if (i < len) { @@ -1435,8 +1263,8 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Check, if we cross a chip boundary */ if (!(page & this->pagemask)) { chipnr++; - this->select_chip(mtd, -1); - this->select_chip(mtd, chipnr); + this->select_chip(this, -1); + this->select_chip(this, chipnr); } /* Check, if the chip supports auto page increment @@ -1444,13 +1272,13 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { /* For subsequent page reads set offset to 0 */ - this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); + this->cmdfunc (this, NAND_CMD_READOOB, 0x0, page & this->pagemask); } } } /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + nand_release_device(this); /* Return happy */ *retlen = len; @@ -1467,36 +1295,32 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * * Read raw data including oob into buffer */ -int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen) +int nand_read_raw (struct nand_chip *this, uint8_t *buf, loff_t from, size_t len, size_t ooblen) { - struct nand_chip *this = mtd->priv; int page = (int) (from >> this->page_shift); int chip = (int) (from >> this->chip_shift); int sndcmd = 1; int cnt = 0; - int pagesize = mtd->oobblock + mtd->oobsize; + int pagesize = this->oobblock + this->oobsize; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) { + if ((from + len) > this->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n"); return -EINVAL; } - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd , FL_READING); - - this->select_chip (mtd, chip); + this->select_chip (this, chip); /* Add requested oob length */ len += ooblen; while (len) { if (sndcmd) - this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); + this->cmdfunc (this, NAND_CMD_READ0, 0, page & this->pagemask); sndcmd = 0; - this->read_buf (mtd, &buf[cnt], pagesize); + this->read_buf (this, &buf[cnt], pagesize); len -= pagesize; cnt += pagesize; @@ -1505,7 +1329,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + while (!this->dev_ready(this)); /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) @@ -1513,7 +1337,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, } /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + nand_release_device(this); return 0; } @@ -1541,10 +1365,9 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, * forces the 0xff fill before using the buffer again. * */ -static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel, +static u_char * nand_prepare_oobbuf (struct nand_chip *this, u_char *fsbuf, struct nand_oobinfo *oobsel, int autoplace, int numpages) { - struct nand_chip *this = mtd->priv; int i, len, ofs; /* Zero copy fs supplied buffer */ @@ -1554,7 +1377,7 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct /* Check, if the buffer must be filled with ff again */ if (this->oobdirty) { memset (this->oob_buf, 0xff, - mtd->oobsize << (this->phys_erase_shift - this->page_shift)); + this->oobsize << (this->phys_erase_shift - this->page_shift)); this->oobdirty = 0; } @@ -1566,19 +1389,19 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct this->oobdirty = 1; ofs = 0; while (numpages--) { - for (i = 0, len = 0; len < mtd->oobavail; i++) { + for (i = 0, len = 0; len < this->oobavail; i++) { int to = ofs + oobsel->oobfree[i][0]; int num = oobsel->oobfree[i][1]; memcpy (&this->oob_buf[to], fsbuf, num); len += num; fsbuf += num; } - ofs += mtd->oobavail; + ofs += this->oobavail; } return this->oob_buf; } -#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0 +#define NOTALIGNED(x) (x & (this->oobblock-1)) != 0 /** * nand_write - [MTD Interface] compability function for nand_write_ecc @@ -1591,9 +1414,9 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL * */ -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) +static int nand_write (struct nand_chip *this, loff_t to, size_t len, size_t * retlen, const u_char * buf) { - return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); + return (nand_write_ecc (this, to, len, retlen, buf, NULL, NULL)); } /** @@ -1608,12 +1431,11 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret * * NAND write with ECC */ -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, +static int nand_write_ecc (struct nand_chip *this, loff_t to, size_t len, size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) { int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; int autoplace = 0, numpages, totalpages; - struct nand_chip *this = mtd->priv; u_char *oobbuf, *bufstart; int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); @@ -1623,7 +1445,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, *retlen = 0; /* Do not allow write past end of device */ - if ((to + len) > mtd->size) { + if ((to + len) > this->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); return -EINVAL; } @@ -1634,21 +1456,18 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_WRITING); - /* Calculate chipnr */ chipnr = (int)(to >> this->chip_shift); /* Select the NAND device */ - this->select_chip(mtd, chipnr); + this->select_chip(this, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) + if (nand_check_wp(this)) goto out; /* if oobsel is NULL, use chip defaults */ if (oobsel == NULL) - oobsel = &mtd->oobinfo; + oobsel = &this->oobinfo; /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { @@ -1670,7 +1489,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, startpage = page; /* Calc number of pages we can write in one go */ numpages = min (ppblock - (startpage & (ppblock - 1)), totalpages); - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); + oobbuf = nand_prepare_oobbuf (this, eccbuf, oobsel, autoplace, numpages); bufstart = (u_char *)buf; /* Loop until all data is written */ @@ -1682,15 +1501,15 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, * real pageprogram command, else select cached programming * if supported by the chip. */ - ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); + ret = nand_write_page (this, page, &oobbuf[oob], oobsel, (--numpages > 0)); if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); goto out; } /* Next oob page */ - oob += mtd->oobsize; + oob += this->oobsize; /* Update written bytes count */ - written += mtd->oobblock; + written += this->oobblock; if (written == len) goto cmp; @@ -1704,7 +1523,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (!(page & (ppblock - 1))){ int ofs; this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, + ret = nand_verify_pages (this, startpage, page - startpage, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { @@ -1714,7 +1533,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, *retlen = written; bufstart = (u_char*) &buf[written]; - ofs = autoplace ? mtd->oobavail : mtd->oobsize; + ofs = autoplace ? this->oobavail : this->oobsize; if (eccbuf) eccbuf += (page - startpage) * ofs; totalpages -= page - startpage; @@ -1723,20 +1542,20 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, startpage = page; oob = 0; this->oobdirty = 1; - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, + oobbuf = nand_prepare_oobbuf (this, eccbuf, oobsel, autoplace, numpages); /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - this->select_chip(mtd, -1); - this->select_chip(mtd, chipnr); + this->select_chip(this, -1); + this->select_chip(this, chipnr); } } } /* Verify the remaining pages */ cmp: this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, totalpages, + ret = nand_verify_pages (this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (!ret) *retlen = written; @@ -1745,7 +1564,7 @@ cmp: out: /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + nand_release_device(this); return ret; } @@ -1761,10 +1580,9 @@ out: * * NAND write out-of-band */ -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) +static int nand_write_oob (struct nand_chip *this, loff_t to, size_t len, size_t * retlen, const u_char * buf) { int column, page, status, ret = -EIO, chipnr; - struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); @@ -1773,32 +1591,29 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * chipnr = (int) (to >> this->chip_shift); /* Mask to get column */ - column = to & (mtd->oobsize - 1); + column = to & (this->oobsize - 1); /* Initialize return length value */ *retlen = 0; /* Do not allow write past end of page */ - if ((column + len) > mtd->oobsize) { + if ((column + len) > this->oobsize) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); return -EINVAL; } - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_WRITING); - /* Select the NAND device */ - this->select_chip(mtd, chipnr); + this->select_chip(this, chipnr); /* Reset the chip. Some chips (like the Toshiba TC5832DC found in one of my DiskOnChip 2000 test units) will clear the whole data page too if we don't do this. I have no clue why, but I seem to have 'fixed' it in the doc2000 driver in August 1999. dwmw2. */ - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + this->cmdfunc(this, NAND_CMD_RESET, -1, -1); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) + if (nand_check_wp(this)) goto out; /* Invalidate the page cache, if we write to the cached page */ @@ -1807,23 +1622,23 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * if (NAND_MUST_PAD(this)) { /* Write out desired data */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask); + this->cmdfunc (this, NAND_CMD_SEQIN, this->oobblock, page & this->pagemask); /* prepad 0xff for partial programming */ - this->write_buf(mtd, ffchars, column); + this->write_buf(this, ffchars, column); /* write data */ - this->write_buf(mtd, buf, len); + this->write_buf(this, buf, len); /* postpad 0xff for partial programming */ - this->write_buf(mtd, ffchars, mtd->oobsize - (len+column)); + this->write_buf(this, ffchars, this->oobsize - (len+column)); } else { /* Write out desired data */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask); + this->cmdfunc (this, NAND_CMD_SEQIN, this->oobblock + column, page & this->pagemask); /* write data */ - this->write_buf(mtd, buf, len); + this->write_buf(this, buf, len); } /* Send command to program the OOB data */ - this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); + this->cmdfunc (this, NAND_CMD_PAGEPROG, -1, -1); - status = this->waitfunc (mtd, this, FL_WRITING); + status = this->waitfunc (this, FL_WRITING); /* See if device thinks it succeeded */ if (status & 0x01) { @@ -1836,9 +1651,9 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * #ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ - this->cmdfunc (mtd, NAND_CMD_READOOB, column, page & this->pagemask); + this->cmdfunc (this, NAND_CMD_READOOB, column, page & this->pagemask); - if (this->verify_buf(mtd, buf, len)) { + if (this->verify_buf(this, buf, len)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); ret = -EIO; goto out; @@ -1847,197 +1662,11 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret = 0; out: /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + nand_release_device(this); return ret; } -/* XXX U-BOOT XXX */ -#if 0 -/** - * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc - * @mtd: MTD device structure - * @vecs: the iovectors to write - * @count: number of vectors - * @to: offset to write to - * @retlen: pointer to variable to store the number of written bytes - * - * NAND write with kvec. This just calls the ecc function - */ -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, - loff_t to, size_t * retlen) -{ - return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); -} - -/** - * nand_writev_ecc - [MTD Interface] write with iovec with ecc - * @mtd: MTD device structure - * @vecs: the iovectors to write - * @count: number of vectors - * @to: offset to write to - * @retlen: pointer to variable to store the number of written bytes - * @eccbuf: filesystem supplied oob data buffer - * @oobsel: oob selection structure - * - * NAND write with iovec with ecc - */ -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, - loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) -{ - int i, page, len, total_len, ret = -EIO, written = 0, chipnr; - int oob, numpages, autoplace = 0, startpage; - struct nand_chip *this = mtd->priv; - int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); - u_char *oobbuf, *bufstart; - - /* Preset written len for early exit */ - *retlen = 0; - - /* Calculate total length of data */ - total_len = 0; - for (i = 0; i < count; i++) - total_len += (int) vecs[i].iov_len; - - DEBUG (MTD_DEBUG_LEVEL3, - "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); - - /* Do not allow write past end of page */ - if ((to + total_len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); - return -EINVAL; - } - - /* reject writes, which are not page aligned */ - if (NOTALIGNED (to) || NOTALIGNED(total_len)) { - printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); - return -EINVAL; - } - - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_WRITING); - - /* Get the current chip-nr */ - chipnr = (int) (to >> this->chip_shift); - /* Select the NAND device */ - this->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) - goto out; - - /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - - /* Autoplace of oob data ? Use the default placement scheme */ - if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { - oobsel = this->autooob; - autoplace = 1; - } - if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) - autoplace = 1; - - /* Setup start page */ - page = (int) (to >> this->page_shift); - /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) - this->pagebuf = -1; - - startpage = page & this->pagemask; - - /* Loop until all kvec' data has been written */ - len = 0; - while (count) { - /* If the given tuple is >= pagesize then - * write it out from the iov - */ - if ((vecs->iov_len - len) >= mtd->oobblock) { - /* Calc number of pages we can write - * out of this iov in one go */ - numpages = (vecs->iov_len - len) >> this->page_shift; - /* Do not cross block boundaries */ - numpages = min (ppblock - (startpage & (ppblock - 1)), numpages); - oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); - bufstart = (u_char *)vecs->iov_base; - bufstart += len; - this->data_poi = bufstart; - oob = 0; - for (i = 1; i <= numpages; i++) { - /* Write one page. If this is the last page to write - * then use the real pageprogram command, else select - * cached programming if supported by the chip. - */ - ret = nand_write_page (mtd, this, page & this->pagemask, - &oobbuf[oob], oobsel, i != numpages); - if (ret) - goto out; - this->data_poi += mtd->oobblock; - len += mtd->oobblock; - oob += mtd->oobsize; - page++; - } - /* Check, if we have to switch to the next tuple */ - if (len >= (int) vecs->iov_len) { - vecs++; - len = 0; - count--; - } - } else { - /* We must use the internal buffer, read data out of each - * tuple until we have a full page to write - */ - int cnt = 0; - while (cnt < mtd->oobblock) { - if (vecs->iov_base != NULL && vecs->iov_len) - this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; - /* Check, if we have to switch to the next tuple */ - if (len >= (int) vecs->iov_len) { - vecs++; - len = 0; - count--; - } - } - this->pagebuf = page; - this->data_poi = this->data_buf; - bufstart = this->data_poi; - numpages = 1; - oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); - ret = nand_write_page (mtd, this, page & this->pagemask, - oobbuf, oobsel, 0); - if (ret) - goto out; - page++; - } - - this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); - if (ret) - goto out; - - written += mtd->oobblock * numpages; - /* All done ? */ - if (!count) - break; - - startpage = page & this->pagemask; - /* Check, if we cross a chip boundary */ - if (!startpage) { - chipnr++; - this->select_chip(mtd, -1); - this->select_chip(mtd, chipnr); - } - } - ret = 0; -out: - /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); - - *retlen = written; - return ret; -} -#endif - /** * single_erease_cmd - [GENERIC] NAND standard block erase command function * @mtd: MTD device structure @@ -2045,12 +1674,11 @@ out: * * Standard erase command for NAND chips */ -static void single_erase_cmd (struct mtd_info *mtd, int page) +static void single_erase_cmd (struct nand_chip *this, int page) { - struct nand_chip *this = mtd->priv; /* Send commands to erase a block */ - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page); - this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1); + this->cmdfunc (this, NAND_CMD_ERASE1, -1, page); + this->cmdfunc (this, NAND_CMD_ERASE2, -1, -1); } /** @@ -2061,15 +1689,14 @@ static void single_erase_cmd (struct mtd_info *mtd, int page) * AND multi block erase command function * Erase 4 consecutive blocks */ -static void multi_erase_cmd (struct mtd_info *mtd, int page) +static void multi_erase_cmd (struct nand_chip *this, int page) { - struct nand_chip *this = mtd->priv; /* Send commands to erase a block */ - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page); - this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1); + this->cmdfunc (this, NAND_CMD_ERASE1, -1, page++); + this->cmdfunc (this, NAND_CMD_ERASE1, -1, page++); + this->cmdfunc (this, NAND_CMD_ERASE1, -1, page++); + this->cmdfunc (this, NAND_CMD_ERASE1, -1, page); + this->cmdfunc (this, NAND_CMD_ERASE2, -1, -1); } /** @@ -2079,9 +1706,9 @@ static void multi_erase_cmd (struct mtd_info *mtd, int page) * * Erase one ore more blocks */ -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) +static int nand_erase (struct nand_chip *this, struct erase_info *instr) { - return nand_erase_nand (mtd, instr, 0); + return nand_erase_nand (this, instr, 0); } /** @@ -2092,10 +1719,9 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) * * Erase one ore more blocks */ -int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt) +int nand_erase_nand (struct nand_chip *this, struct erase_info *instr, int allowbbt) { int page, len, status, pages_per_block, ret, chipnr; - struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); @@ -2113,16 +1739,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb } /* Do not allow erase past end of device */ - if ((instr->len + instr->addr) > mtd->size) { + if ((instr->len + instr->addr) > this->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n"); return -EINVAL; } instr->fail_addr = 0xffffffff; - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_ERASING); - /* Shift to get first page */ page = (int) (instr->addr >> this->page_shift); chipnr = (int) (instr->addr >> this->chip_shift); @@ -2131,11 +1754,11 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb pages_per_block = 1 << (this->phys_erase_shift - this->page_shift); /* Select the NAND device */ - this->select_chip(mtd, chipnr); + this->select_chip(this, chipnr); /* Check the WP bit */ /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { + if (nand_check_wp(this)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); instr->state = MTD_ERASE_FAILED; goto erase_exit; @@ -2149,7 +1772,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb while (len) { #ifndef NAND_ALLOW_ERASE_ALL /* Check if we have a bad block, we do not erase bad blocks ! */ - if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) { + if (nand_block_checkbad(this, ((loff_t) page) << this->page_shift, 0, allowbbt)) { printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; goto erase_exit; @@ -2160,9 +1783,9 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) this->pagebuf = -1; - this->erase_cmd (mtd, page & this->pagemask); + this->erase_cmd (this, page & this->pagemask); - status = this->waitfunc (mtd, this, FL_ERASING); + status = this->waitfunc (this, FL_ERASING); /* See if block erase succeeded */ if (status & 0x01) { @@ -2179,8 +1802,8 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb /* Check, if we cross a chip boundary */ if (len && !(page & this->pagemask)) { chipnr++; - this->select_chip(mtd, -1); - this->select_chip(mtd, chipnr); + this->select_chip(this, -1); + this->select_chip(this, chipnr); } } instr->state = MTD_ERASE_DONE; @@ -2193,7 +1816,7 @@ erase_exit: mtd_erase_callback(instr); /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + nand_release_device(this); /* Return more or less happy */ return ret; @@ -2201,20 +1824,16 @@ erase_exit: /** * nand_sync - [MTD Interface] sync - * @mtd: MTD device structure + * @this: MTD device structure * * Sync is actually a wait for chip ready function */ -static void nand_sync (struct mtd_info *mtd) +static void nand_sync (struct nand_chip *this) { - struct nand_chip *this = mtd->priv; - DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); - /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_SYNCING); /* Release it and go back */ - nand_release_device (mtd); + nand_release_device (this); } @@ -2223,13 +1842,13 @@ static void nand_sync (struct mtd_info *mtd) * @mtd: MTD device structure * @ofs: offset relative to mtd start */ -static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) +static int nand_block_isbad (struct nand_chip *this, loff_t ofs) { /* Check for invalid offset */ - if (ofs > mtd->size) + if (ofs > this->size) return -EINVAL; - return nand_block_checkbad (mtd, ofs, 1, 0); + return nand_block_checkbad (this, ofs, 1, 0); } /** @@ -2237,19 +1856,18 @@ static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) * @mtd: MTD device structure * @ofs: offset relative to mtd start */ -static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) +static int nand_block_markbad (struct nand_chip *this, loff_t ofs) { - struct nand_chip *this = mtd->priv; int ret; - if ((ret = nand_block_isbad(mtd, ofs))) { + if ((ret = nand_block_isbad(this, ofs))) { /* If it was bad already, return success and do nothing. */ if (ret > 0) return 0; return ret; } - return this->block_markbad(mtd, ofs); + return this->block_markbad(this, ofs); } /** @@ -2264,10 +1882,9 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) * they are not provided by the board driver * */ -int nand_scan (struct mtd_info *mtd, int maxchips) +int nand_scan (struct nand_chip *this, int maxchips) { int i, j, 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; @@ -2308,14 +1925,14 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->scan_bbt = nand_default_bbt; /* Select the device */ - this->select_chip(mtd, 0); + this->select_chip(this, 0); /* Send the command for reading device ID */ - this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); + this->cmdfunc (this, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ - nand_maf_id = this->read_byte(mtd); - nand_dev_id = this->read_byte(mtd); + nand_maf_id = this->read_byte(this); + nand_dev_id = this->read_byte(this); /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { @@ -2323,24 +1940,24 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (nand_dev_id != nand_flash_ids[i].id) continue; - if (!mtd->name) mtd->name = nand_flash_ids[i].name; + if (!this->name) this->name = nand_flash_ids[i].name; this->chipsize = 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); + extid = this->read_byte(this); /* The 4th id byte is the important one */ - extid = this->read_byte(mtd); + extid = this->read_byte(this); /* Calc pagesize */ - mtd->oobblock = 1024 << (extid & 0x3); + this->oobblock = 1024 << (extid & 0x3); extid >>= 2; /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock / 512); + this->oobsize = (8 << (extid & 0x01)) * (this->oobblock / 512); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ - mtd->erasesize = (64 * 1024) << (extid & 0x03); + this->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; @@ -2348,9 +1965,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } else { /* Old devices have this data hardcoded in the * device id table */ - mtd->erasesize = nand_flash_ids[i].erasesize; - mtd->oobblock = nand_flash_ids[i].pagesize; - mtd->oobsize = mtd->oobblock / 32; + this->erasesize = nand_flash_ids[i].erasesize; + this->oobblock = nand_flash_ids[i].pagesize; + this->oobsize = this->oobblock / 32; busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; } @@ -2359,22 +1976,22 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (busw != (this->options & NAND_BUSWIDTH_16)) { 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); + nand_manuf_ids[i].name , this->name); printk (KERN_WARNING "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); - this->select_chip(mtd, -1); + this->select_chip(this, -1); return 1; } /* Calculate the address shift from the page size */ - this->page_shift = ffs(mtd->oobblock) - 1; - this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; + this->page_shift = ffs(this->oobblock) - 1; + this->bbt_erase_shift = this->phys_erase_shift = ffs(this->erasesize) - 1; this->chip_shift = ffs(this->chipsize) - 1; /* Set the bad block position */ - this->badblockpos = mtd->oobblock > 512 ? + this->badblockpos = this->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ @@ -2395,7 +2012,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->erase_cmd = single_erase_cmd; /* Do not replace user supplied command function ! */ - if (mtd->oobblock > 512 && this->cmdfunc == nand_command) + if (this->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; /* Try to identify manufacturer */ @@ -2410,19 +2027,19 @@ int nand_scan (struct mtd_info *mtd, int maxchips) #ifndef CFG_NAND_QUIET_TEST printk (KERN_WARNING "No NAND device found!!!\n"); #endif - this->select_chip(mtd, -1); + this->select_chip(this, -1); return 1; } for (i=1; i < maxchips; i++) { - this->select_chip(mtd, i); + this->select_chip(this, i); /* Send the command for reading device ID */ - this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); + this->cmdfunc (this, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ - if (nand_maf_id != this->read_byte(mtd) || - nand_dev_id != this->read_byte(mtd)) + if (nand_maf_id != this->read_byte(this) || + nand_dev_id != this->read_byte(this)) break; } if (i > 1) @@ -2431,7 +2048,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Allocate buffers, if neccecary */ if (!this->oob_buf) { size_t len; - len = mtd->oobsize << (this->phys_erase_shift - this->page_shift); + len = this->oobsize << (this->phys_erase_shift - this->page_shift); this->oob_buf = kmalloc (len, GFP_KERNEL); if (!this->oob_buf) { printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n"); @@ -2442,7 +2059,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (!this->data_buf) { size_t len; - len = mtd->oobblock + mtd->oobsize; + len = this->oobblock + this->oobsize; this->data_buf = kmalloc (len, GFP_KERNEL); if (!this->data_buf) { if (this->options & NAND_OOBBUF_ALLOC) @@ -2453,20 +2070,20 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->options |= NAND_DATABUF_ALLOC; } - /* Store the number of chips and calc total size for mtd */ + /* Store the number of chips and calc total size for this */ this->numchips = i; - mtd->size = i * this->chipsize; + this->size = i * this->chipsize; /* Convert chipsize to number of pages per chip -1. */ this->pagemask = (this->chipsize >> this->page_shift) - 1; /* Preset the internal oob buffer */ - memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); + memset(this->oob_buf, 0xff, this->oobsize << (this->phys_erase_shift - this->page_shift)); /* If no default placement scheme is given, select an * appropriate one */ if (!this->autooob) { /* Select the appropriate default oob placement scheme for * placement agnostic filesystems */ - switch (mtd->oobsize) { + switch (this->oobsize) { case 8: this->autooob = &nand_oob_8; break; @@ -2478,7 +2095,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) break; default: printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", - mtd->oobsize); + this->oobsize); /* BUG(); */ } } @@ -2486,11 +2103,11 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* The number of bytes available for the filesystem to place fs dependend * oob data */ if (this->options & NAND_BUSWIDTH_16) { - mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2); + this->oobavail = this->oobsize - (this->autooob->eccbytes + 2); if (this->autooob->eccbytes & 0x01) - mtd->oobavail--; + this->oobavail--; } else - mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1); + this->oobavail = this->oobsize - (this->autooob->eccbytes + 1); /* * check ECC mode, default to software @@ -2502,9 +2119,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) switch (this->eccmode) { case NAND_ECC_HW12_2048: - if (mtd->oobblock < 2048) { + if (this->oobblock < 2048) { printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", - mtd->oobblock); + this->oobblock); this->eccmode = NAND_ECC_SOFT; this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; @@ -2515,7 +2132,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) case NAND_ECC_HW3_512: case NAND_ECC_HW6_512: case NAND_ECC_HW8_512: - if (mtd->oobblock == 256) { + if (this->oobblock == 256) { printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); this->eccmode = NAND_ECC_SOFT; this->calculate_ecc = nand_calculate_ecc; @@ -2560,21 +2177,21 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* BUG(); */ } - mtd->eccsize = this->eccsize; + this->eccsize = this->eccsize; /* Set the number of read / write steps for one page to ensure ECC generation */ switch (this->eccmode) { case NAND_ECC_HW12_2048: - this->eccsteps = mtd->oobblock / 2048; + this->eccsteps = this->oobblock / 2048; break; case NAND_ECC_HW3_512: case NAND_ECC_HW6_512: case NAND_ECC_HW8_512: - this->eccsteps = mtd->oobblock / 512; + this->eccsteps = this->oobblock / 512; break; case NAND_ECC_HW3_256: case NAND_ECC_SOFT: - this->eccsteps = mtd->oobblock / 256; + this->eccsteps = this->oobblock / 256; break; case NAND_ECC_NONE: @@ -2591,67 +2208,64 @@ int nand_scan (struct mtd_info *mtd, int maxchips) #endif /* De-select the device */ - this->select_chip(mtd, -1); + this->select_chip(this, -1); /* Invalidate the pagebuffer reference */ this->pagebuf = -1; /* Fill in remaining MTD driver data */ - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; - mtd->ecctype = MTD_ECC_SW; - mtd->erase = nand_erase; - mtd->point = NULL; - mtd->unpoint = NULL; - mtd->read = nand_read; - mtd->write = nand_write; - mtd->read_ecc = nand_read_ecc; - mtd->write_ecc = nand_write_ecc; - mtd->read_oob = nand_read_oob; - mtd->write_oob = nand_write_oob; + this->type = MTD_NANDFLASH; + this->flags = MTD_CAP_NANDFLASH | MTD_ECC; + this->ecctype = MTD_ECC_SW; + this->erase = nand_erase; + this->read = nand_read; + this->write = nand_write; + this->read_ecc = nand_read_ecc; + this->write_ecc = nand_write_ecc; + this->read_oob = nand_read_oob; + this->write_oob = nand_write_oob; /* XXX U-BOOT XXX */ #if 0 - mtd->readv = NULL; - mtd->writev = nand_writev; - mtd->writev_ecc = nand_writev_ecc; + this->readv = NULL; + this->writev = nand_writev; + this->writev_ecc = nand_writev_ecc; #endif - mtd->sync = nand_sync; + this->sync = nand_sync; /* XXX U-BOOT XXX */ #if 0 - mtd->lock = NULL; - mtd->unlock = NULL; - mtd->suspend = NULL; - mtd->resume = NULL; + this->lock = NULL; + this->unlock = NULL; + this->suspend = NULL; + this->resume = NULL; #endif - mtd->block_isbad = nand_block_isbad; - mtd->block_markbad = nand_block_markbad; + this->block_isbad = nand_block_isbad; + this->block_markbad = nand_block_markbad; /* and make the autooob the default one */ - memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); + memcpy(&this->oobinfo, this->autooob, sizeof(this->oobinfo)); /* XXX U-BOOT XXX */ #if 0 - mtd->owner = THIS_MODULE; + this->owner = THIS_MODULE; #endif /* Build bad block table */ - return this->scan_bbt (mtd); + return this->scan_bbt (this); } /** * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd: MTD device structure */ -void nand_release (struct mtd_info *mtd) +void nand_release (struct nand_chip *this) { - struct nand_chip *this = mtd->priv; #ifdef CONFIG_MTD_PARTITIONS /* Deregister partitions */ - del_mtd_partitions (mtd); + del_mtd_partitions (this); #endif /* Deregister the device */ /* XXX U-BOOT XXX */ #if 0 - del_mtd_device (mtd); + del_mtd_device (this); #endif /* Free bad block table memory, if allocated */ if (this->bbt) diff --git a/drivers/nand/nand_bbt.c b/drivers/nand/nand_bbt.c index 8ba6d59bb..c36ecf1da 100644 --- a/drivers/nand/nand_bbt.c +++ b/drivers/nand/nand_bbt.c @@ -117,11 +117,10 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des * Read the bad block table starting from page. * */ -static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, +static int read_bbt (struct nand_chip *this, uint8_t *buf, int page, int num, int bits, int offs, int reserved_block_code) { int res, i, j, act = 0; - struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; uint8_t msk = (uint8_t) ((1 << bits) - 1); @@ -131,7 +130,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, while (totlen) { len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); - res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); + res = this->read_ecc (this, from, len, &retlen, buf, NULL, this->autooob); if (res < 0) { if (retlen != len) { printk (KERN_INFO "nand_bbt: Error reading bad block table\n"); @@ -182,9 +181,8 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, * Read the bad block table for all chips starting at a given page * We assume that the bbt bits are in consecutive order. */ -static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +static int read_abs_bbt (struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, int chip) { - struct nand_chip *this = mtd->priv; int res = 0, i; int bits; @@ -193,13 +191,13 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des int offs = 0; for (i = 0; i < this->numchips; i++) { if (chip == -1 || chip == i) - res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); + res = read_bbt (this, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); if (res) return res; offs += this->chipsize >> (this->bbt_erase_shift + 2); } } else { - res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); + res = read_bbt (this, buf, td->pages[0], this->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); if (res) return res; } @@ -217,22 +215,21 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des * We assume that the bbt bits are in consecutive order. * */ -static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, +static int read_abs_bbts (struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { - struct nand_chip *this = mtd->priv; /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); - td->version[0] = buf[mtd->oobblock + td->veroffs]; + nand_read_raw (this, buf, td->pages[0] << this->page_shift, this->oobblock, this->oobsize); + td->version[0] = buf[this->oobblock + td->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); - md->version[0] = buf[mtd->oobblock + md->veroffs]; + nand_read_raw (this, buf, md->pages[0] << this->page_shift, this->oobblock, this->oobsize); + md->version[0] = buf[this->oobblock + md->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } @@ -250,9 +247,8 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de * Create a bad block table by scanning the device * for the given good/bad block identify pattern */ -static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) +static void create_bbt (struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { - struct nand_chip *this = mtd->priv; int i, j, numblocks, len, scanlen; int startblock; loff_t from; @@ -266,14 +262,14 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc else len = 1; } - scanlen = mtd->oobblock + mtd->oobsize; - readlen = len * mtd->oobblock; - ooblen = len * mtd->oobsize; + scanlen = this->oobblock + this->oobsize; + readlen = len * this->oobblock; + ooblen = len * this->oobsize; if (chip == -1) { /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it * makes shifting and masking less painful */ - numblocks = mtd->size >> (this->bbt_erase_shift - 1); + numblocks = this->size >> (this->bbt_erase_shift - 1); startblock = 0; from = 0; } else { @@ -289,9 +285,9 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } for (i = startblock; i < numblocks;) { - nand_read_raw (mtd, buf, from, readlen, ooblen); + nand_read_raw (this, buf, from, readlen, ooblen); for (j = 0; j < len; j++) { - if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + if (check_pattern (&buf[j * scanlen], scanlen, this->oobblock, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); break; } @@ -318,17 +314,16 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc * The bbt ident pattern resides in the oob area of the first page * in a block. */ -static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +static int search_bbt (struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td) { - struct nand_chip *this = mtd->priv; int i, chips; int bits, startblock, block, dir; - int scanlen = mtd->oobblock + mtd->oobsize; + int scanlen = this->oobblock + this->oobsize; int bbtblocks; /* Search direction top -> down ? */ if (td->options & NAND_BBT_LASTBLOCK) { - startblock = (mtd->size >> this->bbt_erase_shift) -1; + startblock = (this->size >> this->bbt_erase_shift) -1; dir = -1; } else { startblock = 0; @@ -342,7 +337,7 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr startblock &= bbtblocks - 1; } else { chips = 1; - bbtblocks = mtd->size >> this->bbt_erase_shift; + bbtblocks = this->size >> this->bbt_erase_shift; } /* Number of bits for each erase block in the bbt */ @@ -356,11 +351,11 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (block = 0; block < td->maxblocks; block++) { int actblock = startblock + dir * block; /* Read first page */ - nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); - if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { + nand_read_raw (this, buf, actblock << this->bbt_erase_shift, this->oobblock, this->oobsize); + if (!check_pattern(buf, scanlen, this->oobblock, td)) { td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); if (td->options & NAND_BBT_VERSION) { - td->version[i] = buf[mtd->oobblock + td->veroffs]; + td->version[i] = buf[this->oobblock + td->veroffs]; } break; } @@ -386,15 +381,15 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr * * Search and read the bad block table(s) */ -static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, +static int search_read_bbts (struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ - search_bbt (mtd, buf, td); + search_bbt (this, buf, td); /* Search the mirror table */ if (md) - search_bbt (mtd, buf, md); + search_bbt (this, buf, md); /* Force result check */ return 1; @@ -413,10 +408,9 @@ static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, * (Re)write the bad block table * */ -static int write_bbt (struct mtd_info *mtd, uint8_t *buf, +static int write_bbt (struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { - struct nand_chip *this = mtd->priv; struct nand_oobinfo oobinfo; struct erase_info einfo; int i, j, res, chip = 0; @@ -440,7 +434,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, chip = chipsel; } } else { - numblocks = (int) (mtd->size >> this->bbt_erase_shift); + numblocks = (int) (this->size >> this->bbt_erase_shift); nrchips = 1; } @@ -505,7 +499,7 @@ write: /* Make it block aligned */ to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; - res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); + res = this->read_ecc (this, to, len, &retlen, buf, &buf[len], &oobinfo); if (res < 0) { if (retlen != len) { printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n"); @@ -519,18 +513,18 @@ write: /* Preset the bbt area with 0xff */ memset (&buf[offs], 0xff, (size_t)(numblocks >> sft)); /* Preset the bbt's oob area with 0xff */ - memset (&buf[len + pageoffs * mtd->oobsize], 0xff, - ((len >> this->page_shift) - pageoffs) * mtd->oobsize); + memset (&buf[len + pageoffs * this->oobsize], 0xff, + ((len >> this->page_shift) - pageoffs) * this->oobsize); if (td->options & NAND_BBT_VERSION) { - buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip]; + buf[len + (pageoffs * this->oobsize) + td->veroffs] = td->version[chip]; } } else { /* Calc length */ len = (size_t) (numblocks >> sft); /* Make it page aligned ! */ - len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1); + len = (len + (this->oobblock-1)) & ~(this->oobblock-1); /* Preset the buffer with 0xff */ - memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize); + memset (buf, 0xff, len + (len >> this->page_shift) * this->oobsize); offs = 0; /* Pattern is located in oob area of first page */ memcpy (&buf[len + td->offs], td->pattern, td->len); @@ -552,16 +546,16 @@ write: } memset (&einfo, 0, sizeof (einfo)); - einfo.mtd = mtd; + einfo.nand = this; einfo.addr = (unsigned long) to; einfo.len = 1 << this->bbt_erase_shift; - res = nand_erase_nand (mtd, &einfo, 1); + res = nand_erase_nand (this, &einfo, 1); if (res < 0) { printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); return res; } - res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); + res = this->write_ecc (this, to, len, &retlen, buf, &buf[len], &oobinfo); if (res < 0) { printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); return res; @@ -583,13 +577,11 @@ write: * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks */ -static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +static int nand_memory_bbt (struct nand_chip *this, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd->priv; - /* Ensure that we only scan for the pattern and nothing else */ bd->options = 0; - create_bbt (mtd, this->data_buf, bd, -1); + create_bbt (this, this->data_buf, bd, -1); return 0; } @@ -605,10 +597,9 @@ static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) * Update is neccecary if one of the tables is missing or the * version nr. of one table is less than the other */ -static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) +static int check_create (struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *bd) { int i, chips, writeops, chipsel, res; - struct nand_chip *this = mtd->priv; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; @@ -679,7 +670,7 @@ create: continue; /* Create the table in memory by scanning the chip(s) */ - create_bbt (mtd, buf, bd, chipsel); + create_bbt (this, buf, bd, chipsel); td->version[i] = 1; if (md) @@ -687,21 +678,21 @@ create: writecheck: /* read back first ? */ if (rd) - read_abs_bbt (mtd, buf, rd, chipsel); + read_abs_bbt (this, buf, rd, chipsel); /* If they weren't versioned, read both. */ if (rd2) - read_abs_bbt (mtd, buf, rd2, chipsel); + read_abs_bbt (this, buf, rd2, chipsel); /* Write the bad block table to the device ? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, td, md, chipsel); + res = write_bbt (this, buf, td, md, chipsel); if (res < 0) return res; } /* Write the mirror bad block table to the device ? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, md, td, chipsel); + res = write_bbt (this, buf, md, td, chipsel); if (res < 0) return res; } @@ -718,9 +709,8 @@ writecheck: * accidental erasures / writes. The regions are identified by * the mark 0x02. */ -static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) +static void mark_bbt_region (struct nand_chip *this, struct nand_bbt_descr *td) { - struct nand_chip *this = mtd->priv; int i, j, chips, block, nrblocks, update; uint8_t oldval, newval; @@ -730,7 +720,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); } else { chips = 1; - nrblocks = (int)(mtd->size >> this->bbt_erase_shift); + nrblocks = (int)(this->size >> this->bbt_erase_shift); } for (i = 0; i < chips; i++) { @@ -743,7 +733,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; if ((oldval != newval) && td->reserved_block_code) - nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); + nand_update_bbt(this, block << (this->bbt_erase_shift - 1)); continue; } update = 0; @@ -763,7 +753,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) new ones have been marked, then we need to update the stored bbts. This should only happen once. */ if (update && td->reserved_block_code) - nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1)); + nand_update_bbt(this, (block - 2) << (this->bbt_erase_shift - 1)); } } @@ -781,15 +771,14 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) * by calling the nand_free_bbt function. * */ -int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +int nand_scan_bbt (struct nand_chip *this, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd->priv; int len, res = 0; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; - len = mtd->size >> (this->bbt_erase_shift + 2); + len = this->size >> (this->bbt_erase_shift + 2); /* Allocate memory (2bit per block) */ this->bbt = kmalloc (len, GFP_KERNEL); if (!this->bbt) { @@ -803,11 +792,11 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) * to build a memory based bad block table */ if (!td) - return nand_memory_bbt(mtd, bd); + return nand_memory_bbt(this, bd); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; + len += (len >> this->page_shift) * this->oobsize; buf = kmalloc (len, GFP_KERNEL); if (!buf) { printk (KERN_ERR "nand_bbt: Out of memory\n"); @@ -818,19 +807,19 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) /* Is the bbt at a given page ? */ if (td->options & NAND_BBT_ABSPAGE) { - res = read_abs_bbts (mtd, buf, td, md); + res = read_abs_bbts (this, buf, td, md); } else { /* Search the bad block table using a pattern in oob */ - res = search_read_bbts (mtd, buf, td, md); + res = search_read_bbts (this, buf, td, md); } if (res) - res = check_create (mtd, buf, bd); + res = check_create (this, buf, bd); /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region (mtd, td); + mark_bbt_region (this, td); if (md) - mark_bbt_region (mtd, md); + mark_bbt_region (this, md); kfree (buf); return res; @@ -844,9 +833,8 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) * * The function updates the bad block table(s) */ -int nand_update_bbt (struct mtd_info *mtd, loff_t offs) +int nand_update_bbt (struct nand_chip *this, loff_t offs) { - struct nand_chip *this = mtd->priv; int len, res = 0, writeops = 0; int chip, chipsel; uint8_t *buf; @@ -856,10 +844,10 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) if (!this->bbt || !td) return -EINVAL; - len = mtd->size >> (this->bbt_erase_shift + 2); + len = this->size >> (this->bbt_erase_shift + 2); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; + len += (len >> this->page_shift) * this->oobsize; buf = kmalloc (len, GFP_KERNEL); if (!buf) { printk (KERN_ERR "nand_update_bbt: Out of memory\n"); @@ -883,13 +871,13 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) /* Write the bad block table to the device ? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, td, md, chipsel); + res = write_bbt (this, buf, td, md, chipsel); if (res < 0) goto out; } /* Write the mirror bad block table to the device ? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, md, td, chipsel); + res = write_bbt (this, buf, md, td, chipsel); } out: @@ -974,10 +962,8 @@ static struct nand_bbt_descr bbt_mirror_descr = { * support for the device and calls the nand_scan_bbt function * */ -int nand_default_bbt (struct mtd_info *mtd) +int nand_default_bbt (struct nand_chip *this) { - struct nand_chip *this = mtd->priv; - /* Default for AG-AND. We must use a flash based * bad block table as the devices have factory marked * _good_ blocks. Erasing those blocks leads to loss @@ -992,7 +978,7 @@ int nand_default_bbt (struct mtd_info *mtd) this->bbt_md = &bbt_mirror_descr; } this->options |= NAND_USE_FLASH_BBT; - return nand_scan_bbt (mtd, &agand_flashbased); + return nand_scan_bbt (this, &agand_flashbased); } @@ -1004,18 +990,18 @@ int nand_default_bbt (struct mtd_info *mtd) this->bbt_md = &bbt_mirror_descr; } if (!this->badblock_pattern) { - this->badblock_pattern = (mtd->oobblock > 512) ? + this->badblock_pattern = (this->oobblock > 512) ? &largepage_flashbased : &smallpage_flashbased; } } else { this->bbt_td = NULL; this->bbt_md = NULL; if (!this->badblock_pattern) { - this->badblock_pattern = (mtd->oobblock > 512) ? + this->badblock_pattern = (this->oobblock > 512) ? &largepage_memorybased : &smallpage_memorybased; } } - return nand_scan_bbt (mtd, this->badblock_pattern); + return nand_scan_bbt (this, this->badblock_pattern); } /** @@ -1025,9 +1011,8 @@ int nand_default_bbt (struct mtd_info *mtd) * @allowbbt: allow access to bad block table region * */ -int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) +int nand_isbad_bbt (struct nand_chip *this, loff_t offs, int allowbbt) { - struct nand_chip *this = mtd->priv; int block; uint8_t res; diff --git a/drivers/nand/nand_ecc.c b/drivers/nand/nand_ecc.c index 9fca7b13d..4c9d3e4ac 100644 --- a/drivers/nand/nand_ecc.c +++ b/drivers/nand/nand_ecc.c @@ -112,7 +112,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, * @dat: raw data * @ecc_code: buffer for ECC */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +int nand_calculate_ecc(struct nand_chip *nand, const u_char *dat, u_char *ecc_code) { u_char idx, reg1, reg2, reg3; int j; @@ -154,7 +154,7 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code * * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) +int nand_correct_data(struct nand_chip *nand, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { u_char a, b, c, d1, d2, d3, add, bit, i; diff --git a/drivers/nand/nand_ids.c b/drivers/nand/nand_ids.c index 8ebd04c16..e041b1904 100644 --- a/drivers/nand/nand_ids.c +++ b/drivers/nand/nand_ids.c @@ -2,110 +2,129 @@ * drivers/mtd/nandids.c * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $ + * + * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ - #include #include - /* * Chip ID list * * Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, * options * -* Pagesize; 0, 256, 512 -* 0 get this information from the extended chip ID +* Pagesize; 0, 256, 512 +* 0 get this information from the extended chip ID + 256 256 Byte page size * 512 512 Byte page size */ struct nand_flash_dev nand_flash_ids[] = { - {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, - {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0}, - {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0}, - {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0}, - {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0}, - {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0}, - {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0}, - {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, - {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, - {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, - {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, - {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, - {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, - {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, +#ifdef CONFIG_MTD_NAND_MUSEUM_IDS + {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, + {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0}, + {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0}, + {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0}, + {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0}, + {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0}, + {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0}, + {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, + {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, + {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, - {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, - {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, - {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, + {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, + {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, + {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, +#endif - {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, - {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, - {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, + {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, + {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, - {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, - {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, + {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, + {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, - {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, - {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, + {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, + {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, + {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, + {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, + {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, + {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0}, + {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, + + /* + * These are the new chips with large page size. The pagesize and the + * erasesize is determined from the extended id bytes + */ +#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR) +#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) + + /*512 Megabit */ + {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, - /* These are the new chips with large page size. The pagesize - * and the erasesize is determined from the extended id bytes - */ /* 1 Gigabit */ - {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS}, + {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS}, + {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16}, + {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16}, /* 2 Gigabit */ - {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS}, + {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS}, + {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16}, + {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16}, /* 4 Gigabit */ - {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS}, + {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS}, + {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16}, + {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16}, /* 8 Gigabit */ - {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS}, + {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS}, + {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16}, + {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16}, /* 16 Gigabit */ - {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, - {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS}, + {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS}, + {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16}, + {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, - /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! - * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes - * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 - * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go - * There are more speed improvements for reads and writes possible, but not implemented now + /* + * Renesas AND 1 Gigabit. Those chips do not support extended id and + * have a strange page/block layout ! The chosen minimum erasesize is + * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page + * planes 1 block = 2 pages, but due to plane arrangement the blocks + * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would + * increase the eraseblock size so we chose a combined one which can be + * erased in one go There are more speed improvements for reads and + * writes possible, but not implemented now */ - {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY}, + {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, + NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | + BBT_AUTO_REFRESH + }, {NULL,} }; @@ -120,6 +139,8 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, + {NAND_MFR_HYNIX, "Hynix"}, + {NAND_MFR_MICRON, "Micron"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index c8c30ee91..ff7cfdbe1 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -23,7 +23,7 @@ fail_addr = 0xffffffff, the failure was not at the device level or was not specific to any particular block. */ struct erase_info { - struct mtd_info *mtd; + struct nand_chip *nand; u_int32_t addr; u_int32_t len; u_int32_t fail_addr; @@ -43,92 +43,6 @@ struct mtd_erase_region_info { u_int32_t numblocks; /* Number of blocks of erasesize in this region */ }; -struct mtd_info { - u_char type; - u_int32_t flags; - u_int32_t size; /* Total size of the MTD */ - - /* "Major" erase size for the device. Naïve users may take this - * to be the only erase size available, or may use the more detailed - * information below if they desire - */ - u_int32_t erasesize; - - u_int32_t oobblock; /* Size of OOB blocks (e.g. 512) */ - u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */ - u_int32_t oobavail; /* Number of bytes in OOB area available for fs */ - u_int32_t ecctype; - u_int32_t eccsize; - - - /* Kernel-only stuff starts here. */ - char *name; - int index; - - /* oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) */ - struct nand_oobinfo oobinfo; - - /* Data for variable erase regions. If numeraseregions is zero, - * it means that the whole device has erasesize as given above. - */ - int numeraseregions; - struct mtd_erase_region_info *eraseregions; - - /* This really shouldn't be here. It can go away in 2.5 */ - u_int32_t bank_size; - - int (*erase) (struct mtd_info *mtd, struct erase_info *instr); - - /* This stuff for eXecute-In-Place */ - int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); - - /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ - void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len); - - - int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - - int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); - int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); - - int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - - /* - * Methods to access the protection register area, present in some - * flash devices. The user data is one time programmable but the - * factory data is read only. - */ - int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - - int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - - /* This function is not yet implemented */ - int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - /* Sync */ - void (*sync) (struct mtd_info *mtd); - /* Bad block management functions */ - int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); - int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); - - void *priv; - - struct module *owner; - int usecount; -}; - - - /* Kernel-side ioctl definitions */ - -extern int add_mtd_device(struct mtd_info *mtd); -extern int del_mtd_device (struct mtd_info *mtd); - -extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); - -extern void put_mtd_device(struct mtd_info *mtd); - - #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) #define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index d5b248e8e..6e984a72f 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -54,15 +54,16 @@ #include #include +#include -struct mtd_info; +struct nand_chip; /* Scan and identify a NAND device */ -extern int nand_scan (struct mtd_info *mtd, int max_chips); +extern int nand_scan (struct nand_chip *, int max_chips); /* Free resources held by the NAND device */ -extern void nand_release (struct mtd_info *mtd); +extern void nand_release (struct nand_chip *); /* Read raw data from the device without ECC */ -extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen); +extern int nand_read_raw (struct nand_chip *, uint8_t *buf, loff_t from, size_t len, size_t ooblen); /* This constant declares the max. oobsize / page, which @@ -165,6 +166,16 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ #define NAND_4PAGE_ARRAY 0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others. */ +#define BBT_AUTO_REFRESH 0x00000080 +/* Chip does not require ready check on read. True + * for all large page devices, as they do not support + * autoincrement.*/ +#define NAND_NO_READRDY 0x00000100 +/* Chip does not allow subpage writes */ +#define NAND_NO_SUBPAGE_WRITE 0x00000200 /* Options valid for Samsung large page devices */ #define NAND_SAMSUNG_LP_OPTIONS \ @@ -275,26 +286,26 @@ struct nand_chip { void __iomem *IO_ADDR_R; void __iomem *IO_ADDR_W; - u_char (*read_byte)(struct mtd_info *mtd); - void (*write_byte)(struct mtd_info *mtd, u_char byte); - u16 (*read_word)(struct mtd_info *mtd); - void (*write_word)(struct mtd_info *mtd, u16 word); + u_char (*read_byte)(struct nand_chip *); + void (*write_byte)(struct nand_chip *, u_char byte); + u16 (*read_word)(struct nand_chip *); + void (*write_word)(struct nand_chip *, u16 word); - void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); - void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); - int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); - void (*select_chip)(struct mtd_info *mtd, int chip); - int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); - int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); - void (*hwcontrol)(struct mtd_info *mtd, int cmd); - int (*dev_ready)(struct mtd_info *mtd); - void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); - int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); - int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); - int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); - void (*enable_hwecc)(struct mtd_info *mtd, int mode); - void (*erase_cmd)(struct mtd_info *mtd, int page); - int (*scan_bbt)(struct mtd_info *mtd); + void (*write_buf)(struct nand_chip *, const u_char *buf, int len); + void (*read_buf)(struct nand_chip *, u_char *buf, int len); + int (*verify_buf)(struct nand_chip *, const u_char *buf, int len); + void (*select_chip)(struct nand_chip *, int chip); + int (*block_bad)(struct nand_chip *, loff_t ofs, int getchip); + int (*block_markbad)(struct nand_chip *, loff_t ofs); + void (*hwcontrol)(struct nand_chip *, int cmd); + int (*dev_ready)(struct nand_chip *); + void (*cmdfunc)(struct nand_chip *, unsigned command, int column, int page_addr); + int (*waitfunc)(struct nand_chip *, int state); + int (*calculate_ecc)(struct nand_chip *, const u_char *dat, u_char *ecc_code); + int (*correct_data)(struct nand_chip *, u_char *dat, u_char *read_ecc, u_char *calc_ecc); + void (*enable_hwecc)(struct nand_chip *, int mode); + void (*erase_cmd)(struct nand_chip *, int page); + int (*scan_bbt)(struct nand_chip *); int eccmode; int eccsize; int eccbytes; @@ -321,6 +332,55 @@ struct nand_chip { struct nand_bbt_descr *badblock_pattern; struct nand_hw_control *controller; void *priv; + + + /* Members formerly from mtd_info */ + u_int32_t oobblock; /* Size of OOB blocks (e.g. 512) */ + u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */ + u_int32_t oobavail; /* Number of bytes in OOB area available for fs */ + u_int32_t ecctype; + + /* "Major" erase size for the device. Naïve users may take this + * to be the only erase size available, or may use the more detailed + * information below if they desire + */ + u_int32_t erasesize; + + /* Kernel-only stuff starts here. */ + char *name; + u_int32_t size; /* Total size of the MTD */ + + int (*read_ecc) (struct nand_chip *, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); + int (*write_ecc) (struct nand_chip *, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); + + int (*read_oob) (struct nand_chip *, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*write_oob) (struct nand_chip *, loff_t to, size_t len, size_t *retlen, const u_char *buf); + + /* Sync */ + void (*sync) (struct nand_chip *); + /* Bad block management functions */ + int (*block_isbad) (struct nand_chip *, loff_t ofs); + + int (*read) (struct nand_chip *, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*write) (struct nand_chip *, loff_t to, size_t len, size_t *retlen, const u_char *buf); + + /* oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) */ + struct nand_oobinfo oobinfo; + + u_char type; + u_int32_t flags; + int (*erase) (struct nand_chip *, struct erase_info *instr); + + /* Minimal writable flash unit size. In case of NOR flash it is 1 (even + * though individual bits can be cleared), in case of NAND flash it is + * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR + * it is of ECC block size, etc. It is illegal to have writesize = 0. + * Any driver registering a struct mtd_info must ensure a writesize of + * 1 or larger. + */ + u_int32_t writesize; + + struct device_d dev; }; /* @@ -332,6 +392,8 @@ struct nand_chip { #define NAND_MFR_NATIONAL 0x8f #define NAND_MFR_RENESAS 0x07 #define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_MICRON 0x2c /** * struct nand_flash_dev - NAND Flash Device ID Structure @@ -437,11 +499,11 @@ struct nand_bbt_descr { /* The maximum number of blocks to scan for a bbt */ #define NAND_BBT_SCAN_MAXBLOCKS 4 -extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd); -extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs); -extern int nand_default_bbt (struct mtd_info *mtd); -extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); -extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); +extern int nand_scan_bbt (struct nand_chip *, struct nand_bbt_descr *bd); +extern int nand_update_bbt (struct nand_chip *, loff_t offs); +extern int nand_default_bbt (struct nand_chip *); +extern int nand_isbad_bbt (struct nand_chip *, loff_t offs, int allowbbt); +extern int nand_erase_nand (struct nand_chip *, struct erase_info *instr, int allowbbt); /* * Constants for oob configuration diff --git a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h index 12c5bc342..5069b425d 100644 --- a/include/linux/mtd/nand_ecc.h +++ b/include/linux/mtd/nand_ecc.h @@ -20,11 +20,11 @@ struct mtd_info; /* * Calculate 3 byte ECC code for 256 byte block */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); +int nand_calculate_ecc(struct nand_chip *, const u_char *dat, u_char *ecc_code); /* * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); +int nand_correct_data(struct nand_chip *, u_char *dat, u_char *read_ecc, u_char *calc_ecc); #endif /* __MTD_NAND_ECC_H__ */ diff --git a/include/nand.h b/include/nand.h deleted file mode 100644 index 23493f7e9..000000000 --- a/include/nand.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) Copyright 2005 - * 2N Telekomunikace, a.s. - * Ladislav Michl - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef _NAND_H_ -#define _NAND_H_ - -#include -#include -#include - -typedef struct mtd_info nand_info_t; - -extern int nand_curr_device; -extern nand_info_t nand_info[]; - -static inline int nand_read(nand_info_t *info, ulong ofs, ulong *len, u_char *buf) -{ - return info->read(info, ofs, *len, (size_t *)len, buf); -} - -static inline int nand_write(nand_info_t *info, ulong ofs, ulong *len, u_char *buf) -{ - return info->write(info, ofs, *len, (size_t *)len, buf); -} - -static inline int nand_block_isbad(nand_info_t *info, ulong ofs) -{ - return info->block_isbad(info, ofs); -} - -static inline int nand_erase(nand_info_t *info, ulong off, ulong size) -{ - struct erase_info instr; - - instr.mtd = info; - instr.addr = off; - instr.len = size; - instr.callback = 0; - - return info->erase(info, &instr); -} - - -/***************************************************************************** - * declarations from nand_util.c - ****************************************************************************/ - -struct nand_write_options { - u_char *buffer; /* memory block containing image to write */ - ulong length; /* number of bytes to write */ - ulong offset; /* start address in NAND */ - int quiet; /* don't display progress messages */ - int autoplace; /* if true use auto oob layout */ - int forcejffs2; /* force jffs2 oob layout */ - int forceyaffs; /* force yaffs oob layout */ - int noecc; /* write without ecc */ - int writeoob; /* image contains oob data */ - int pad; /* pad to page size */ - int blockalign; /* 1|2|4 set multiple of eraseblocks - * to align to */ -}; - -typedef struct nand_write_options nand_write_options_t; - -struct nand_read_options { - u_char *buffer; /* memory block in which read image is written*/ - ulong length; /* number of bytes to read */ - ulong offset; /* start address in NAND */ - int quiet; /* don't display progress messages */ - int readoob; /* put oob data in image */ -}; - -typedef struct nand_read_options nand_read_options_t; - -struct nand_erase_options { - ulong length; /* number of bytes to erase */ - ulong offset; /* first address in NAND to erase */ - int quiet; /* don't display progress messages */ - int jffs2; /* if true: format for jffs2 usage - * (write appropriate cleanmarker blocks) */ - int scrub; /* if true, really clean NAND by erasing - * bad blocks (UNSAFE) */ -}; - -typedef struct nand_erase_options nand_erase_options_t; - -int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts); - -int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts); -int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); - -#define NAND_LOCK_STATUS_TIGHT 0x01 -#define NAND_LOCK_STATUS_LOCK 0x02 -#define NAND_LOCK_STATUS_UNLOCK 0x04 - -int nand_lock( nand_info_t *meminfo, int tight ); -int nand_unlock( nand_info_t *meminfo, ulong start, ulong length ); -int nand_get_lock_status(nand_info_t *meminfo, ulong offset); - -#ifdef CFG_NAND_SELECT_DEVICE -void board_nand_select_device(struct nand_chip *nand, int chip); -#endif - -#endif