nand.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:34k
- /*
- * drivers/mtd/nand.c
- *
- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
- *
- * $Id: nand.c,v 1.12 2001/10/02 15:05:14 dwmw2 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.
- *
- * Overview:
- * This is the generic MTD driver for NAND flash devices. It should be
- * capable of working with almost all NAND chips currently available.
- */
- #include <linux/delay.h>
- #include <linux/errno.h>
- #include <linux/sched.h>
- #include <linux/types.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/nand_ids.h>
- #include <linux/interrupt.h>
- #include <asm/io.h>
- #ifdef CONFIG_MTD_NAND_ECC
- #include <linux/mtd/nand_ecc.h>
- #endif
- /*
- * Macros for low-level register control
- */
- #define NAND_CTRL (*(volatile unsigned char *)
- ((struct nand_chip *) mtd->priv)->CTRL_ADDR)
- #define nand_select() NAND_CTRL &= ~this->NCE;
- nand_command(mtd, NAND_CMD_RESET, -1, -1);
- udelay (10);
- #define nand_deselect() NAND_CTRL |= ~this->NCE;
- /*
- * NAND low-level MTD interface functions
- */
- 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,
- size_t *retlen, u_char *buf, u_char *ecc_code);
- 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,
- size_t *retlen, const u_char *buf,
- u_char *ecc_code);
- 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_writev (struct mtd_info *mtd, const struct iovec *vecs,
- unsigned long count, loff_t to, size_t *retlen);
- static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
- static void nand_sync (struct mtd_info *mtd);
- /*
- * Send command to NAND device
- */
- static void nand_command (struct mtd_info *mtd, unsigned command,
- int column, int page_addr)
- {
- register struct nand_chip *this = mtd->priv;
- register unsigned long NAND_IO_ADDR = this->IO_ADDR;
- /* Begin command latch cycle */
- NAND_CTRL |= this->CLE;
- /*
- * Write out the command to the device.
- */
- if (command != NAND_CMD_SEQIN)
- writeb (command, NAND_IO_ADDR);
- else {
- if (mtd->oobblock == 256 && column >= 256) {
- column -= 256;
- writeb(NAND_CMD_RESET, NAND_IO_ADDR);
- writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
- writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
- }
- else if (mtd->oobblock == 512 && column >= 256) {
- if (column < 512) {
- column -= 256;
- writeb(NAND_CMD_READ1, NAND_IO_ADDR);
- writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
- }
- else {
- column -= 512;
- writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
- writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
- }
- }
- else {
- writeb(NAND_CMD_READ0, NAND_IO_ADDR);
- writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
- }
- }
- /* Set ALE and clear CLE to start address cycle */
- NAND_CTRL &= ~this->CLE;
- NAND_CTRL |= this->ALE;
- /* Serially input address */
- if (column != -1)
- writeb (column, NAND_IO_ADDR);
- if (page_addr != -1) {
- writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
- writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
- /* One more address cycle for higher density devices */
- if (mtd->size & 0x0c000000) {
- writeb ((unsigned char) ((page_addr >> 16) & 0x0f),
- NAND_IO_ADDR);
- }
- }
- /* Latch in address */
- NAND_CTRL &= ~this->ALE;
- /* Pause for 15us */
- udelay (15);
- }
- /*
- * NAND read
- */
- static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
- #ifdef CONFIG_MTD_NAND_ECC
- struct nand_chip *this = mtd->priv;
-
- return nand_read_ecc (mtd, from, len, retlen, buf, this->ecc_code_buf);
- #else
- return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
- #endif
- }
- /*
- * NAND read with ECC
- */
- static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *ecc_code)
- {
- int j, col, page, state;
- int erase_state = 0;
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE(wait, current);
- #ifdef CONFIG_MTD_NAND_ECC
- int ecc_result;
- u_char ecc_calc[6];
- #endif
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_read_ecc: from = 0x%08x, len = %in", (unsigned int) from,
- (int) len);
- /* Do not allow reads past end of device */
- if ((from + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_read_ecc: Attempt read beyond end of devicen");
- *retlen = 0;
- return -EINVAL;
- }
- /* Grab the lock and see if the device is available */
- retry:
- spin_lock_bh (&this->chip_lock);
- switch (this->state) {
- case FL_READY:
- this->state = FL_READING;
- spin_unlock_bh (&this->chip_lock);
- break;
- case FL_ERASING:
- this->state = FL_READING;
- erase_state = 1;
- spin_unlock_bh (&this->chip_lock);
- break;
- default:
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- };
- /* First we calculate the starting page */
- page = from >> this->page_shift;
- /* Get raw starting column */
- col = from & (mtd->oobblock - 1);
- /* State machine for devices having pages larger than 256 bytes */
- state = (col < mtd->eccsize) ? 0 : 1;
- /* Calculate column address within ECC block context */
- col = (col >= mtd->eccsize) ? (col - mtd->eccsize) : col;
- /* Initialize return value */
- *retlen = 0;
- /* Select the NAND device */
- nand_select ();
- /* Loop until all data read */
- while (*retlen < len) {
- #ifdef CONFIG_MTD_NAND_ECC
- /* Send the read command */
- if (!state)
- nand_command (mtd, NAND_CMD_READ0, 0x00, page);
- else
- nand_command (mtd, NAND_CMD_READ1, 0x00, page);
- /* Read in a block big enough for ECC */
- for (j=0 ; j < mtd->eccsize ; j++)
- this->data_buf[j] = readb (this->IO_ADDR);
- /* Read in the out-of-band data */
- if (!state) {
- nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
- for (j=0 ; j<3 ; j++)
- ecc_code[j] = readb(this->IO_ADDR);
- nand_command (mtd, NAND_CMD_READ0, 0x00, page);
- }
- else {
- nand_command (mtd, NAND_CMD_READOOB, 0x03, page);
- for (j=3 ; j<6 ; j++)
- ecc_code[j] = readb(this->IO_ADDR);
- nand_command (mtd, NAND_CMD_READ0, 0x00, page);
- }
- /* Calculate the ECC and verify it */
- if (!state) {
- nand_calculate_ecc (&this->data_buf[0],
- &ecc_calc[0]);
- ecc_result = nand_correct_data (&this->data_buf[0],
- &ecc_code[0], &ecc_calc[0]);
- }
- else {
- nand_calculate_ecc (&this->data_buf[0],
- &ecc_calc[3]);
- ecc_result = nand_correct_data (&this->data_buf[0],
- &ecc_code[3], &ecc_calc[3]);
- }
- if (ecc_result == -1) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_read_ecc: "
- "Failed ECC read, page 0x%08xn", page);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- if (erase_state)
- this->state = FL_ERASING;
- else
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- /* Read the data from ECC data buffer into return buffer */
- if ((*retlen + (mtd->eccsize - col)) >= len) {
- while (*retlen < len)
- buf[(*retlen)++] = this->data_buf[col++];
- /* We're done */
- continue;
- }
- else
- for (j=col ; j < mtd->eccsize ; j++)
- buf[(*retlen)++] = this->data_buf[j];
- #else
- /* Send the read command */
- if (!state)
- nand_command (mtd, NAND_CMD_READ0, col, page);
- else
- nand_command (mtd, NAND_CMD_READ1, col, page);
- /* Read the data directly into the return buffer */
- if ((*retlen + (mtd->eccsize - col)) >= len) {
- while (*retlen < len)
- buf[(*retlen)++] = readb (this->IO_ADDR);
- /* We're done */
- continue;
- }
- else
- for (j=col ; j < mtd->eccsize ; j++)
- buf[(*retlen)++] = readb (this->IO_ADDR);
- #endif
- /*
- * If the amount of data to be read is greater than
- * (256 - col), then all subsequent reads will take
- * place on page or half-page (in the case of 512 byte
- * page devices) aligned boundaries and the column
- * address will be zero. Setting the column address to
- * to zero after the first read allows us to simplify
- * the reading of data and the if/else statements above.
- */
- if (col)
- col = 0x00;
- /* Increment page address */
- if ((mtd->oobblock == 256) || state)
- page++;
- /* Toggle state machine */
- if (mtd->oobblock == 512)
- state = state ? 0 : 1;
- }
- /* De-select the NAND device */
- nand_deselect ();
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- if (erase_state)
- this->state = FL_ERASING;
- else
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
-
- /* Return happy */
- return 0;
- }
- /*
- * NAND read out-of-band
- */
- static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
- int i, col, page;
- int erase_state = 0;
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE(wait, current);
-
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_read_oob: from = 0x%08x, len = %in", (unsigned int) from,
- (int) len);
- /* Shift to get page */
- page = ((int) from) >> this->page_shift;
- /* Mask to get column */
- col = from & 0x0f;
- /* Initialize return length value */
- *retlen = 0;
- /* Do not allow read past end of page */
- if ((col + len) > mtd->oobsize) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_read_oob: Attempt read past end of page "
- "0x%08x, column %i, length %in", page, col, len);
- return -EINVAL;
- }
- retry:
- /* Grab the lock and see if the device is available */
- spin_lock_bh (&this->chip_lock);
- switch (this->state) {
- case FL_READY:
- this->state = FL_READING;
- spin_unlock_bh (&this->chip_lock);
- break;
- case FL_ERASING:
- this->state = FL_READING;
- erase_state = 1;
- spin_unlock_bh (&this->chip_lock);
- break;
- default:
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- };
- /* Select the NAND device */
- nand_select ();
- /* Send the read command */
- nand_command (mtd, NAND_CMD_READOOB, col, page);
- /* Read the data */
- for (i = 0 ; i < len ; i++)
- buf[i] = readb (this->IO_ADDR);
- /* De-select the NAND device */
- nand_deselect ();
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- if (erase_state)
- this->state = FL_ERASING;
- else
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- /* Return happy */
- *retlen = len;
- return 0;
- }
- /*
- * NAND write
- */
- static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
- {
- #ifdef CONFIG_MTD_NAND_ECC
- struct nand_chip *this = mtd->priv;
-
- return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);
- #else
- return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
- #endif
- }
- /*
- * NAND write with ECC
- */
- static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf,
- u_char *ecc_code)
- {
- int i, page, col, cnt, status;
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE(wait, current);
- #ifdef CONFIG_MTD_NAND_ECC
- int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
- #endif
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_write_ecc: to = 0x%08x, len = %in", (unsigned int) to,
- (int) len);
- /* Do not allow write past end of page */
- if ((to + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_ecc: Attempted write past end of devicen");
- return -EINVAL;
- }
- retry:
- /* Grab the lock and see if the device is available */
- spin_lock_bh (&this->chip_lock);
- switch (this->state) {
- case FL_READY:
- this->state = FL_WRITING;
- spin_unlock_bh (&this->chip_lock);
- break;
- default:
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- };
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
- /* Get the starting column */
- col = to & (mtd->oobblock - 1);
- /* Initialize return length value */
- *retlen = 0;
- /* Select the NAND device */
- nand_select ();
- /* Check the WP bit */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_ecc: Device is write protected!!!n");
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- /* Loop until all data is written */
- while (*retlen < len) {
- /* Write data into buffer */
- if ((col + len) >= mtd->oobblock)
- for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++)
- this->data_buf[i] = buf[(*retlen + cnt)];
- else
- for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++)
- this->data_buf[i] = buf[(*retlen + cnt)];
-
- #ifdef CONFIG_MTD_NAND_ECC
- /* Zero out the ECC array */
- for (i=0 ; i < 6 ; i++)
- ecc_code[i] = 0x00;
- /* Calculate and write the ECC if we have enough data */
- if ((col < mtd->eccsize) &&
- ((col + (len - *retlen)) >= mtd->eccsize)) {
- nand_command (mtd, NAND_CMD_READ0, col, page);
- for (i=0 ; i < col ; i++)
- this->data_buf[i] = readb (this->IO_ADDR);
- nand_calculate_ecc (&this->data_buf[0], &ecc_code[0]);
- for (i=0 ; i<3 ; i++)
- this->data_buf[(mtd->oobblock + i)] =
- ecc_code[i];
- }
- /* Calculate and write the second ECC if we have enough data */
- if ((mtd->oobblock == 512) &&
- ((col + (len - *retlen)) >= mtd->oobblock)) {
- nand_calculate_ecc (&this->data_buf[256], &ecc_code[3]);
- for (i=3 ; i<6 ; i++)
- this->data_buf[(mtd->oobblock + i)] =
- ecc_code[i];
- }
- /* Write ones for partial page programming */
- for (i=ecc_bytes ; i < mtd->oobsize ; i++)
- this->data_buf[(mtd->oobblock + i)] = 0xff;
- #else
- /* Write ones for partial page programming */
- for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
- this->data_buf[i] = 0xff;
- #endif
- /* Write pre-padding bytes into buffer */
- for (i=0 ; i < col ; i++)
- this->data_buf[i] = 0xff;
- /* Write post-padding bytes into buffer */
- if ((col + (len - *retlen)) < mtd->oobblock) {
- for(i=(col + cnt) ; i < mtd->oobblock ; i++)
- this->data_buf[i] = 0xff;
- }
- /* Send command to begin auto page programming */
- nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
- /* Write out complete page of data */
- for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
- writeb (this->data_buf[i], this->IO_ADDR);
- /* Send command to actually program the data */
- nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
- /*
- * Wait for program operation to complete. This could
- * take up to 3000us (3ms) on some devices, so we try
- * and exit as quickly as possible.
- */
- status = 0;
- for (i=0 ; i<24 ; i++) {
- /* Delay for 125us */
- udelay (125);
- /* Check the status */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- status = (int) readb (this->IO_ADDR);
- if (status & 0x40)
- break;
- }
- /* See if device thinks it succeeded */
- if (status & 0x01) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_ecc: "
- "Failed write, page 0x%08x, "
- "%6i bytes were succesfuln", page, *retlen);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /*
- * The NAND device assumes that it is always writing to
- * a cleanly erased page. Hence, it performs its internal
- * write verification only on bits that transitioned from
- * 1 to 0. The device does NOT verify the whole page on a
- * byte by byte basis. It is possible that the page was
- * not completely erased or the page is becoming unusable
- * due to wear. The read with ECC would catch 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.
- */
-
- /* Send command to read back the page */
- if (col < mtd->eccsize)
- nand_command (mtd, NAND_CMD_READ0, col, page);
- else
- nand_command (mtd, NAND_CMD_READ1, col - 256, page);
- /* Loop through and verify the data */
- for (i=col ; i < cnt ; i++) {
- if (this->data_buf[i] != readb (this->IO_ADDR)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_ecc: "
- "Failed write verify, page 0x%08x, "
- "%6i bytes were succesfuln",
- page, *retlen);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- }
- #ifdef CONFIG_MTD_NAND_ECC
- /*
- * We also want to check that the ECC bytes wrote
- * correctly for the same reasons stated above.
- */
- nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
- for (i=0 ; i < ecc_bytes ; i++) {
- if ((readb (this->IO_ADDR) != ecc_code[i]) &&
- ecc_code[i]) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_ecc: Failed ECC write "
- "verify, page 0x%08x, "
- "%6i bytes were succesfuln",
- page, i);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- }
- #endif
- #endif
- /*
- * If we are writing a large amount of data and/or it
- * crosses page or half-page boundaries, we set the
- * the column to zero. It simplifies the program logic.
- */
- if (col)
- col = 0x00;
- /* Update written bytes count */
- *retlen += cnt;
- /* Increment page address */
- page++;
- }
- /* De-select the NAND device */
- nand_deselect ();
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- /* Return happy */
- *retlen = len;
- return 0;
- }
- /*
- * 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)
- {
- int i, column, page, status;
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE(wait, current);
-
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_write_oob: to = 0x%08x, len = %in", (unsigned int) to,
- (int) len);
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
- /* Mask to get column */
- column = to & 0x1f;
- /* Initialize return length value */
- *retlen = 0;
- /* Do not allow write past end of page */
- if ((column + len) > mtd->oobsize) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_oob: Attempt to write past end of pagen");
- return -EINVAL;
- }
- retry:
- /* Grab the lock and see if the device is available */
- spin_lock_bh (&this->chip_lock);
- switch (this->state) {
- case FL_READY:
- this->state = FL_WRITING;
- spin_unlock_bh (&this->chip_lock);
- break;
- default:
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- };
- /* Select the NAND device */
- nand_select ();
- /* Check the WP bit */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_oob: Device is write protected!!!n");
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- /* Write out desired data */
- nand_command (mtd, NAND_CMD_SEQIN, column + 512, page);
- for (i=0 ; i<len ; i++)
- writeb (buf[i], this->IO_ADDR);
- /* Send command to program the OOB data */
- nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
- /*
- * Wait for program operation to complete. This could
- * take up to 3000us (3ms) on some devices, so we try
- * and exit as quickly as possible.
- */
- status = 0;
- for (i=0 ; i<24 ; i++) {
- /* Delay for 125us */
- udelay (125);
- /* Check the status */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- status = (int) readb (this->IO_ADDR);
- if (status & 0x40)
- break;
- }
- /* See if device thinks it succeeded */
- if (status & 0x01) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_oob: "
- "Failed write, page 0x%08xn", page);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /* Send command to read back the data */
- nand_command (mtd, NAND_CMD_READOOB, column, page);
- /* Loop through and verify the data */
- for (i=0 ; i<len ; i++) {
- if (buf[i] != readb (this->IO_ADDR)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_write_oob: "
- "Failed write verify, page 0x%08xn", page);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- }
- #endif
- /* De-select the NAND device */
- nand_deselect ();
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- /* Return happy */
- *retlen = len;
- return 0;
- }
- /*
- * NAND write with iovec
- */
- static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
- unsigned long count, loff_t to, size_t *retlen)
- {
- int i, page, col, cnt, len, total_len, status;
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE(wait, current);
- #ifdef CONFIG_MTD_NAND_ECC
- int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
- #endif
- /* 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 = %in", (unsigned int) to,
- (unsigned int) total_len);
- /* 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 devicen");
- return -EINVAL;
- }
- retry:
- /* Grab the lock and see if the device is available */
- spin_lock_bh (&this->chip_lock);
- switch (this->state) {
- case FL_READY:
- this->state = FL_WRITING;
- spin_unlock_bh (&this->chip_lock);
- break;
- default:
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- };
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
- /* Get the starting column */
- col = to & (mtd->oobblock - 1);
- /* Initialize return length value */
- *retlen = 0;
- /* Select the NAND device */
- nand_select ();
- /* Check the WP bit */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_writev: Device is write protected!!!n");
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- /* Loop until all iovecs' data has been written */
- cnt = col;
- len = 0;
- while (count) {
- /* Do any need pre-fill for partial page programming */
- for (i=0 ; i < cnt ; i++)
- this->data_buf[i] = 0xff;
- /*
- * Read data out of each tuple until we have a full page
- * to write or we've read all the tuples.
- */
- while ((cnt < mtd->oobblock) && count) {
- this->data_buf[cnt++] =
- ((u_char *) vecs->iov_base)[len++];
- if (len >= (int) vecs->iov_len) {
- vecs++;
- len = 0;
- count--;
- }
- }
-
- /* Do any need post-fill for partial page programming */
- for (i=cnt ; i < mtd->oobblock ; i++)
- this->data_buf[i] = 0xff;
- #ifdef CONFIG_MTD_NAND_ECC
- /* Zero out the ECC array */
- for (i=0 ; i < 6 ; i++)
- this->ecc_code_buf[i] = 0x00;
- /* Calculate and write the first ECC */
- if (col >= mtd->eccsize) {
- nand_command (mtd, NAND_CMD_READ0, col, page);
- for (i=0 ; i < col ; i++)
- this->data_buf[i] = readb (this->IO_ADDR);
- nand_calculate_ecc (&this->data_buf[0],
- &(this->ecc_code_buf[0]));
- for (i=0 ; i<3 ; i++)
- this->data_buf[(mtd->oobblock + i)] =
- this->ecc_code_buf[i];
- }
- /* Calculate and write the second ECC */
- if ((mtd->oobblock == 512) && (cnt == mtd->oobblock)) {
- nand_calculate_ecc (&this->data_buf[256],
- &(this->ecc_code_buf[3]));
- for (i=3 ; i<6 ; i++)
- this->data_buf[(mtd->oobblock + i)] =
- this->ecc_code_buf[i];
- }
- /* Write ones for partial page programming */
- for (i=ecc_bytes ; i < mtd->oobsize ; i++)
- this->data_buf[(mtd->oobblock + i)] = 0xff;
- #else
- /* Write ones for partial page programming */
- for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
- this->data_buf[i] = 0xff;
- #endif
- /* Send command to begin auto page programming */
- nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
- /* Write out complete page of data */
- for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
- writeb (this->data_buf[i], this->IO_ADDR);
- /* Send command to actually program the data */
- nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
- /*
- * Wait for program operation to complete. This could
- * take up to 3000us (3ms) on some devices, so we try
- * and exit as quickly as possible.
- */
- status = 0;
- for (i=0 ; i<24 ; i++) {
- /* Delay for 125us */
- udelay (125);
- /* Check the status */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- status = (int) readb (this->IO_ADDR);
- if (status & 0x40)
- break;
- }
- /* See if device thinks it succeeded */
- if (status & 0x01) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_writev: "
- "Failed write, page 0x%08x, "
- "%6i bytes were succesfuln", page, *retlen);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /*
- * The NAND device assumes that it is always writing to
- * a cleanly erased page. Hence, it performs its internal
- * write verification only on bits that transitioned from
- * 1 to 0. The device does NOT verify the whole page on a
- * byte by byte basis. It is possible that the page was
- * not completely erased or the page is becoming unusable
- * due to wear. The read with ECC would catch 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.
- */
-
- /* Send command to read back the page */
- if (col < mtd->eccsize)
- nand_command (mtd, NAND_CMD_READ0, col, page);
- else
- nand_command (mtd, NAND_CMD_READ1, col - 256, page);
- /* Loop through and verify the data */
- for (i=col ; i < cnt ; i++) {
- if (this->data_buf[i] != readb (this->IO_ADDR)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_writev: "
- "Failed write verify, page 0x%08x, "
- "%6i bytes were succesfuln",
- page, *retlen);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- }
- #ifdef CONFIG_MTD_NAND_ECC
- /*
- * We also want to check that the ECC bytes wrote
- * correctly for the same reasons stated above.
- */
- nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
- for (i=0 ; i < ecc_bytes ; i++) {
- if ((readb (this->IO_ADDR) != this->ecc_code_buf[i]) &&
- this->ecc_code_buf[i]) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_writev: Failed ECC write "
- "verify, page 0x%08x, "
- "%6i bytes were succesfuln",
- page, i);
- nand_deselect ();
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- }
- #endif
- #endif
- /* Update written bytes count */
- *retlen += (cnt - col);
- /* Reset written byte counter and column */
- col = cnt = 0;
- /* Increment page address */
- page++;
- }
- /* De-select the NAND device */
- nand_deselect ();
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
- /* Return happy */
- return 0;
- }
- /*
- * NAND erase a block
- */
- static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
- {
- int i, page, len, status, pages_per_block;
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE(wait, current);
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_erase: start = 0x%08x, len = %in",
- (unsigned int) instr->addr, (unsigned int) instr->len);
- /* Start address must align on block boundary */
- if (instr->addr & (mtd->erasesize - 1)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_erase: Unaligned addressn");
- return -EINVAL;
- }
- /* Length must align on block boundary */
- if (instr->len & (mtd->erasesize - 1)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_erase: Length not block alignedn");
- return -EINVAL;
- }
- /* Do not allow erase past end of device */
- if ((instr->len + instr->addr) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_erase: Erase past end of devicen");
- return -EINVAL;
- }
- retry:
- /* Grab the lock and see if the device is available */
- spin_lock_bh (&this->chip_lock);
- switch (this->state) {
- case FL_READY:
- this->state = FL_ERASING;
- break;
- default:
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- };
- /* Shift to get first page */
- page = (int) (instr->addr >> this->page_shift);
- /* Calculate pages in each block */
- pages_per_block = mtd->erasesize / mtd->oobblock;
- /* Select the NAND device */
- nand_select ();
- /* Check the WP bit */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_erase: Device is write protected!!!n");
- nand_deselect ();
- this->state = FL_READY;
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- /* Loop through the pages */
- len = instr->len;
- while (len) {
- /* Send commands to erase a page */
- nand_command(mtd, NAND_CMD_ERASE1, -1, page);
- nand_command(mtd, NAND_CMD_ERASE2, -1, -1);
- /*
- * Wait for program operation to complete. This could
- * take up to 4000us (4ms) on some devices, so we try
- * and exit as quickly as possible.
- */
- status = 0;
- for (i=0 ; i<32 ; i++) {
- /* Delay for 125us */
- udelay (125);
- /* Check the status */
- nand_command (mtd, NAND_CMD_STATUS, -1, -1);
- status = (int) readb (this->IO_ADDR);
- if (status & 0x40)
- break;
- }
- /* See if block erase succeeded */
- if (status & 0x01) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "nand_erase: "
- "Failed erase, page 0x%08xn", page);
- nand_deselect ();
- this->state = FL_READY;
- spin_unlock_bh (&this->chip_lock);
- return -EIO;
- }
- /* Increment page address and decrement length */
- len -= mtd->erasesize;
- page += pages_per_block;
- /* Release the spin lock */
- spin_unlock_bh (&this->chip_lock);
- erase_retry:
- /* Check the state and sleep if it changed */
- spin_lock_bh (&this->chip_lock);
- if (this->state == FL_ERASING) {
- continue;
- }
- else {
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule();
- remove_wait_queue (&this->wq, &wait);
- goto erase_retry;
- }
- }
- spin_unlock_bh (&this->chip_lock);
- /* De-select the NAND device */
- nand_deselect ();
- /* Do call back function */
- if (instr->callback)
- instr->callback (instr);
- /* The device is ready */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- spin_unlock_bh (&this->chip_lock);
- /* Return happy */
- return 0;
- }
- /*
- * NAND sync
- */
- static void nand_sync (struct mtd_info *mtd)
- {
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE(wait, current);
- DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: calledn");
- retry:
- /* Grab the spinlock */
- spin_lock_bh(&this->chip_lock);
- /* See what's going on */
- switch(this->state) {
- case FL_READY:
- case FL_SYNCING:
- this->state = FL_SYNCING;
- spin_unlock_bh (&this->chip_lock);
- break;
- default:
- /* Not an idle state */
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule ();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- }
- /* Lock the device */
- spin_lock_bh (&this->chip_lock);
- /* Set the device to be ready again */
- if (this->state == FL_SYNCING) {
- this->state = FL_READY;
- wake_up (&this->wq);
- }
- /* Unlock the device */
- spin_unlock_bh (&this->chip_lock);
- }
- /*
- * Scan for the NAND device
- */
- int nand_scan (struct mtd_info *mtd)
- {
- int i, nand_maf_id, nand_dev_id;
- struct nand_chip *this = mtd->priv;
- /* Select the device */
- nand_select ();
- /* Send the command for reading device ID */
- nand_command (mtd, NAND_CMD_READID, 0x00, -1);
- /* Read manufacturer and device IDs */
- nand_maf_id = readb (this->IO_ADDR);
- nand_dev_id = readb (this->IO_ADDR);
- /* Print and store flash device information */
- for (i = 0; nand_flash_ids[i].name != NULL; i++) {
- if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
- nand_dev_id == nand_flash_ids[i].model_id) {
- if (!mtd->size) {
- mtd->name = nand_flash_ids[i].name;
- mtd->erasesize = nand_flash_ids[i].erasesize;
- mtd->size = (1 << nand_flash_ids[i].chipshift);
- mtd->eccsize = 256;
- if (nand_flash_ids[i].page256) {
- mtd->oobblock = 256;
- mtd->oobsize = 8;
- this->page_shift = 8;
- }
- else {
- mtd->oobblock = 512;
- mtd->oobsize = 16;
- this->page_shift = 9;
- }
- }
- printk (KERN_INFO "NAND device: Manufacture ID:"
- " 0x%02x, Chip ID: 0x%02x (%s)n",
- nand_maf_id, nand_dev_id, mtd->name);
- break;
- }
- }
- /* Initialize state and spinlock */
- this->state = FL_READY;
- spin_lock_init(&this->chip_lock);
- /* De-select the device */
- nand_deselect ();
- /* Print warning message for no device */
- if (!mtd->size) {
- printk (KERN_WARNING "No NAND device found!!!n");
- return 1;
- }
- /* Fill in remaining MTD driver data */
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
- mtd->module = THIS_MODULE;
- 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;
- mtd->readv = NULL;
- mtd->writev = nand_writev;
- mtd->sync = nand_sync;
- mtd->lock = NULL;
- mtd->unlock = NULL;
- mtd->suspend = NULL;
- mtd->resume = NULL;
- /* Return happy */
- return 0;
- }
- EXPORT_SYMBOL(nand_scan);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
- MODULE_DESCRIPTION("Generic NAND flash driver code");