/*
 *  drivers/mtd/nand.c
 *
 *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
 *
 * $Id: nand.c,v 1.10 2001/03/20 07:26:01 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 <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 = %i\n", (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 device\n");
		*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%08x\n", 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 = %i\n", (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 %i\n", 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 = %i\n", (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 device\n");
		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 succesful\n", 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 succesful\n",
					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 succesful\n",
					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 = %i\n", (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 page\n");
		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%08x\n", 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%08x\n", 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 = %i\n", (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 device\n");
		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 succesful\n", 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 succesful\n",
					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 succesful\n",
					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 = %i\n",
		(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 address\n");
		return -EINVAL;
	}

	/* Length must align on block boundary */
	if (instr->len & (mtd->erasesize - 1)) {
		DEBUG (MTD_DEBUG_LEVEL0,
			"nand_erase: Length not block aligned\n");
		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 device\n");
		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%08x\n", 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: called\n");

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);
