diff options
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
| -rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 398 | 
1 files changed, 217 insertions, 181 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 6b3a875647c..635ee002769 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -24,7 +24,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/sched.h>  #include <linux/delay.h>  #include <linux/interrupt.h> @@ -65,11 +64,11 @@ MODULE_PARM_DESC(otp,	"Corresponding behaviour of OneNAND in OTP"  			"	   : 2 -> 1st Block lock"  			"	   : 3 -> BOTH OTP Block and 1st Block lock"); -/** - *  onenand_oob_128 - oob info for Flex-Onenand with 4KB page - *  For now, we expose only 64 out of 80 ecc bytes +/* + * flexonenand_oob_128 - oob info for Flex-Onenand with 4KB page + * For now, we expose only 64 out of 80 ecc bytes   */ -static struct nand_ecclayout onenand_oob_128 = { +static struct nand_ecclayout flexonenand_oob_128 = {  	.eccbytes	= 64,  	.eccpos		= {  		6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -86,6 +85,35 @@ static struct nand_ecclayout onenand_oob_128 = {  	}  }; +/* + * onenand_oob_128 - oob info for OneNAND with 4KB page + * + * Based on specification: + * 4Gb M-die OneNAND Flash (KFM4G16Q4M, KFN8G16Q4M). Rev. 1.3, Apr. 2010 + * + * For eccpos we expose only 64 bytes out of 72 (see struct nand_ecclayout) + * + * oobfree uses the spare area fields marked as + * "Managed by internal ECC logic for Logical Sector Number area" + */ +static struct nand_ecclayout onenand_oob_128 = { +	.eccbytes	= 64, +	.eccpos		= { +		7, 8, 9, 10, 11, 12, 13, 14, 15, +		23, 24, 25, 26, 27, 28, 29, 30, 31, +		39, 40, 41, 42, 43, 44, 45, 46, 47, +		55, 56, 57, 58, 59, 60, 61, 62, 63, +		71, 72, 73, 74, 75, 76, 77, 78, 79, +		87, 88, 89, 90, 91, 92, 93, 94, 95, +		103, 104, 105, 106, 107, 108, 109, 110, 111, +		119 +	}, +	.oobfree	= { +		{2, 3}, {18, 3}, {34, 3}, {50, 3}, +		{66, 3}, {82, 3}, {98, 3}, {114, 3} +	} +}; +  /**   * onenand_oob_64 - oob info for large (2KB) page   */ @@ -400,8 +428,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le  		value = onenand_bufferram_address(this, block);  		this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); -		if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this) || -		    ONENAND_IS_4KB_PAGE(this)) +		if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this))  			/* It is always BufferRAM0 */  			ONENAND_SET_BUFFERRAM0(this);  		else @@ -430,7 +457,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le  		case FLEXONENAND_CMD_RECOVER_LSB:  		case ONENAND_CMD_READ:  		case ONENAND_CMD_READOOB: -			if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) +			if (ONENAND_IS_4KB_PAGE(this))  				/* It is always BufferRAM0 */  				dataram = ONENAND_SET_BUFFERRAM0(this);  			else @@ -949,6 +976,8 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state)  		if (this->state == FL_READY) {  			this->state = new_state;  			spin_unlock(&this->chip_lock); +			if (new_state != FL_PM_SUSPENDED && this->enable) +				this->enable(mtd);  			break;  		}  		if (new_state == FL_PM_SUSPENDED) { @@ -975,6 +1004,8 @@ static void onenand_release_device(struct mtd_info *mtd)  {  	struct onenand_chip *this = mtd->priv; +	if (this->state != FL_PM_SUSPENDED && this->disable) +		this->disable(mtd);  	/* Release the chip */  	spin_lock(&this->chip_lock);  	this->state = FL_READY; @@ -983,7 +1014,7 @@ static void onenand_release_device(struct mtd_info *mtd)  }  /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer   * @param mtd		MTD device structure   * @param buf		destination address   * @param column	oob offset to read from @@ -1047,7 +1078,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)  		return status;  	/* check if we failed due to uncorrectable error */ -	if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR) +	if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)  		return status;  	/* check if address lies in MLC region */ @@ -1090,10 +1121,10 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	int ret = 0;  	int writesize = this->writesize; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", -	      __func__, (unsigned int) from, (int) len); +	pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, +			(int)len); -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1127,8 +1158,10 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			if (unlikely(ret))  				ret = onenand_recover_lsb(mtd, from, ret);  			onenand_update_bufferram(mtd, from, !ret); -			if (ret == -EBADMSG) +			if (mtd_is_eccerr(ret))  				ret = 0; +			if (ret) +				break;  		}  		this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); @@ -1136,7 +1169,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			thisooblen = oobsize - oobcolumn;  			thisooblen = min_t(int, thisooblen, ooblen - oobread); -			if (ops->mode == MTD_OOB_AUTO) +			if (ops->mode == MTD_OPS_AUTO_OOB)  				onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);  			else  				this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1167,7 +1200,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	if (mtd->ecc_stats.failed - stats.failed)  		return -EBADMSG; -	return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +	/* return max bitflips per ecc step; ONENANDs correct 1 bit only */ +	return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;  }  /** @@ -1192,10 +1226,10 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	int ret = 0, boundary = 0;  	int writesize = this->writesize; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", -			__func__, (unsigned int) from, (int) len); +	pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, +			(int)len); -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1221,7 +1255,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			this->command(mtd, ONENAND_CMD_READ, from, writesize);   			ret = this->wait(mtd, FL_READING);   			onenand_update_bufferram(mtd, from, !ret); -			if (ret == -EBADMSG) +			if (mtd_is_eccerr(ret))  				ret = 0;   		}   	} @@ -1257,7 +1291,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			thisooblen = oobsize - oobcolumn;  			thisooblen = min_t(int, thisooblen, ooblen - oobread); -			if (ops->mode == MTD_OOB_AUTO) +			if (ops->mode == MTD_OPS_AUTO_OOB)  				onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);  			else  				this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1281,7 +1315,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,   		/* Now wait for load */   		ret = this->wait(mtd, FL_READING);   		onenand_update_bufferram(mtd, from, !ret); -		if (ret == -EBADMSG) +		if (mtd_is_eccerr(ret))  			ret = 0;   	} @@ -1299,7 +1333,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	if (mtd->ecc_stats.failed - stats.failed)  		return -EBADMSG; -	return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +	/* return max bitflips per ecc step; ONENANDs correct 1 bit only */ +	return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;  }  /** @@ -1317,19 +1352,19 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,  	struct mtd_ecc_stats stats;  	int read = 0, thislen, column, oobsize;  	size_t len = ops->ooblen; -	mtd_oob_mode_t mode = ops->mode; +	unsigned int mode = ops->mode;  	u_char *buf = ops->oobbuf;  	int ret = 0, readcmd;  	from += ops->ooboffs; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", -		__func__, (unsigned int) from, (int) len); +	pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, +			(int)len);  	/* Initialize return length value */  	ops->oobretlen = 0; -	if (mode == MTD_OOB_AUTO) +	if (mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1353,7 +1388,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,  	stats = mtd->ecc_stats; -	readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; +	readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;  	while (read < len) {  		cond_resched(); @@ -1369,13 +1404,13 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,  		if (unlikely(ret))  			ret = onenand_recover_lsb(mtd, from, ret); -		if (ret && ret != -EBADMSG) { +		if (ret && !mtd_is_eccerr(ret)) {  			printk(KERN_ERR "%s: read failed = 0x%x\n",  				__func__, ret);  			break;  		} -		if (mode == MTD_OOB_AUTO) +		if (mode == MTD_OPS_AUTO_OOB)  			onenand_transfer_auto_oob(mtd, buf, column, thislen);  		else  			this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); @@ -1429,7 +1464,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,  	int ret;  	onenand_get_device(mtd, FL_READING); -	ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? +	ret = ONENAND_IS_4KB_PAGE(this) ?  		onenand_mlc_read_ops_nolock(mtd, from, &ops) :  		onenand_read_ops_nolock(mtd, from, &ops);  	onenand_release_device(mtd); @@ -1453,10 +1488,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,  	int ret;  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB:  		break; -	case MTD_OOB_RAW: +	case MTD_OPS_RAW:  		/* Not implemented yet */  	default:  		return -EINVAL; @@ -1464,7 +1499,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,  	onenand_get_device(mtd, FL_READING);  	if (ops->datbuf) -		ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? +		ret = ONENAND_IS_4KB_PAGE(this) ?  			onenand_mlc_read_ops_nolock(mtd, from, ops) :  			onenand_read_ops_nolock(mtd, from, ops);  	else @@ -1485,8 +1520,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)  {  	struct onenand_chip *this = mtd->priv;  	unsigned long timeout; -	unsigned int interrupt; -	unsigned int ctrl; +	unsigned int interrupt, ctrl, ecc, addr1, addr8;  	/* The 20 msec is enough */  	timeout = jiffies + msecs_to_jiffies(20); @@ -1498,25 +1532,28 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)  	/* To get correct interrupt status in timeout case */  	interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);  	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); +	addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1); +	addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);  	if (interrupt & ONENAND_INT_READ) { -		int ecc = onenand_read_ecc(this); +		ecc = onenand_read_ecc(this);  		if (ecc & ONENAND_ECC_2BIT_ALL) { -			printk(KERN_WARNING "%s: ecc error = 0x%04x, " -				"controller error 0x%04x\n", -				__func__, ecc, ctrl); +			printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x " +			       "intr 0x%04x addr1 %#x addr8 %#x\n", +			       __func__, ecc, ctrl, interrupt, addr1, addr8);  			return ONENAND_BBT_READ_ECC_ERROR;  		}  	} else { -		printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n", -			__func__, ctrl, interrupt); +		printk(KERN_ERR "%s: read timeout! ctrl 0x%04x " +		       "intr 0x%04x addr1 %#x addr8 %#x\n", +		       __func__, ctrl, interrupt, addr1, addr8);  		return ONENAND_BBT_READ_FATAL_ERROR;  	}  	/* Initial bad block case: 0x2400 or 0x0400 */  	if (ctrl & ONENAND_CTRL_ERROR) { -		printk(KERN_DEBUG "%s: controller error = 0x%04x\n", -			__func__, ctrl); +		printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x " +		       "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);  		return ONENAND_BBT_READ_ERROR;  	} @@ -1540,8 +1577,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,  	size_t len = ops->ooblen;  	u_char *buf = ops->oobbuf; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %zi\n", -		__func__, (unsigned int) from, len); +	pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from, +			len);  	/* Initialize return value */  	ops->oobretlen = 0; @@ -1558,7 +1595,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,  	column = from & (mtd->oobsize - 1); -	readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; +	readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;  	while (read < len) {  		cond_resched(); @@ -1612,7 +1649,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to  	u_char *oob_buf = this->oob_buf;  	int status, i, readcmd; -	readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; +	readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;  	this->command(mtd, readcmd, to, mtd->oobsize);  	onenand_update_bufferram(mtd, to, 0); @@ -1641,11 +1678,10 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,  	int ret = 0;  	int thislen, column; +	column = addr & (this->writesize - 1); +  	while (len != 0) { -		thislen = min_t(int, this->writesize, len); -		column = addr & (this->writesize - 1); -		if (column + thislen > this->writesize) -			thislen = this->writesize - column; +		thislen = min_t(int, this->writesize - column, len);  		this->command(mtd, ONENAND_CMD_READ, addr, this->writesize); @@ -1659,12 +1695,13 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,  		this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize); -		if (memcmp(buf, this->verify_buf, thislen)) +		if (memcmp(buf, this->verify_buf + column, thislen))  			return -EBADMSG;  		len -= thislen;  		buf += thislen;  		addr += thislen; +		column = 0;  	}  	return 0; @@ -1714,18 +1751,8 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,  	/* Wait for any existing operation to clear */  	onenand_panic_wait(mtd); -	DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", -		__func__, (unsigned int) to, (int) len); - -	/* Initialize retlen, in case of early exit */ -	*retlen = 0; - -	/* Do not allow writes past end of device */ -	if (unlikely((to + len) > mtd->size)) { -		printk(KERN_ERR "%s: Attempt write to past end of device\n", -			__func__); -		return -EINVAL; -	} +	pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, +			(int)len);  	/* Reject writes, which are not page aligned */          if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) { @@ -1785,7 +1812,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,  }  /** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer   * @param mtd		MTD device structure   * @param oob_buf	oob buffer   * @param buf		source address @@ -1845,22 +1872,15 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  	const u_char *buf = ops->datbuf;  	const u_char *oob = ops->oobbuf;  	u_char *oobbuf; -	int ret = 0; +	int ret = 0, cmd; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", -		__func__, (unsigned int) to, (int) len); +	pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, +			(int)len);  	/* Initialize retlen, in case of early exit */  	ops->retlen = 0;  	ops->oobretlen = 0; -	/* Do not allow writes past end of device */ -	if (unlikely((to + len) > mtd->size)) { -		printk(KERN_ERR "%s: Attempt write to past end of device\n", -			__func__); -		return -EINVAL; -	} -  	/* Reject writes, which are not page aligned */          if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {  		printk(KERN_ERR "%s: Attempt to write not page aligned data\n", @@ -1872,7 +1892,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  	if (!len)  		return 0; -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1909,7 +1929,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  				/* We send data to spare ram with oobsize  				 * to prevent byte access */  				memset(oobbuf, 0xff, mtd->oobsize); -				if (ops->mode == MTD_OOB_AUTO) +				if (ops->mode == MTD_OPS_AUTO_OOB)  					onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);  				else  					memcpy(oobbuf + oobcolumn, oob, thisooblen); @@ -1954,7 +1974,19 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  			ONENAND_SET_NEXT_BUFFERRAM(this);  		} -		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); +		this->ongoing = 0; +		cmd = ONENAND_CMD_PROG; + +		/* Exclude 1st OTP and OTP blocks for cache program feature */ +		if (ONENAND_IS_CACHE_PROGRAM(this) && +		    likely(onenand_block(this, to) != 0) && +		    ONENAND_IS_4KB_PAGE(this) && +		    ((written + thislen) < len)) { +			cmd = ONENAND_CMD_2X_CACHE_PROG; +			this->ongoing = 1; +		} + +		this->command(mtd, cmd, to, mtd->writesize);  		/*  		 * 2 PLANE, MLC, and Flex-OneNAND wait here @@ -2007,7 +2039,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  /** - * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band   * @param mtd		MTD device structure   * @param to		offset to write to   * @param len		number of bytes to write @@ -2026,17 +2058,17 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,  	u_char *oobbuf;  	size_t len = ops->ooblen;  	const u_char *buf = ops->oobbuf; -	mtd_oob_mode_t mode = ops->mode; +	unsigned int mode = ops->mode;  	to += ops->ooboffs; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", -		__func__, (unsigned int) to, (int) len); +	pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, +			(int)len);  	/* Initialize retlen, in case of early exit */  	ops->oobretlen = 0; -	if (mode == MTD_OOB_AUTO) +	if (mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -2067,7 +2099,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,  	oobbuf = this->oob_buf; -	oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; +	oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;  	/* Loop until all data write */  	while (written < len) { @@ -2080,13 +2112,13 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,  		/* We send data to spare ram with oobsize  		 * to prevent byte access */  		memset(oobbuf, 0xff, mtd->oobsize); -		if (mode == MTD_OOB_AUTO) +		if (mode == MTD_OPS_AUTO_OOB)  			onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);  		else  			memcpy(oobbuf + column, buf, thislen);  		this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); -		if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) { +		if (ONENAND_IS_4KB_PAGE(this)) {  			/* Set main area of DataRAM to 0xff*/  			memset(this->page_buf, 0xff, mtd->writesize);  			this->write_bufferram(mtd, ONENAND_DATARAM, @@ -2169,10 +2201,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,  	int ret;  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB:  		break; -	case MTD_OOB_RAW: +	case MTD_OPS_RAW:  		/* Not implemented yet */  	default:  		return -EINVAL; @@ -2233,7 +2265,7 @@ static int onenand_multiblock_erase_verify(struct mtd_info *mtd,  }  /** - * onenand_multiblock_erase - [Internal] erase block(s) using multiblock erase + * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase   * @param mtd		MTD device structure   * @param instr		erase instruction   * @param region	erase region @@ -2349,7 +2381,7 @@ static int onenand_multiblock_erase(struct mtd_info *mtd,  /** - * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase + * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase   * @param mtd		MTD device structure   * @param instr		erase instruction   * @param region	erase region @@ -2405,7 +2437,7 @@ static int onenand_block_by_block_erase(struct mtd_info *mtd,  		len -= block_size;  		addr += block_size; -		if (addr == region_end) { +		if (region && addr == region_end) {  			if (!len)  				break;  			region++; @@ -2441,14 +2473,9 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)  	struct mtd_erase_region_info *region = NULL;  	loff_t region_offset = 0; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__, -	      (unsigned long long) instr->addr, (unsigned long long) instr->len); - -	/* Do not allow erase past end of device */ -	if (unlikely((len + addr) > mtd->size)) { -		printk(KERN_ERR "%s: Erase past end of device\n", __func__); -		return -EINVAL; -	} +	pr_debug("%s: start=0x%012llx, len=%llu\n", __func__, +			(unsigned long long)instr->addr, +			(unsigned long long)instr->len);  	if (FLEXONENAND(this)) {  		/* Find the eraseregion of this address */ @@ -2476,12 +2503,11 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)  		return -EINVAL;  	} -	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; -  	/* Grab the lock and see if the device is available */  	onenand_get_device(mtd, FL_ERASING); -	if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { +	if (ONENAND_IS_4KB_PAGE(this) || region || +	    instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {  		/* region is set for Flex-OneNAND (no mb erase) */  		ret = onenand_block_by_block_erase(mtd, instr,  						   region, block_size); @@ -2509,7 +2535,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)   */  static void onenand_sync(struct mtd_info *mtd)  { -	DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); +	pr_debug("%s: called\n", __func__);  	/* Grab the lock and see if the device is available */  	onenand_get_device(mtd, FL_SYNCING); @@ -2529,10 +2555,6 @@ static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)  {  	int ret; -	/* Check for invalid offset */ -	if (ofs > mtd->size) -		return -EINVAL; -  	onenand_get_device(mtd, FL_READING);  	ret = onenand_block_isbad_nolock(mtd, ofs, 0);  	onenand_release_device(mtd); @@ -2553,7 +2575,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  	struct bbm_info *bbm = this->bbm;  	u_char buf[2] = {0, 0};  	struct mtd_oob_ops ops = { -		.mode = MTD_OOB_PLACE, +		.mode = MTD_OPS_PLACE_OOB,  		.ooblen = 2,  		.oobbuf = buf,  		.ooboffs = 0, @@ -2583,7 +2605,6 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)   */  static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)  { -	struct onenand_chip *this = mtd->priv;  	int ret;  	ret = onenand_block_isbad(mtd, ofs); @@ -2595,7 +2616,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)  	}  	onenand_get_device(mtd, FL_WRITING); -	ret = this->block_markbad(mtd, ofs); +	ret = mtd_block_markbad(mtd, ofs);  	onenand_release_device(mtd);  	return ret;  } @@ -2873,7 +2894,7 @@ static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,  }  /** - * onenand_otp_write_oob_nolock - [Internal] OneNAND write out-of-band, specific to OTP + * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP   * @param mtd		MTD device structure   * @param to		offset to write to   * @param len		number of bytes to write @@ -3029,7 +3050,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,  	this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);  	this->wait(mtd, FL_OTPING); -	ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? +	ret = ONENAND_IS_4KB_PAGE(this) ?  		onenand_mlc_read_ops_nolock(mtd, from, &ops) :  		onenand_read_ops_nolock(mtd, from, &ops); @@ -3121,7 +3142,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,  		this->command(mtd, ONENAND_CMD_RESET, 0, 0);  		this->wait(mtd, FL_RESETING);  	} else { -		ops.mode = MTD_OOB_PLACE; +		ops.mode = MTD_OPS_PLACE_OOB;  		ops.ooblen = len;  		ops.oobbuf = buf;  		ops.ooboffs = 0; @@ -3216,20 +3237,17 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,  /**   * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info   * @param mtd		MTD device structure - * @param buf		the databuffer to put/get data   * @param len		number of bytes to read + * @param retlen	pointer to variable to store the number of read bytes + * @param buf		the databuffer to put/get data   *   * Read factory OTP info.   */ -static int onenand_get_fact_prot_info(struct mtd_info *mtd, -			struct otp_info *buf, size_t len) +static int onenand_get_fact_prot_info(struct mtd_info *mtd, size_t len, +				      size_t *retlen, struct otp_info *buf)  { -	size_t retlen; -	int ret; - -	ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY); - -	return ret ? : retlen; +	return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL, +				MTD_OTP_FACTORY);  }  /** @@ -3251,20 +3269,17 @@ static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,  /**   * onenand_get_user_prot_info - [MTD Interface] Read user OTP info   * @param mtd		MTD device structure - * @param buf		the databuffer to put/get data + * @param retlen	pointer to variable to store the number of read bytes   * @param len		number of bytes to read + * @param buf		the databuffer to put/get data   *   * Read user OTP info.   */ -static int onenand_get_user_prot_info(struct mtd_info *mtd, -			struct otp_info *buf, size_t len) +static int onenand_get_user_prot_info(struct mtd_info *mtd, size_t len, +				      size_t *retlen, struct otp_info *buf)  { -	size_t retlen; -	int ret; - -	ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER); - -	return ret ? : retlen; +	return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL, +				MTD_OTP_USER);  }  /** @@ -3377,8 +3392,23 @@ static void onenand_check_features(struct mtd_info *mtd)  	case ONENAND_DEVICE_DENSITY_4Gb:  		if (ONENAND_IS_DDP(this))  			this->options |= ONENAND_HAS_2PLANE; -		else if (numbufs == 1) +		else if (numbufs == 1) {  			this->options |= ONENAND_HAS_4KB_PAGE; +			this->options |= ONENAND_HAS_CACHE_PROGRAM; +			/* +			 * There are two different 4KiB pagesize chips +			 * and no way to detect it by H/W config values. +			 * +			 * To detect the correct NOP for each chips, +			 * It should check the version ID as workaround. +			 * +			 * Now it has as following +			 * KFM4G16Q4M has NOP 4 with version ID 0x0131 +			 * KFM4G16Q5M has NOP 1 with versoin ID 0x013e +			 */ +			if ((this->version_id & 0xf) == 0xe) +				this->options |= ONENAND_HAS_NOP_1; +		}  	case ONENAND_DEVICE_DENSITY_2Gb:  		/* 2Gb DDP does not have 2 plane */ @@ -3399,7 +3429,11 @@ static void onenand_check_features(struct mtd_info *mtd)  		break;  	} -	if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) +	/* The MLC has 4KiB pagesize. */ +	if (ONENAND_IS_MLC(this)) +		this->options |= ONENAND_HAS_4KB_PAGE; + +	if (ONENAND_IS_4KB_PAGE(this))  		this->options &= ~ONENAND_HAS_2PLANE;  	if (FLEXONENAND(this)) { @@ -3415,6 +3449,8 @@ static void onenand_check_features(struct mtd_info *mtd)  		printk(KERN_DEBUG "Chip has 2 plane\n");  	if (this->options & ONENAND_HAS_4KB_PAGE)  		printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); +	if (this->options & ONENAND_HAS_CACHE_PROGRAM) +		printk(KERN_DEBUG "Chip has cache program feature\n");  }  /** @@ -3482,7 +3518,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)  {  	struct onenand_chip *this = mtd->priv;  	unsigned die, bdry; -	int ret, syscfg, locked; +	int syscfg, locked;  	/* Disable ECC */  	syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); @@ -3493,7 +3529,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)  		this->wait(mtd, FL_SYNCING);  		this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0); -		ret = this->wait(mtd, FL_READING); +		this->wait(mtd, FL_READING);  		bdry = this->read_word(this->base + ONENAND_DATARAM);  		if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3) @@ -3503,7 +3539,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)  		this->boundary[die] = bdry & FLEXONENAND_PI_MASK;  		this->command(mtd, ONENAND_CMD_RESET, 0, 0); -		ret = this->wait(mtd, FL_RESETING); +		this->wait(mtd, FL_RESETING);  		printk(KERN_INFO "Die %d boundary: %d%s\n", die,  		       this->boundary[die], locked ? "(Locked)" : "(Unlocked)"); @@ -3606,7 +3642,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int  	int i, ret;  	int block;  	struct mtd_oob_ops ops = { -		.mode = MTD_OOB_PLACE, +		.mode = MTD_OPS_PLACE_OOB,  		.ooboffs = 0,  		.ooblen	= mtd->oobsize,  		.datbuf	= NULL, @@ -3647,7 +3683,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int   * flexonenand_set_boundary	- Writes the SLC boundary   * @param mtd			- mtd info structure   */ -int flexonenand_set_boundary(struct mtd_info *mtd, int die, +static int flexonenand_set_boundary(struct mtd_info *mtd, int die,  				    int boundary, int lock)  {  	struct onenand_chip *this = mtd->priv; @@ -3687,7 +3723,7 @@ int flexonenand_set_boundary(struct mtd_info *mtd, int die,  	/* Check is boundary is locked */  	this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0); -	ret = this->wait(mtd, FL_READING); +	this->wait(mtd, FL_READING);  	thisboundary = this->read_word(this->base + ONENAND_DATARAM);  	if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) { @@ -3788,7 +3824,7 @@ static int onenand_chip_probe(struct mtd_info *mtd)  static int onenand_probe(struct mtd_info *mtd)  {  	struct onenand_chip *this = mtd->priv; -	int maf_id, dev_id, ver_id; +	int dev_id, ver_id;  	int density;  	int ret; @@ -3796,8 +3832,7 @@ static int onenand_probe(struct mtd_info *mtd)  	if (ret)  		return ret; -	/* Read manufacturer and device IDs from Register */ -	maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); +	/* Device and version IDs from Register */  	dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);  	ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);  	this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY); @@ -3831,7 +3866,7 @@ static int onenand_probe(struct mtd_info *mtd)  	/* The data buffer size is equal to page size */  	mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);  	/* We use the full BufferRAM */ -	if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) +	if (ONENAND_IS_4KB_PAGE(this))  		mtd->writesize <<= 1;  	mtd->oobsize = mtd->writesize >> 5; @@ -3953,11 +3988,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)  	/* Allocate buffers, if necessary */  	if (!this->page_buf) {  		this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL); -		if (!this->page_buf) { -			printk(KERN_ERR "%s: Can't allocate page_buf\n", -				__func__); +		if (!this->page_buf)  			return -ENOMEM; -		}  #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE  		this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);  		if (!this->verify_buf) { @@ -3970,8 +4002,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)  	if (!this->oob_buf) {  		this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);  		if (!this->oob_buf) { -			printk(KERN_ERR "%s: Can't allocate oob_buf\n", -				__func__);  			if (this->options & ONENAND_PAGEBUF_ALLOC) {  				this->options &= ~ONENAND_PAGEBUF_ALLOC;  				kfree(this->page_buf); @@ -3990,8 +4020,15 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)  	 */  	switch (mtd->oobsize) {  	case 128: -		this->ecclayout = &onenand_oob_128; -		mtd->subpage_sft = 0; +		if (FLEXONENAND(this)) { +			this->ecclayout = &flexonenand_oob_128; +			mtd->subpage_sft = 0; +		} else { +			this->ecclayout = &onenand_oob_128; +			mtd->subpage_sft = 2; +		} +		if (ONENAND_IS_NOP_1(this)) +			mtd->subpage_sft = 0;  		break;  	case 64:  		this->ecclayout = &onenand_oob_64; @@ -4026,37 +4063,40 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)  	mtd->oobavail = this->ecclayout->oobavail;  	mtd->ecclayout = this->ecclayout; +	mtd->ecc_strength = 1;  	/* Fill in remaining MTD driver data */  	mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;  	mtd->flags = MTD_CAP_NANDFLASH; -	mtd->erase = onenand_erase; -	mtd->point = NULL; -	mtd->unpoint = NULL; -	mtd->read = onenand_read; -	mtd->write = onenand_write; -	mtd->read_oob = onenand_read_oob; -	mtd->write_oob = onenand_write_oob; -	mtd->panic_write = onenand_panic_write; +	mtd->_erase = onenand_erase; +	mtd->_point = NULL; +	mtd->_unpoint = NULL; +	mtd->_read = onenand_read; +	mtd->_write = onenand_write; +	mtd->_read_oob = onenand_read_oob; +	mtd->_write_oob = onenand_write_oob; +	mtd->_panic_write = onenand_panic_write;  #ifdef CONFIG_MTD_ONENAND_OTP -	mtd->get_fact_prot_info = onenand_get_fact_prot_info; -	mtd->read_fact_prot_reg = onenand_read_fact_prot_reg; -	mtd->get_user_prot_info = onenand_get_user_prot_info; -	mtd->read_user_prot_reg = onenand_read_user_prot_reg; -	mtd->write_user_prot_reg = onenand_write_user_prot_reg; -	mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; +	mtd->_get_fact_prot_info = onenand_get_fact_prot_info; +	mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg; +	mtd->_get_user_prot_info = onenand_get_user_prot_info; +	mtd->_read_user_prot_reg = onenand_read_user_prot_reg; +	mtd->_write_user_prot_reg = onenand_write_user_prot_reg; +	mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;  #endif -	mtd->sync = onenand_sync; -	mtd->lock = onenand_lock; -	mtd->unlock = onenand_unlock; -	mtd->suspend = onenand_suspend; -	mtd->resume = onenand_resume; -	mtd->block_isbad = onenand_block_isbad; -	mtd->block_markbad = onenand_block_markbad; +	mtd->_sync = onenand_sync; +	mtd->_lock = onenand_lock; +	mtd->_unlock = onenand_unlock; +	mtd->_suspend = onenand_suspend; +	mtd->_resume = onenand_resume; +	mtd->_block_isbad = onenand_block_isbad; +	mtd->_block_markbad = onenand_block_markbad;  	mtd->owner = THIS_MODULE; +	mtd->writebufsize = mtd->writesize;  	/* Unlock whole block */ -	this->unlock_all(mtd); +	if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING)) +		this->unlock_all(mtd);  	ret = this->scan_bbt(mtd);  	if ((!FLEXONENAND(this)) || ret) @@ -4078,12 +4118,8 @@ void onenand_release(struct mtd_info *mtd)  {  	struct onenand_chip *this = mtd->priv; -#ifdef CONFIG_MTD_PARTITIONS  	/* Deregister partitions */ -	del_mtd_partitions (mtd); -#endif -	/* Deregister the device */ -	del_mtd_device (mtd); +	mtd_device_unregister(mtd);  	/* Free bad block table memory, if allocated */  	if (this->bbm) {  | 
