diff options
Diffstat (limited to 'drivers/mtd')
44 files changed, 2497 insertions, 1689 deletions
| diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 543c845ff..99f39fc75 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -25,7 +25,9 @@ include $(TOPDIR)/config.mk  LIB	:= $(obj)libmtd.o -COBJS-$(CONFIG_MTD_DEVICE) += mtdcore.o +ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND))) +COBJS-y += mtdcore.o +endif  COBJS-$(CONFIG_MTD_PARTITIONS) += mtdpart.o  COBJS-$(CONFIG_MTD_CONCAT) += mtdconcat.o  COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 25f875202..25a571075 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -1797,7 +1797,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)  			};  			int i; -			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { +			for (i = 0; i < ARRAY_SIZE(modes); i++) {  				info->vendor = modes[i];  				info->start[0] =  					(ulong)map_physmem(base, @@ -1883,8 +1883,7 @@ static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)  	/* Issue FLASH reset command */  	flash_cmd_reset(info); -	for (cfi_offset=0; -	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); +	for (cfi_offset = 0; cfi_offset < ARRAY_SIZE(flash_offset_cfi);  	     cfi_offset++) {  		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],  				 FLASH_CMD_CFI); @@ -2336,7 +2335,7 @@ void flash_protect_default(void)  #endif  #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) -	for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { +	for (i = 0; i < ARRAY_SIZE(apl); i++) {  		debug("autoprotecting from %08lx to %08lx\n",  		      apl[i].start, apl[i].start + apl[i].size - 1);  		flash_protect(FLAG_PROTECT_SET, diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c index 8d74fa941..bbb71a19e 100644 --- a/drivers/mtd/cfi_mtd.c +++ b/drivers/mtd/cfi_mtd.c @@ -244,12 +244,12 @@ int cfi_mtd_init(void)  		mtd->size		= fi->size;  		mtd->writesize		= 1; -		mtd->erase		= cfi_mtd_erase; -		mtd->read		= cfi_mtd_read; -		mtd->write		= cfi_mtd_write; -		mtd->sync		= cfi_mtd_sync; -		mtd->lock		= cfi_mtd_lock; -		mtd->unlock		= cfi_mtd_unlock; +		mtd->_erase		= cfi_mtd_erase; +		mtd->_read		= cfi_mtd_read; +		mtd->_write		= cfi_mtd_write; +		mtd->_sync		= cfi_mtd_sync; +		mtd->_lock		= cfi_mtd_lock; +		mtd->_unlock		= cfi_mtd_unlock;  		mtd->priv		= fi;  		if (add_mtd_device(mtd)) diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index e6d938417..31e4289b1 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -70,14 +70,14 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,  			/* Entire transaction goes into this subdev */  			size = len; -		err = subdev->read(subdev, from, size, &retsize, buf); +		err = mtd_read(subdev, from, size, &retsize, buf);  		/* Save information about bitflips! */  		if (unlikely(err)) { -			if (err == -EBADMSG) { +			if (mtd_is_eccerr(err)) {  				mtd->ecc_stats.failed++;  				ret = err; -			} else if (err == -EUCLEAN) { +			} else if (mtd_is_bitflip(err)) {  				mtd->ecc_stats.corrected++;  				/* Do not overwrite -EBADMSG !! */  				if (!ret) @@ -105,9 +105,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,  	int err = -EINVAL;  	int i; -	if (!(mtd->flags & MTD_WRITEABLE)) -		return -EROFS; -  	*retlen = 0;  	for (i = 0; i < concat->num_subdev; i++) { @@ -124,11 +121,7 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,  		else  			size = len; -		if (!(subdev->flags & MTD_WRITEABLE)) -			err = -EROFS; -		else -			err = subdev->write(subdev, to, size, &retsize, buf); - +		err = mtd_write(subdev, to, size, &retsize, buf);  		if (err)  			break; @@ -165,16 +158,16 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)  		if (from + devops.len > subdev->size)  			devops.len = subdev->size - from; -		err = subdev->read_oob(subdev, from, &devops); +		err = mtd_read_oob(subdev, from, &devops);  		ops->retlen += devops.retlen;  		ops->oobretlen += devops.oobretlen;  		/* Save information about bitflips! */  		if (unlikely(err)) { -			if (err == -EBADMSG) { +			if (mtd_is_eccerr(err)) {  				mtd->ecc_stats.failed++;  				ret = err; -			} else if (err == -EUCLEAN) { +			} else if (mtd_is_bitflip(err)) {  				mtd->ecc_stats.corrected++;  				/* Do not overwrite -EBADMSG !! */  				if (!ret) @@ -225,7 +218,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)  		if (to + devops.len > subdev->size)  			devops.len = subdev->size - to; -		err = subdev->write_oob(subdev, to, &devops); +		err = mtd_write_oob(subdev, to, &devops);  		ops->retlen += devops.retlen;  		if (err)  			return err; @@ -271,7 +264,7 @@ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)  	 * FIXME: Allow INTERRUPTIBLE. Which means  	 * not having the wait_queue head on the stack.  	 */ -	err = mtd->erase(mtd, erase); +	err = mtd_erase(mtd, erase);  	if (!err) {  		set_current_state(TASK_UNINTERRUPTIBLE);  		add_wait_queue(&waitq, &wait); @@ -294,15 +287,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)  	uint64_t length, offset = 0;  	struct erase_info *erase; -	if (!(mtd->flags & MTD_WRITEABLE)) -		return -EROFS; - -	if (instr->addr > concat->mtd.size) -		return -EINVAL; - -	if (instr->len + instr->addr > concat->mtd.size) -		return -EINVAL; -  	/*  	 * Check for proper erase block alignment of the to-be-erased area.  	 * It is easier to do this based on the super device's erase @@ -350,8 +334,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)  			return -EINVAL;  	} -	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; -  	/* make a local copy of instr to avoid modifying the caller's struct */  	erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); @@ -390,10 +372,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)  		else  			erase->len = length; -		if (!(subdev->flags & MTD_WRITEABLE)) { -			err = -EROFS; -			break; -		}  		length -= erase->len;  		if ((err = concat_dev_erase(subdev, erase))) {  			/* sanity check: should never happen since @@ -429,9 +407,6 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	struct mtd_concat *concat = CONCAT(mtd);  	int i, err = -EINVAL; -	if ((len + ofs) > mtd->size) -		return -EINVAL; -  	for (i = 0; i < concat->num_subdev; i++) {  		struct mtd_info *subdev = concat->subdev[i];  		uint64_t size; @@ -446,7 +421,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  		else  			size = len; -		err = subdev->lock(subdev, ofs, size); +		err = mtd_lock(subdev, ofs, size);  		if (err)  			break; @@ -467,9 +442,6 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	struct mtd_concat *concat = CONCAT(mtd);  	int i, err = 0; -	if ((len + ofs) > mtd->size) -		return -EINVAL; -  	for (i = 0; i < concat->num_subdev; i++) {  		struct mtd_info *subdev = concat->subdev[i];  		uint64_t size; @@ -484,7 +456,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  		else  			size = len; -		err = subdev->unlock(subdev, ofs, size); +		err = mtd_unlock(subdev, ofs, size);  		if (err)  			break; @@ -507,7 +479,7 @@ static void concat_sync(struct mtd_info *mtd)  	for (i = 0; i < concat->num_subdev; i++) {  		struct mtd_info *subdev = concat->subdev[i]; -		subdev->sync(subdev); +		mtd_sync(subdev);  	}  } @@ -516,12 +488,9 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)  	struct mtd_concat *concat = CONCAT(mtd);  	int i, res = 0; -	if (!concat->subdev[0]->block_isbad) +	if (!mtd_can_have_bb(concat->subdev[0]))  		return res; -	if (ofs > mtd->size) -		return -EINVAL; -  	for (i = 0; i < concat->num_subdev; i++) {  		struct mtd_info *subdev = concat->subdev[i]; @@ -530,7 +499,7 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)  			continue;  		} -		res = subdev->block_isbad(subdev, ofs); +		res = mtd_block_isbad(subdev, ofs);  		break;  	} @@ -542,12 +511,9 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)  	struct mtd_concat *concat = CONCAT(mtd);  	int i, err = -EINVAL; -	if (!concat->subdev[0]->block_markbad) +	if (!mtd_can_have_bb(concat->subdev[0]))  		return 0; -	if (ofs > mtd->size) -		return -EINVAL; -  	for (i = 0; i < concat->num_subdev; i++) {  		struct mtd_info *subdev = concat->subdev[i]; @@ -556,7 +522,7 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)  			continue;  		} -		err = subdev->block_markbad(subdev, ofs); +		err = mtd_block_markbad(subdev, ofs);  		if (!err)  			mtd->ecc_stats.badblocks++;  		break; @@ -609,14 +575,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to c  	concat->mtd.subpage_sft = subdev[0]->subpage_sft;  	concat->mtd.oobsize = subdev[0]->oobsize;  	concat->mtd.oobavail = subdev[0]->oobavail; -	if (subdev[0]->read_oob) -		concat->mtd.read_oob = concat_read_oob; -	if (subdev[0]->write_oob) -		concat->mtd.write_oob = concat_write_oob; -	if (subdev[0]->block_isbad) -		concat->mtd.block_isbad = concat_block_isbad; -	if (subdev[0]->block_markbad) -		concat->mtd.block_markbad = concat_block_markbad; +	if (subdev[0]->_read_oob) +		concat->mtd._read_oob = concat_read_oob; +	if (subdev[0]->_write_oob) +		concat->mtd._write_oob = concat_write_oob; +	if (subdev[0]->_block_isbad) +		concat->mtd._block_isbad = concat_block_isbad; +	if (subdev[0]->_block_markbad) +		concat->mtd._block_markbad = concat_block_markbad;  	concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; @@ -653,8 +619,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to c  		if (concat->mtd.writesize   !=  subdev[i]->writesize ||  		    concat->mtd.subpage_sft != subdev[i]->subpage_sft ||  		    concat->mtd.oobsize    !=  subdev[i]->oobsize || -		    !concat->mtd.read_oob  != !subdev[i]->read_oob || -		    !concat->mtd.write_oob != !subdev[i]->write_oob) { +		    !concat->mtd._read_oob  != !subdev[i]->_read_oob || +		    !concat->mtd._write_oob != !subdev[i]->_write_oob) {  			kfree(concat);  			printk("Incompatible OOB or ECC data on \"%s\"\n",  			       subdev[i]->name); @@ -669,12 +635,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to c  	concat->num_subdev = num_devs;  	concat->mtd.name = name; -	concat->mtd.erase = concat_erase; -	concat->mtd.read = concat_read; -	concat->mtd.write = concat_write; -	concat->mtd.sync = concat_sync; -	concat->mtd.lock = concat_lock; -	concat->mtd.unlock = concat_unlock; +	concat->mtd._erase = concat_erase; +	concat->mtd._read = concat_read; +	concat->mtd._write = concat_write; +	concat->mtd._sync = concat_sync; +	concat->mtd._lock = concat_lock; +	concat->mtd._unlock = concat_unlock;  	/*  	 * Combine the erase block size info of the subdevices: diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 3a81adaf6..49c08145a 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -25,6 +25,11 @@ int add_mtd_device(struct mtd_info *mtd)  			mtd->index = i;  			mtd->usecount = 0; +			/* default value if not set by driver */ +			if (mtd->bitflip_threshold == 0) +				mtd->bitflip_threshold = mtd->ecc_strength; + +  			/* No need to get a refcount on the module containing  			   the notifier, since we hold the mtd_table_mutex */ @@ -186,3 +191,189 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,  	}  }  #endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */ + + /* + * Erase is an asynchronous operation.  Device drivers are supposed + * to call instr->callback() whenever the operation completes, even + * if it completes with a failure. + * Callers are supposed to pass a callback function and wait for it + * to be called before writing to the block. + */ +int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ +	if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr) +		return -EINVAL; +	if (!(mtd->flags & MTD_WRITEABLE)) +		return -EROFS; +	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; +	if (!instr->len) { +		instr->state = MTD_ERASE_DONE; +		mtd_erase_callback(instr); +		return 0; +	} +	return mtd->_erase(mtd, instr); +} + +int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, +	     u_char *buf) +{ +	if (from < 0 || from > mtd->size || len > mtd->size - from) +		return -EINVAL; +	if (!len) +		return 0; +	return mtd->_read(mtd, from, len, retlen, buf); +} + +int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, +	      const u_char *buf) +{ +	*retlen = 0; +	if (to < 0 || to > mtd->size || len > mtd->size - to) +		return -EINVAL; +	if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE)) +		return -EROFS; +	if (!len) +		return 0; +	return mtd->_write(mtd, to, len, retlen, buf); +} + +/* + * In blackbox flight recorder like scenarios we want to make successful writes + * in interrupt context. panic_write() is only intended to be called when its + * known the kernel is about to panic and we need the write to succeed. Since + * the kernel is not going to be running for much longer, this function can + * break locks and delay to ensure the write succeeds (but not sleep). + */ +int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, +		    const u_char *buf) +{ +	*retlen = 0; +	if (!mtd->_panic_write) +		return -EOPNOTSUPP; +	if (to < 0 || to > mtd->size || len > mtd->size - to) +		return -EINVAL; +	if (!(mtd->flags & MTD_WRITEABLE)) +		return -EROFS; +	if (!len) +		return 0; +	return mtd->_panic_write(mtd, to, len, retlen, buf); +} + +int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ +	ops->retlen = ops->oobretlen = 0; +	if (!mtd->_read_oob) +		return -EOPNOTSUPP; +	return mtd->_read_oob(mtd, from, ops); +} + +/* + * Method to access the protection register area, present in some flash + * devices. The user data is one time programmable but the factory data is read + * only. + */ +int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, +			   size_t len) +{ +	if (!mtd->_get_fact_prot_info) +		return -EOPNOTSUPP; +	if (!len) +		return 0; +	return mtd->_get_fact_prot_info(mtd, buf, len); +} + +int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, +			   size_t *retlen, u_char *buf) +{ +	*retlen = 0; +	if (!mtd->_read_fact_prot_reg) +		return -EOPNOTSUPP; +	if (!len) +		return 0; +	return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf); +} + +int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf, +			   size_t len) +{ +	if (!mtd->_get_user_prot_info) +		return -EOPNOTSUPP; +	if (!len) +		return 0; +	return mtd->_get_user_prot_info(mtd, buf, len); +} + +int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, +			   size_t *retlen, u_char *buf) +{ +	*retlen = 0; +	if (!mtd->_read_user_prot_reg) +		return -EOPNOTSUPP; +	if (!len) +		return 0; +	return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf); +} + +int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, +			    size_t *retlen, u_char *buf) +{ +	*retlen = 0; +	if (!mtd->_write_user_prot_reg) +		return -EOPNOTSUPP; +	if (!len) +		return 0; +	return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf); +} + +int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) +{ +	if (!mtd->_lock_user_prot_reg) +		return -EOPNOTSUPP; +	if (!len) +		return 0; +	return mtd->_lock_user_prot_reg(mtd, from, len); +} + +/* Chip-supported device locking */ +int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ +	if (!mtd->_lock) +		return -EOPNOTSUPP; +	if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) +		return -EINVAL; +	if (!len) +		return 0; +	return mtd->_lock(mtd, ofs, len); +} + +int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ +	if (!mtd->_unlock) +		return -EOPNOTSUPP; +	if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) +		return -EINVAL; +	if (!len) +		return 0; +	return mtd->_unlock(mtd, ofs, len); +} + +int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ +	if (!mtd->_block_isbad) +		return 0; +	if (ofs < 0 || ofs > mtd->size) +		return -EINVAL; +	return mtd->_block_isbad(mtd, ofs); +} + +int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ +	if (!mtd->_block_markbad) +		return -EOPNOTSUPP; +	if (ofs < 0 || ofs > mtd->size) +		return -EINVAL; +	if (!(mtd->flags & MTD_WRITEABLE)) +		return -EROFS; +	return mtd->_block_markbad(mtd, ofs); +} + diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index cbfc6796c..9dfe7bbc9 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -52,17 +52,11 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,  	int res;  	stats = part->master->ecc_stats; - -	if (from >= mtd->size) -		len = 0; -	else if (from + len > mtd->size) -		len = mtd->size - from; -	res = part->master->read(part->master, from + part->offset, -				   len, retlen, buf); +	res = mtd_read(part->master, from + part->offset, len, retlen, buf);  	if (unlikely(res)) { -		if (res == -EUCLEAN) +		if (mtd_is_bitflip(res))  			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; -		if (res == -EBADMSG) +		if (mtd_is_eccerr(res))  			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;  	}  	return res; @@ -78,12 +72,12 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,  		return -EINVAL;  	if (ops->datbuf && from + ops->len > mtd->size)  		return -EINVAL; -	res = part->master->read_oob(part->master, from + part->offset, ops); +	res = mtd_read_oob(part->master, from + part->offset, ops);  	if (unlikely(res)) { -		if (res == -EUCLEAN) +		if (mtd_is_bitflip(res))  			mtd->ecc_stats.corrected++; -		if (res == -EBADMSG) +		if (mtd_is_eccerr(res))  			mtd->ecc_stats.failed++;  	}  	return res; @@ -93,58 +87,35 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,  		size_t len, size_t *retlen, u_char *buf)  {  	struct mtd_part *part = PART(mtd); -	return part->master->read_user_prot_reg(part->master, from, -					len, retlen, buf); +	return mtd_read_user_prot_reg(part->master, from, len, retlen, buf);  }  static int part_get_user_prot_info(struct mtd_info *mtd,  		struct otp_info *buf, size_t len)  {  	struct mtd_part *part = PART(mtd); -	return part->master->get_user_prot_info(part->master, buf, len); +	return mtd_get_user_prot_info(part->master, buf, len);  }  static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,  		size_t len, size_t *retlen, u_char *buf)  {  	struct mtd_part *part = PART(mtd); -	return part->master->read_fact_prot_reg(part->master, from, -					len, retlen, buf); +	return mtd_read_fact_prot_reg(part->master, from, len, retlen, buf);  }  static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,  		size_t len)  {  	struct mtd_part *part = PART(mtd); -	return part->master->get_fact_prot_info(part->master, buf, len); +	return mtd_get_fact_prot_info(part->master, buf, len);  }  static int part_write(struct mtd_info *mtd, loff_t to, size_t len,  		size_t *retlen, const u_char *buf)  {  	struct mtd_part *part = PART(mtd); -	if (!(mtd->flags & MTD_WRITEABLE)) -		return -EROFS; -	if (to >= mtd->size) -		len = 0; -	else if (to + len > mtd->size) -		len = mtd->size - to; -	return part->master->write(part->master, to + part->offset, -				    len, retlen, buf); -} - -static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len, -		size_t *retlen, const u_char *buf) -{ -	struct mtd_part *part = PART(mtd); -	if (!(mtd->flags & MTD_WRITEABLE)) -		return -EROFS; -	if (to >= mtd->size) -		len = 0; -	else if (to + len > mtd->size) -		len = mtd->size - to; -	return part->master->panic_write(part->master, to + part->offset, -				    len, retlen, buf); +	return mtd_write(part->master, to + part->offset, len, retlen, buf);  }  static int part_write_oob(struct mtd_info *mtd, loff_t to, @@ -152,41 +123,34 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,  {  	struct mtd_part *part = PART(mtd); -	if (!(mtd->flags & MTD_WRITEABLE)) -		return -EROFS; -  	if (to >= mtd->size)  		return -EINVAL;  	if (ops->datbuf && to + ops->len > mtd->size)  		return -EINVAL; -	return part->master->write_oob(part->master, to + part->offset, ops); +	return mtd_write_oob(part->master, to + part->offset, ops);  }  static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,  		size_t len, size_t *retlen, u_char *buf)  {  	struct mtd_part *part = PART(mtd); -	return part->master->write_user_prot_reg(part->master, from, -					len, retlen, buf); +	return mtd_write_user_prot_reg(part->master, from, len, retlen, buf);  }  static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,  		size_t len)  {  	struct mtd_part *part = PART(mtd); -	return part->master->lock_user_prot_reg(part->master, from, len); +	return mtd_lock_user_prot_reg(part->master, from, len);  }  static int part_erase(struct mtd_info *mtd, struct erase_info *instr)  {  	struct mtd_part *part = PART(mtd);  	int ret; -	if (!(mtd->flags & MTD_WRITEABLE)) -		return -EROFS; -	if (instr->addr >= mtd->size) -		return -EINVAL; +  	instr->addr += part->offset; -	ret = part->master->erase(part->master, instr); +	ret = mtd_erase(part->master, instr);  	if (ret) {  		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)  			instr->fail_addr -= part->offset; @@ -197,7 +161,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)  void mtd_erase_callback(struct erase_info *instr)  { -	if (instr->mtd->erase == part_erase) { +	if (instr->mtd->_erase == part_erase) {  		struct mtd_part *part = PART(instr->mtd);  		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) @@ -211,32 +175,26 @@ void mtd_erase_callback(struct erase_info *instr)  static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  {  	struct mtd_part *part = PART(mtd); -	if ((len + ofs) > mtd->size) -		return -EINVAL; -	return part->master->lock(part->master, ofs + part->offset, len); +	return mtd_lock(part->master, ofs + part->offset, len);  }  static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  {  	struct mtd_part *part = PART(mtd); -	if ((len + ofs) > mtd->size) -		return -EINVAL; -	return part->master->unlock(part->master, ofs + part->offset, len); +	return mtd_unlock(part->master, ofs + part->offset, len);  }  static void part_sync(struct mtd_info *mtd)  {  	struct mtd_part *part = PART(mtd); -	part->master->sync(part->master); +	mtd_sync(part->master);  }  static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)  {  	struct mtd_part *part = PART(mtd); -	if (ofs >= mtd->size) -		return -EINVAL;  	ofs += part->offset; -	return part->master->block_isbad(part->master, ofs); +	return mtd_block_isbad(part->master, ofs);  }  static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) @@ -244,12 +202,8 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)  	struct mtd_part *part = PART(mtd);  	int res; -	if (!(mtd->flags & MTD_WRITEABLE)) -		return -EROFS; -	if (ofs >= mtd->size) -		return -EINVAL;  	ofs += part->offset; -	res = part->master->block_markbad(part->master, ofs); +	res = mtd_block_markbad(part->master, ofs);  	if (!res)  		mtd->ecc_stats.badblocks++;  	return res; @@ -303,39 +257,36 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,  	slave->mtd.name = part->name;  	slave->mtd.owner = master->owner; -	slave->mtd.read = part_read; -	slave->mtd.write = part_write; - -	if (master->panic_write) -		slave->mtd.panic_write = part_panic_write; +	slave->mtd._read = part_read; +	slave->mtd._write = part_write; -	if (master->read_oob) -		slave->mtd.read_oob = part_read_oob; -	if (master->write_oob) -		slave->mtd.write_oob = part_write_oob; -	if (master->read_user_prot_reg) -		slave->mtd.read_user_prot_reg = part_read_user_prot_reg; -	if (master->read_fact_prot_reg) -		slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; -	if (master->write_user_prot_reg) -		slave->mtd.write_user_prot_reg = part_write_user_prot_reg; -	if (master->lock_user_prot_reg) -		slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; -	if (master->get_user_prot_info) -		slave->mtd.get_user_prot_info = part_get_user_prot_info; -	if (master->get_fact_prot_info) -		slave->mtd.get_fact_prot_info = part_get_fact_prot_info; -	if (master->sync) -		slave->mtd.sync = part_sync; -	if (master->lock) -		slave->mtd.lock = part_lock; -	if (master->unlock) -		slave->mtd.unlock = part_unlock; -	if (master->block_isbad) -		slave->mtd.block_isbad = part_block_isbad; -	if (master->block_markbad) -		slave->mtd.block_markbad = part_block_markbad; -	slave->mtd.erase = part_erase; +	if (master->_read_oob) +		slave->mtd._read_oob = part_read_oob; +	if (master->_write_oob) +		slave->mtd._write_oob = part_write_oob; +	if (master->_read_user_prot_reg) +		slave->mtd._read_user_prot_reg = part_read_user_prot_reg; +	if (master->_read_fact_prot_reg) +		slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg; +	if (master->_write_user_prot_reg) +		slave->mtd._write_user_prot_reg = part_write_user_prot_reg; +	if (master->_lock_user_prot_reg) +		slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg; +	if (master->_get_user_prot_info) +		slave->mtd._get_user_prot_info = part_get_user_prot_info; +	if (master->_get_fact_prot_info) +		slave->mtd._get_fact_prot_info = part_get_fact_prot_info; +	if (master->_sync) +		slave->mtd._sync = part_sync; +	if (master->_lock) +		slave->mtd._lock = part_lock; +	if (master->_unlock) +		slave->mtd._unlock = part_unlock; +	if (master->_block_isbad) +		slave->mtd._block_isbad = part_block_isbad; +	if (master->_block_markbad) +		slave->mtd._block_markbad = part_block_markbad; +	slave->mtd._erase = part_erase;  	slave->master = master;  	slave->offset = part->offset;  	slave->index = partno; @@ -416,12 +367,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,  	}  	slave->mtd.ecclayout = master->ecclayout; -	if (master->block_isbad) { +	if (master->_block_isbad) {  		uint64_t offs = 0;  		while (offs < slave->mtd.size) { -			if (master->block_isbad(master, -						offs + slave->offset)) +			if (mtd_block_isbad(master, offs + slave->offset))  				slave->mtd.ecc_stats.badblocks++;  			offs += slave->mtd.erasesize;  		} diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 882170491..bb81e8411 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -83,6 +83,7 @@ COBJS-$(CONFIG_NAND_DOCG4) += docg4.o  else  # minimal SPL drivers  COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o +COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o  COBJS-$(CONFIG_NAND_MXC) += mxc_nand_spl.o  endif # drivers diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 994dd9f09..3bfbaf8ac 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -489,7 +489,7 @@ normal_check:  }  static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, -	struct nand_chip *chip, uint8_t *buf, int page) +	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)  {  	struct atmel_nand_host *host = chip->priv;  	int eccsize = chip->ecc.size; @@ -529,8 +529,9 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,  	return 0;  } -static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, -		struct nand_chip *chip, const uint8_t *buf) +static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, +		struct nand_chip *chip, const uint8_t *buf, +		int oob_required)  {  	struct atmel_nand_host *host = chip->priv;  	uint32_t *eccpos = chip->ecc.layout->eccpos; @@ -557,7 +558,7 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,  	if (!timeout) {  		printk(KERN_ERR "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); -		return; +		goto out;  	}  	for (i = 0; i < host->pmecc_sector_number; i++) { @@ -570,6 +571,8 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,  		}  	}  	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +out: +	return 0;  }  static void atmel_pmecc_core_init(struct mtd_info *mtd) @@ -706,6 +709,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,  	nand->ecc.read_page = atmel_nand_pmecc_read_page;  	nand->ecc.write_page = atmel_nand_pmecc_write_page; +	nand->ecc.strength = cap;  	atmel_pmecc_core_init(mtd); @@ -775,9 +779,10 @@ static int atmel_nand_calculate(struct mtd_info *mtd,   * mtd:        mtd info structure   * chip:       nand chip info structure   * buf:        buffer to store read data + * oob_required:    caller expects OOB data read to chip->oob_poi   */ -static int atmel_nand_read_page(struct mtd_info *mtd, -		struct nand_chip *chip, uint8_t *buf, int page) +static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, +				uint8_t *buf, int oob_required, int page)  {  	int eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; diff --git a/drivers/mtd/nand/bfin_nand.c b/drivers/mtd/nand/bfin_nand.c index c7ddbb21d..7e755e896 100644 --- a/drivers/mtd/nand/bfin_nand.c +++ b/drivers/mtd/nand/bfin_nand.c @@ -374,9 +374,11 @@ int board_nand_init(struct nand_chip *chip)  		if (!NAND_IS_512()) {  			chip->ecc.bytes = 3;  			chip->ecc.size = 256; +			chip->ecc.strength = 1;  		} else {  			chip->ecc.bytes = 6;  			chip->ecc.size = 512; +			chip->ecc.strength = 2;  		}  		chip->ecc.mode = NAND_ECC_HW;  		chip->ecc.calculate = bfin_nfc_calculate_ecc; diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index e8506ddd9..90f59857f 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -607,12 +607,13 @@ void davinci_nand_init(struct nand_chip *nand)  {  	nand->chip_delay  = 0;  #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT -	nand->options	  |= NAND_USE_FLASH_BBT; +	nand->bbt_options	  |= NAND_BBT_USE_FLASH;  #endif  #ifdef CONFIG_SYS_NAND_HW_ECC  	nand->ecc.mode = NAND_ECC_HW;  	nand->ecc.size = 512;  	nand->ecc.bytes = 3; +	nand->ecc.strength = 1;  	nand->ecc.calculate = nand_davinci_calculate_ecc;  	nand->ecc.correct  = nand_davinci_correct_data;  	nand->ecc.hwctl  = nand_davinci_enable_hwecc; @@ -623,6 +624,7 @@ void davinci_nand_init(struct nand_chip *nand)  	nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;  	nand->ecc.size = 512;  	nand->ecc.bytes = 10; +	nand->ecc.strength = 4;  	nand->ecc.calculate = nand_davinci_4bit_calculate_ecc;  	nand->ecc.correct = nand_davinci_4bit_correct_data;  	nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index edf3a099b..4cd741ebb 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -134,7 +134,7 @@ static struct rs_control *rs_decoder;  /*   * The HW decoder in the DoC ASIC's provides us a error syndrome, - * which we must convert to a standard syndrom usable by the generic + * which we must convert to a standard syndrome usable by the generic   * Reed-Solomon library code.   *   * Fabrice Bellard figured this out in the old docecc code. I added @@ -154,7 +154,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)  	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);  	parity = ecc[1]; -	/* Initialize the syndrom buffer */ +	/* Initialize the syndrome buffer */  	for (i = 0; i < NROOTS; i++)  		s[i] = ds[0];  	/* @@ -1033,7 +1033,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,  		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);  	else  		WriteDOC(DOC_ECC_DIS, docptr, ECCConf); -	if (no_ecc_failures && (ret == -EBADMSG)) { +	if (no_ecc_failures && mtd_is_eccerr(ret)) {  		printk(KERN_ERR "suppressing ECC failure\n");  		ret = 0;  	} @@ -1073,7 +1073,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch  	size_t retlen;  	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { -		ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf); +		ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);  		if (retlen != mtd->writesize)  			continue;  		if (ret) { @@ -1098,7 +1098,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch  	/* Only one mediaheader was found.  We want buf to contain a  	   mediaheader on return, so we'll have to re-read the one we found. */  	offs = doc->mh0_page << this->page_shift; -	ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf); +	ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);  	if (retlen != mtd->writesize) {  		/* Insanity.  Give up. */  		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n"); @@ -1658,7 +1658,8 @@ static int __init doc_probe(unsigned long physadr)  	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;  	nand->ecc.size		= 512;  	nand->ecc.bytes		= 6; -	nand->options		= NAND_USE_FLASH_BBT; +	nand->ecc.strength	= 2; +	nand->bbt_options	= NAND_BBT_USE_FLASH;  	doc->physadr		= physadr;  	doc->virtadr		= virtadr; diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 7dd9953be..09f01c80d 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -487,7 +487,7 @@ static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  }  static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, -			  int page, int sndcmd) +			  int page)  {  	struct docg4_priv *doc = nand->priv;  	void __iomem *docptr = CONFIG_SYS_NAND_BASE; @@ -577,7 +577,7 @@ static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  		writew(p[i], nand->IO_ADDR_W);  } -static void write_page(struct mtd_info *mtd, struct nand_chip *nand, +static int write_page(struct mtd_info *mtd, struct nand_chip *nand,  		       const uint8_t *buf, int use_ecc)  {  	void __iomem *docptr = CONFIG_SYS_NAND_BASE; @@ -626,16 +626,18 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand,  	write_nop(docptr);  	writew(0, docptr + DOC_DATAEND);  	write_nop(docptr); + +	return 0;  } -static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, -				 const uint8_t *buf) +static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, +				 const uint8_t *buf, int oob_required)  {  	return write_page(mtd, nand, buf, 0);  } -static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, -			     const uint8_t *buf) +static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, +			     const uint8_t *buf, int oob_required)  {  	return write_page(mtd, nand, buf, 1);  } @@ -706,13 +708,13 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,  static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand, -			       uint8_t *buf, int page) +			       uint8_t *buf, int oob_required, int page)  {  	return read_page(mtd, nand, buf, page, 0);  }  static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand, -			   uint8_t *buf, int page) +			   uint8_t *buf, int oob_required, int page)  {  	return read_page(mtd, nand, buf, page, 1);  } @@ -779,7 +781,7 @@ static int read_factory_bbt(struct mtd_info *mtd)  		return -ENOMEM;  	read_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); -	status = docg4_read_page(mtd, nand, buf, DOCG4_FACTORY_BBT_PAGE); +	status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);  	if (status)  		goto exit; @@ -858,7 +860,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)  	/* write first page of block */  	write_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); -	docg4_write_page(mtd, nand, buf); +	docg4_write_page(mtd, nand, buf, 1);  	ret = pageprog(mtd);  	if (!ret)  		mtd->ecc_stats.badblocks++; @@ -959,8 +961,8 @@ int docg4_nand_init(struct mtd_info *mtd, struct nand_chip *nand, int devnum)  	nand->ecc.size = DOCG4_PAGE_SIZE;  	nand->ecc.prepad = 8;  	nand->ecc.bytes	= 8; -	nand->options = -		NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR; +	nand->ecc.strength = DOCG4_T; +	nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;  	nand->controller = &nand->hwcontrol;  	/* methods */ diff --git a/drivers/mtd/nand/docg4_spl.c b/drivers/mtd/nand/docg4_spl.c index 95e856c21..734cbeb7c 100644 --- a/drivers/mtd/nand/docg4_spl.c +++ b/drivers/mtd/nand/docg4_spl.c @@ -113,7 +113,6 @@ static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr)  	int g4_index = 0;  	uint16_t flash_status;  	uint16_t *buf; -	uint16_t discard, magic_high, magic_low;  	/* flash_offset must be aligned to the start of a block */  	if (flash_offset & 0x3ffff) @@ -154,9 +153,9 @@ static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr)  	 * The IPL on the palmtreo680 requires that this contain a 32 bit magic  	 * number, or the load aborts.  We'll ignore it.  	 */ -	discard = readw(docptr + 0x103c); /* hw quirk; 1st read discarded */ -	magic_low = readw(docptr + 0x103c); -	magic_high = readw(docptr + DOCG4_MYSTERY_REG); +	readw(docptr + 0x103c); /* hw quirk; 1st read discarded */ +	readw(docptr + 0x103c);	/* lower 16 bits of magic number */ +	readw(docptr + DOCG4_MYSTERY_REG); /* upper 16 bits of magic number */  	writew(0, docptr + DOC_DATAEND);  	write_nop(docptr);  	write_nop(docptr); @@ -183,15 +182,15 @@ static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr)  		write_nop(docptr);  		/* read the 512 bytes of page data, 2 bytes at a time */ -		discard = readw(docptr + 0x103c); +		readw(docptr + 0x103c); /* hw quirk */  		for (i = 0; i < 256; i++)  			*buf++ = readw(docptr + 0x103c);  		/* read oob, but discard it */  		for (i = 0; i < 7; i++) -			discard = readw(docptr + 0x103c); -		discard = readw(docptr + DOCG4_OOB_6_7); -		discard = readw(docptr + DOCG4_OOB_6_7); +			readw(docptr + 0x103c); +		readw(docptr + DOCG4_OOB_6_7); +		readw(docptr + DOCG4_OOB_6_7);  		writew(0, docptr + DOC_DATAEND);  		write_nop(docptr); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 834a8a649..0fa776ae9 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -640,9 +640,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)  	return fsl_elbc_read_byte(mtd);  } -static int fsl_elbc_read_page(struct mtd_info *mtd, -			      struct nand_chip *chip, -			      uint8_t *buf, int page) +static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, +			      uint8_t *buf, int oob_required, int page)  {  	fsl_elbc_read_buf(mtd, buf, mtd->writesize);  	fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -656,12 +655,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd,  /* ECC will be calculated automatically, and errors will be detected in   * waitfunc.   */ -static void fsl_elbc_write_page(struct mtd_info *mtd, -				struct nand_chip *chip, -				const uint8_t *buf) +static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, +				const uint8_t *buf, int oob_required)  {  	fsl_elbc_write_buf(mtd, buf, mtd->writesize);  	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + +	return 0;  }  static struct fsl_elbc_ctrl *elbc_ctrl; @@ -747,8 +747,8 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)  	nand->bbt_md = &bbt_mirror_descr;    	/* set up nand options */ -	nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | -			NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE; +	nand->options = NAND_NO_SUBPAGE_WRITE; +	nand->bbt_options = NAND_BBT_USE_FLASH;  	nand->controller = &elbc_ctrl->controller;  	nand->priv = priv; @@ -756,20 +756,8 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)  	nand->ecc.read_page = fsl_elbc_read_page;  	nand->ecc.write_page = fsl_elbc_write_page; -#ifdef CONFIG_FSL_ELBC_FMR -	priv->fmr = CONFIG_FSL_ELBC_FMR; -#else  	priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT); -	/* -	 * Hardware expects small page has ECCM0, large page has ECCM1 -	 * when booting from NAND.  Board config can override if not -	 * booting from NAND. -	 */ -	if (or & OR_FCM_PGS) -		priv->fmr |= FMR_ECCM; -#endif -  	/* If CS Base Register selects full hardware ECC then use it */  	if ((br & BR_DECC) == BR_DECC_CHK_GEN) {  		nand->ecc.mode = NAND_ECC_HW; @@ -781,16 +769,32 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)  		nand->ecc.size = 512;  		nand->ecc.bytes = 3;  		nand->ecc.steps = 1; +		nand->ecc.strength = 1;  	} else {  		/* otherwise fall back to default software ECC */  		nand->ecc.mode = NAND_ECC_SOFT;  	} +	ret = nand_scan_ident(mtd, 1, NULL); +	if (ret) +		return ret; +  	/* Large-page-specific setup */ -	if (or & OR_FCM_PGS) { +	if (mtd->writesize == 2048) { +		setbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, +			     OR_FCM_PGS); +		in_be32(&elbc_ctrl->regs->bank[priv->bank].or); +  		priv->page_size = 1;  		nand->badblock_pattern = &largepage_memorybased; +		/* +		 * Hardware expects small page has ECCM0, large page has +		 * ECCM1 when booting from NAND, and we follow that even +		 * when not booting from NAND. +		 */ +		priv->fmr |= FMR_ECCM; +  		/* adjust ecc setup if needed */  		if ((br & BR_DECC) == BR_DECC_CHK_GEN) {  			nand->ecc.steps = 4; @@ -798,12 +802,14 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)  					   &fsl_elbc_oob_lp_eccm1 :  					   &fsl_elbc_oob_lp_eccm0;  		} +	} else if (mtd->writesize == 512) { +		clrbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, +			     OR_FCM_PGS); +		in_be32(&elbc_ctrl->regs->bank[priv->bank].or); +	} else { +		return -ENODEV;  	} -	ret = nand_scan_ident(mtd, 1, NULL); -	if (ret) -		return ret; -  	ret = nand_scan_tail(mtd);  	if (ret)  		return ret; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index b13d8a930..439822c5a 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -21,6 +21,7 @@  #include <common.h>  #include <malloc.h> +#include <nand.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h> @@ -41,7 +42,6 @@ struct fsl_ifc_ctrl;  /* mtd information per set */  struct fsl_ifc_mtd { -	struct mtd_info mtd;  	struct nand_chip chip;  	struct fsl_ifc_ctrl *ctrl; @@ -686,9 +686,8 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)  	return nand_fsr;  } -static int fsl_ifc_read_page(struct mtd_info *mtd, -			      struct nand_chip *chip, -			      uint8_t *buf, int page) +static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, +			     uint8_t *buf, int oob_required, int page)  {  	struct fsl_ifc_mtd *priv = chip->priv;  	struct fsl_ifc_ctrl *ctrl = priv->ctrl; @@ -705,12 +704,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd,  /* ECC will be calculated automatically, and errors will be detected in   * waitfunc.   */ -static void fsl_ifc_write_page(struct mtd_info *mtd, -				struct nand_chip *chip, -				const uint8_t *buf) +static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, +			       const uint8_t *buf, int oob_required)  {  	fsl_ifc_write_buf(mtd, buf, mtd->writesize);  	fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + +	return 0;  }  static void fsl_ifc_ctrl_init(void) @@ -794,11 +794,14 @@ static void fsl_ifc_sram_init(void)  	out_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext);  } -int board_nand_init(struct nand_chip *nand) +static int fsl_ifc_chip_init(int devnum, u8 *addr)  { +	struct mtd_info *mtd = &nand_info[devnum]; +	struct nand_chip *nand;  	struct fsl_ifc_mtd *priv;  	struct nand_ecclayout *layout;  	uint32_t cspr = 0, csor = 0, ver = 0; +	int ret;  	if (!ifc_ctrl) {  		fsl_ifc_ctrl_init(); @@ -811,18 +814,18 @@ int board_nand_init(struct nand_chip *nand)  		return -ENOMEM;  	priv->ctrl = ifc_ctrl; -	priv->vbase = nand->IO_ADDR_R; +	priv->vbase = addr;  	/* Find which chip select it is connected to.  	 */  	for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { -		phys_addr_t base_addr = virt_to_phys(nand->IO_ADDR_R); +		phys_addr_t phys_addr = virt_to_phys(addr);  		cspr = in_be32(&ifc_ctrl->regs->cspr_cs[priv->bank].cspr);  		csor = in_be32(&ifc_ctrl->regs->csor_cs[priv->bank].csor);  		if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND && -		    (cspr & CSPR_BA) == CSPR_PHYS_ADDR(base_addr)) { +		    (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr)) {  			ifc_ctrl->cs_nand = priv->bank << IFC_NAND_CSEL_SHIFT;  			break;  		} @@ -835,6 +838,9 @@ int board_nand_init(struct nand_chip *nand)  		return -ENODEV;  	} +	nand = &priv->chip; +	mtd->priv = nand; +  	ifc_ctrl->chips[priv->bank] = priv;  	/* fill in nand_chip structure */ @@ -852,8 +858,8 @@ int board_nand_init(struct nand_chip *nand)  	nand->bbt_md = &bbt_mirror_descr;  	/* set up nand options */ -	nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | -			NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE; +	nand->options = NAND_NO_SUBPAGE_WRITE; +	nand->bbt_options = NAND_BBT_USE_FLASH;  	if (cspr & CSPR_PORT_SIZE_16) {  		nand->read_byte = fsl_ifc_read_byte16; @@ -884,11 +890,13 @@ int board_nand_init(struct nand_chip *nand)  			bbt_mirror_descr.offs = 0;  		} +		nand->ecc.strength = 4;  		priv->bufnum_mask = 15;  		break;  	case CSOR_NAND_PGS_2K:  		layout = &oob_2048_ecc4; +		nand->ecc.strength = 4;  		priv->bufnum_mask = 3;  		break; @@ -896,8 +904,10 @@ int board_nand_init(struct nand_chip *nand)  		if ((csor & CSOR_NAND_ECC_MODE_MASK) ==  		    CSOR_NAND_ECC_MODE_4) {  			layout = &oob_4096_ecc4; +			nand->ecc.strength = 4;  		} else {  			layout = &oob_4096_ecc8; +			nand->ecc.strength = 8;  			nand->ecc.bytes = 16;  		} @@ -921,5 +931,31 @@ int board_nand_init(struct nand_chip *nand)  	if (ver == FSL_IFC_V1_1_0)  		fsl_ifc_sram_init(); +	ret = nand_scan_ident(mtd, 1, NULL); +	if (ret) +		return ret; + +	ret = nand_scan_tail(mtd); +	if (ret) +		return ret; + +	ret = nand_register(devnum); +	if (ret) +		return ret;  	return 0;  } + +#ifndef CONFIG_SYS_NAND_BASE_LIST +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#endif + +static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = +	CONFIG_SYS_NAND_BASE_LIST; + +void board_nand_init(void) +{ +	int i; + +	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) +		fsl_ifc_chip_init(i, (u8 *)base_address[i]); +} diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c new file mode 100644 index 000000000..8537c4c6f --- /dev/null +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -0,0 +1,258 @@ +/* + * NAND boot for Freescale Integrated Flash Controller, NAND FCM + * + * Copyright 2011 Freescale Semiconductor, Inc. + * Author: Dipen Dudhat <dipen.dudhat@freescale.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/fsl_ifc.h> +#include <linux/mtd/nand.h> + +static inline int is_blank(uchar *addr, int page_size) +{ +	int i; + +	for (i = 0; i < page_size; i++) { +		if (__raw_readb(&addr[i]) != 0xff) +			return 0; +	} + +	/* +	 * For the SPL, don't worry about uncorrectable errors +	 * where the main area is all FFs but shouldn't be. +	 */ +	return 1; +} + +/* returns nonzero if entire page is blank */ +static inline int check_read_ecc(uchar *buf, u32 *eccstat, +				 unsigned int bufnum, int page_size) +{ +	u32 reg = eccstat[bufnum / 4]; +	int errors = (reg >> ((3 - bufnum % 4) * 8)) & 0xf; + +	if (errors == 0xf) { /* uncorrectable */ +		/* Blank pages fail hw ECC checks */ +		if (is_blank(buf, page_size)) +			return 1; + +		puts("ecc error\n"); +		for (;;) +			; +	} + +	return 0; +} + +static inline void nand_wait(uchar *buf, int bufnum, int page_size) +{ +	struct fsl_ifc *ifc = IFC_BASE_ADDR; +	u32 status; +	u32 eccstat[4]; +	int bufperpage = page_size / 512; +	int bufnum_end, i; + +	bufnum *= bufperpage; +	bufnum_end = bufnum + bufperpage - 1; + +	do { +		status = in_be32(&ifc->ifc_nand.nand_evter_stat); +	} while (!(status & IFC_NAND_EVTER_STAT_OPC)); + +	if (status & IFC_NAND_EVTER_STAT_FTOER) { +		puts("flash time out error\n"); +		for (;;) +			; +	} + +	for (i = bufnum / 4; i <= bufnum_end / 4; i++) +		eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]); + +	for (i = bufnum; i <= bufnum_end; i++) { +		if (check_read_ecc(buf, eccstat, i, page_size)) +			break; +	} + +	out_be32(&ifc->ifc_nand.nand_evter_stat, status); +} + +static inline int bad_block(uchar *marker, int port_size) +{ +	if (port_size == 8) +		return __raw_readb(marker) != 0xff; +	else +		return __raw_readw((u16 *)marker) != 0xffff; +} + +static void nand_load(unsigned int offs, int uboot_size, uchar *dst) +{ +	struct fsl_ifc *ifc = IFC_BASE_ADDR; +	uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; +	int page_size; +	int port_size; +	int pages_per_blk; +	int blk_size; +	int bad_marker = 0; +	int bufnum_mask, bufnum; + +	int csor, cspr; +	int pos = 0; +	int j = 0; + +	int sram_addr; +	int pg_no; + +	/* Get NAND Flash configuration */ +	csor = CONFIG_SYS_NAND_CSOR; +	cspr = CONFIG_SYS_NAND_CSPR; + +	port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8; + +	if (csor & CSOR_NAND_PGS_4K) { +		page_size = 4096; +		bufnum_mask = 0x1; +	} else if (csor & CSOR_NAND_PGS_2K) { +		page_size = 2048; +		bufnum_mask = 0x3; +	} else { +		page_size = 512; +		bufnum_mask = 0xf; + +		if (port_size == 8) +			bad_marker = 5; +	} + +	pages_per_blk = +		32 << ((csor & CSOR_NAND_PB_MASK) >> CSOR_NAND_PB_SHIFT); + +	blk_size = pages_per_blk * page_size; + +	/* Open Full SRAM mapping for spare are access */ +	out_be32(&ifc->ifc_nand.ncfgr, 0x0); + +	/* Clear Boot events */ +	out_be32(&ifc->ifc_nand.nand_evter_stat, 0xffffffff); + +	/* Program FIR/FCR for Large/Small page */ +	if (page_size > 512) { +		out_be32(&ifc->ifc_nand.nand_fir0, +			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | +			 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | +			 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | +			 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | +			 (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP4_SHIFT)); +		out_be32(&ifc->ifc_nand.nand_fir1, 0x0); + +		out_be32(&ifc->ifc_nand.nand_fcr0, +			 (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | +			 (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); +	} else { +		out_be32(&ifc->ifc_nand.nand_fir0, +			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | +			 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | +			 (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) | +			 (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP3_SHIFT)); +		out_be32(&ifc->ifc_nand.nand_fir1, 0x0); + +		out_be32(&ifc->ifc_nand.nand_fcr0, +			 NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); +	} + +	/* Program FBCR = 0 for full page read */ +	out_be32(&ifc->ifc_nand.nand_fbcr, 0); + +	/* Read and copy u-boot on SDRAM from NAND device, In parallel +	 * check for Bad block if found skip it and read continue to +	 * next Block +	 */ +	while (pos < uboot_size) { +		int i = 0; +		do { +			pg_no = offs / page_size; +			bufnum = pg_no & bufnum_mask; +			sram_addr = bufnum * page_size * 2; + +			out_be32(&ifc->ifc_nand.row0, pg_no); +			out_be32(&ifc->ifc_nand.col0, 0); +			/* start read */ +			out_be32(&ifc->ifc_nand.nandseq_strt, +				 IFC_NAND_SEQ_STRT_FIR_STRT); + +			/* wait for read to complete */ +			nand_wait(&buf[sram_addr], bufnum, page_size); + +			/* +			 * If either of the first two pages are marked bad, +			 * continue to the next block. +			 */ +			if (i++ < 2 && +			    bad_block(&buf[sram_addr + page_size + bad_marker], +				      port_size)) { +				puts("skipping\n"); +				offs = (offs + blk_size) & ~(blk_size - 1); +				pos &= ~(blk_size - 1); +				break; +			} + +			for (j = 0; j < page_size; j++) +				dst[pos + j] = __raw_readb(&buf[sram_addr + j]); + +			pos += page_size; +			offs += page_size; +		} while ((offs & (blk_size - 1)) && (pos < uboot_size)); +	} +} + +/* + * Main entrypoint for NAND Boot. It's necessary that SDRAM is already + * configured and available since this code loads the main U-boot image + * from NAND into SDRAM and starts from there. + */ +void nand_boot(void) +{ +	__attribute__((noreturn)) void (*uboot)(void); +	/* +	 * Load U-Boot image from NAND into RAM +	 */ +	nand_load(CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE, +		  (uchar *)CONFIG_SYS_NAND_U_BOOT_DST); + +#ifdef CONFIG_NAND_ENV_DST +	nand_load(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, +		  (uchar *)CONFIG_NAND_ENV_DST); + +#ifdef CONFIG_ENV_OFFSET_REDUND +	nand_load(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, +		  (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); +#endif +#endif +	/* +	 * Jump to U-Boot image +	 */ +#ifdef CONFIG_SPL_FLUSH_IMAGE +	/* +	 * Clean d-cache and invalidate i-cache, to +	 * make sure that no stale data is executed. +	 */ +	flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); +#endif +	uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; +	uboot(); +} diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 7a61d88cc..fab2aebc3 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -341,6 +341,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data + * @oob_required:	caller expects OOB data read to chip->oob_poi   * @page:	page number to read   *   * This routine is needed for fsmc verison 8 as reading from NAND chip has to be @@ -350,7 +351,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)   * max of 8 bits)   */  static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, -				 uint8_t *buf, int page) +				 uint8_t *buf, int oob_required, int page)  {  	struct fsmc_eccplace *fsmc_eccpl;  	int i, j, s, stat, eccsize = chip->ecc.size; @@ -452,6 +453,7 @@ int fsmc_nand_init(struct nand_chip *nand)  	switch (fsmc_version) {  	case FSMC_VER8:  		nand->ecc.bytes = 13; +		nand->ecc.strength = 8;  		nand->ecc.correct = fsmc_bch8_correct_data;  		nand->ecc.read_page = fsmc_read_page_hwecc;  		if (mtd->writesize == 512) @@ -466,6 +468,7 @@ int fsmc_nand_init(struct nand_chip *nand)  		break;  	default:  		nand->ecc.bytes = 3; +		nand->ecc.strength = 1;  		nand->ecc.layout = &fsmc_ecc1_layout;  		nand->ecc.correct = nand_correct_data;  		break; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 3ec34f3c9..9421e5661 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -253,9 +253,10 @@ int board_nand_init(struct nand_chip *nand)  	nand->ecc.mode		= NAND_ECC_HW_OOB_FIRST;  	nand->ecc.size		= CONFIG_SYS_NAND_ECCSIZE;  	nand->ecc.bytes		= CONFIG_SYS_NAND_ECCBYTES; +	nand->ecc.strength	= 4;  	nand->ecc.layout	= &qi_lb60_ecclayout_2gb;  	nand->chip_delay	= 50; -	nand->options		= NAND_USE_FLASH_BBT; +	nand->bbt_options	|= NAND_BBT_USE_FLASH;  	return 0;  } diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index e6b7a7066..e53f341dc 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -621,7 +621,7 @@ int board_nand_init(struct nand_chip *chip)  	chip->write_buf = mpc5121_nfc_write_buf;  	chip->verify_buf = mpc5121_nfc_verify_buf;  	chip->select_chip = mpc5121_nfc_select_chip; -	chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; +	chip->bbt_options = NAND_BBT_USE_FLASH;  	chip->ecc.mode = NAND_ECC_SOFT;  	/* Reset NAND Flash controller */ diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index eeba52194..ac435f205 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -396,7 +396,7 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)  #if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)  static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,  				      struct nand_chip *chip, -				      int page, int sndcmd) +				      int page)  {  	struct mxc_nand_host *host = chip->priv;  	uint8_t *buf = chip->oob_poi; @@ -450,6 +450,7 @@ static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,  static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,  					   struct nand_chip *chip,  					   uint8_t *buf, +					   int oob_required,  					   int page)  {  	struct mxc_nand_host *host = chip->priv; @@ -494,6 +495,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,  static int mxc_nand_read_page_syndrome(struct mtd_info *mtd,  				       struct nand_chip *chip,  				       uint8_t *buf, +				       int oob_required,  				       int page)  {  	struct mxc_nand_host *host = chip->priv; @@ -583,9 +585,10 @@ static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd,  	return status & NAND_STATUS_FAIL ? -EIO : 0;  } -static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, +static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,  					     struct nand_chip *chip, -					     const uint8_t *buf) +					     const uint8_t *buf, +					     int oob_required)  {  	struct mxc_nand_host *host = chip->priv;  	int eccsize = chip->ecc.size; @@ -619,11 +622,13 @@ static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,  	size = mtd->oobsize - (oob - chip->oob_poi);  	if (size)  		chip->write_buf(mtd, oob, size); +	return 0;  } -static void mxc_nand_write_page_syndrome(struct mtd_info *mtd, +static int mxc_nand_write_page_syndrome(struct mtd_info *mtd,  					 struct nand_chip *chip, -					 const uint8_t *buf) +					 const uint8_t *buf, +					 int oob_required)  {  	struct mxc_nand_host *host = chip->priv;  	int i, n, eccsize = chip->ecc.size; @@ -662,6 +667,7 @@ static void mxc_nand_write_page_syndrome(struct mtd_info *mtd,  	i = mtd->oobsize - (oob - chip->oob_poi);  	if (i)  		chip->write_buf(mtd, oob, i); +	return 0;  }  static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, @@ -1188,7 +1194,7 @@ int board_nand_init(struct nand_chip *this)  #endif  #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT -	this->options |= NAND_USE_FLASH_BBT; +	this->bbt_options |= NAND_BBT_USE_FLASH;  	this->bbt_td = &bbt_main_descr;  	this->bbt_md = &bbt_mirror_descr;  #endif @@ -1236,6 +1242,13 @@ int board_nand_init(struct nand_chip *this)  		this->ecc.mode = NAND_ECC_HW;  	} +	if (this->ecc.mode == NAND_ECC_HW) { +		if (is_mxc_nfc_1()) +			this->ecc.strength = 1; +		else +			this->ecc.strength = 4; +	} +  	host->pagesize_2k = 0;  	this->ecc.size = 512; diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index 398e4ddc1..866cabd27 100644 --- a/drivers/mtd/nand/mxs_nand.c +++ b/drivers/mtd/nand/mxs_nand.c @@ -553,7 +553,8 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)   * Read a page from NAND.   */  static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand, -					uint8_t *buf, int page) +					uint8_t *buf, int oob_required, +					int page)  {  	struct mxs_nand_info *nand_info = nand->priv;  	struct mxs_dma_desc *d; @@ -698,8 +699,9 @@ rtn:  /*   * Write a page to NAND.   */ -static void mxs_nand_ecc_write_page(struct mtd_info *mtd, -				struct nand_chip *nand, const uint8_t *buf) +static int mxs_nand_ecc_write_page(struct mtd_info *mtd, +				struct nand_chip *nand, const uint8_t *buf, +				int oob_required)  {  	struct mxs_nand_info *nand_info = nand->priv;  	struct mxs_dma_desc *d; @@ -755,6 +757,7 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd,  rtn:  	mxs_nand_return_dma_descs(nand_info); +	return 0;  }  /* @@ -770,7 +773,7 @@ static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from,  	struct mxs_nand_info *nand_info = chip->priv;  	int ret; -	if (ops->mode == MTD_OOB_RAW) +	if (ops->mode == MTD_OPS_RAW)  		nand_info->raw_oob_mode = 1;  	else  		nand_info->raw_oob_mode = 0; @@ -795,7 +798,7 @@ static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to,  	struct mxs_nand_info *nand_info = chip->priv;  	int ret; -	if (ops->mode == MTD_OOB_RAW) +	if (ops->mode == MTD_OPS_RAW)  		nand_info->raw_oob_mode = 1;  	else  		nand_info->raw_oob_mode = 0; @@ -873,7 +876,7 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)   * what to do.   */  static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand, -				int page, int cmd) +				int page)  {  	struct mxs_nand_info *nand_info = nand->priv; @@ -1006,19 +1009,19 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)  	writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set);  	/* Hook some operations at the MTD level. */ -	if (mtd->read_oob != mxs_nand_hook_read_oob) { -		nand_info->hooked_read_oob = mtd->read_oob; -		mtd->read_oob = mxs_nand_hook_read_oob; +	if (mtd->_read_oob != mxs_nand_hook_read_oob) { +		nand_info->hooked_read_oob = mtd->_read_oob; +		mtd->_read_oob = mxs_nand_hook_read_oob;  	} -	if (mtd->write_oob != mxs_nand_hook_write_oob) { -		nand_info->hooked_write_oob = mtd->write_oob; -		mtd->write_oob = mxs_nand_hook_write_oob; +	if (mtd->_write_oob != mxs_nand_hook_write_oob) { +		nand_info->hooked_write_oob = mtd->_write_oob; +		mtd->_write_oob = mxs_nand_hook_write_oob;  	} -	if (mtd->block_markbad != mxs_nand_hook_block_markbad) { -		nand_info->hooked_block_markbad = mtd->block_markbad; -		mtd->block_markbad = mxs_nand_hook_block_markbad; +	if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { +		nand_info->hooked_block_markbad = mtd->_block_markbad; +		mtd->_block_markbad = mxs_nand_hook_block_markbad;  	}  	/* We use the reference implementation for bad block management. */ @@ -1172,6 +1175,7 @@ int board_nand_init(struct nand_chip *nand)  	nand->ecc.mode		= NAND_ECC_HW;  	nand->ecc.bytes		= 9;  	nand->ecc.size		= 512; +	nand->ecc.strength	= 8;  	return 0; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a2d06be99..9e05cef41 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -21,7 +21,7 @@   *  TODO:   *	Enable cached programming for 2k page size chips   *	Check, if mtd->ecctype should be set to MTD_ECC_HW - *	if we have HW ecc support. + *	if we have HW ECC support.   *	The AG-AND chips have nice features for speed improvement,   *	which are not supported yet. Read / program 4 pages in one go.   *	BBT table is not serialized, has to be fixed @@ -134,21 +134,14 @@ static int check_offs_len(struct mtd_info *mtd,  		ret = -EINVAL;  	} -	/* Do not allow past end of device */ -	if (ofs + len > mtd->size) { -		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n", -					__func__); -		ret = -EINVAL; -	} -  	return ret;  }  /**   * nand_release_device - [GENERIC] release chip - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Deselect, release chip lock and wake up anyone waiting on the device + * Deselect, release chip lock and wake up anyone waiting on the device.   */  static void nand_release_device(struct mtd_info *mtd)  { @@ -160,9 +153,9 @@ static void nand_release_device(struct mtd_info *mtd)  /**   * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth.   */  uint8_t nand_read_byte(struct mtd_info *mtd)  { @@ -172,10 +165,11 @@ uint8_t nand_read_byte(struct mtd_info *mtd)  /**   * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * @mtd:	MTD device structure + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @mtd: MTD device structure + * + * Default read function for 16bit buswidth with endianness conversion.   * - * Default read function for 16bit buswith with - * endianess conversion   */  static uint8_t nand_read_byte16(struct mtd_info *mtd)  { @@ -185,10 +179,9 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)  /**   * nand_read_word - [DEFAULT] read one word from the chip - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Default read function for 16bit buswith without - * endianess conversion + * Default read function for 16bit buswidth without endianness conversion.   */  static u16 nand_read_word(struct mtd_info *mtd)  { @@ -198,8 +191,8 @@ static u16 nand_read_word(struct mtd_info *mtd)  /**   * nand_select_chip - [DEFAULT] control CE line - * @mtd:	MTD device structure - * @chipnr:	chipnumber to select, -1 for deselect + * @mtd: MTD device structure + * @chipnr: chipnumber to select, -1 for deselect   *   * Default select function for 1 chip devices.   */ @@ -221,11 +214,11 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)  /**   * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd:	MTD device structure - * @buf:	data buffer - * @len:	number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write   * - * Default write function for 8bit buswith + * Default write function for 8bit buswidth.   */  void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -238,11 +231,11 @@ void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd:	MTD device structure - * @buf:	buffer to store date - * @len:	number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read   * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth.   */  void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  { @@ -255,11 +248,11 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  /**   * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd:	MTD device structure - * @buf:	buffer containing the data to compare - * @len:	number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare   * - * Default verify function for 8bit buswith + * Default verify function for 8bit buswidth.   */  static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -274,11 +267,11 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd:	MTD device structure - * @buf:	data buffer - * @len:	number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write   * - * Default write function for 16bit buswith + * Default write function for 16bit buswidth.   */  void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -294,11 +287,11 @@ void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd:	MTD device structure - * @buf:	buffer to store date - * @len:	number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read   * - * Default read function for 16bit buswith + * Default read function for 16bit buswidth.   */  void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)  { @@ -313,11 +306,11 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)  /**   * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd:	MTD device structure - * @buf:	buffer containing the data to compare - * @len:	number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare   * - * Default verify function for 16bit buswith + * Default verify function for 16bit buswidth.   */  static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -335,19 +328,19 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd:	MTD device structure - * @ofs:	offset from device start - * @getchip:	0, if the chip is already selected + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected   *   * Check, if the block is bad.   */  static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  { -	int page, chipnr, res = 0; +	int page, chipnr, res = 0, i = 0;  	struct nand_chip *chip = mtd->priv;  	u16 bad; -	if (chip->options & NAND_BBT_SCANLASTPAGE) +	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)  		ofs += mtd->erasesize - mtd->writesize;  	page = (int)(ofs >> chip->page_shift) & chip->pagemask; @@ -361,23 +354,29 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  		chip->select_chip(mtd, chipnr);  	} -	if (chip->options & NAND_BUSWIDTH_16) { -		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, -			      page); -		bad = cpu_to_le16(chip->read_word(mtd)); -		if (chip->badblockpos & 0x1) -			bad >>= 8; -		else -			bad &= 0xFF; -	} else { -		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); -		bad = chip->read_byte(mtd); -	} +	do { +		if (chip->options & NAND_BUSWIDTH_16) { +			chip->cmdfunc(mtd, NAND_CMD_READOOB, +					chip->badblockpos & 0xFE, page); +			bad = cpu_to_le16(chip->read_word(mtd)); +			if (chip->badblockpos & 0x1) +				bad >>= 8; +			else +				bad &= 0xFF; +		} else { +			chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, +					page); +			bad = chip->read_byte(mtd); +		} -	if (likely(chip->badblockbits == 8)) -		res = bad != 0xFF; -	else -		res = hweight8(bad) < chip->badblockbits; +		if (likely(chip->badblockbits == 8)) +			res = bad != 0xFF; +		else +			res = hweight8(bad) < chip->badblockbits; +		ofs += mtd->writesize; +		page = (int)(ofs >> chip->page_shift) & chip->pagemask; +		i++; +	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));  	if (getchip)  		nand_release_device(mtd); @@ -387,57 +386,83 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  /**   * nand_default_block_markbad - [DEFAULT] mark a block bad - * @mtd:	MTD device structure - * @ofs:	offset from device start + * @mtd: MTD device structure + * @ofs: offset from device start   * - * This is the default implementation, which can be overridden by - * a hardware specific driver. + * This is the default implementation, which can be overridden by a hardware + * specific driver. We try operations in the following order, according to our + * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): + *  (1) erase the affected block, to allow OOB marker to be written cleanly + *  (2) update in-memory BBT + *  (3) write bad block marker to OOB area of affected block + *  (4) update flash-based BBT + * Note that we retain the first error encountered in (3) or (4), finish the + * procedures, and dump the error in the end.  */  static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  {  	struct nand_chip *chip = mtd->priv;  	uint8_t buf[2] = { 0, 0 }; -	int block, ret, i = 0; +	int block, res, ret = 0, i = 0; +	int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); -	if (chip->options & NAND_BBT_SCANLASTPAGE) -		ofs += mtd->erasesize - mtd->writesize; +	if (write_oob) { +		struct erase_info einfo; + +		/* Attempt erase before marking OOB */ +		memset(&einfo, 0, sizeof(einfo)); +		einfo.mtd = mtd; +		einfo.addr = ofs; +		einfo.len = 1 << chip->phys_erase_shift; +		nand_erase_nand(mtd, &einfo, 0); +	}  	/* Get block number */  	block = (int)(ofs >> chip->bbt_erase_shift); +	/* Mark block bad in memory-based BBT */  	if (chip->bbt)  		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); -	/* Do we have a flash based bad block table ? */ -	if (chip->options & NAND_USE_FLASH_BBT) -		ret = nand_update_bbt(mtd, ofs); -	else { +	/* Write bad block marker to OOB */ +	if (write_oob) { +		struct mtd_oob_ops ops; +		loff_t wr_ofs = ofs; +  		nand_get_device(chip, mtd, FL_WRITING); -		/* Write to first two pages and to byte 1 and 6 if necessary. -		 * If we write to more than one location, the first error -		 * encountered quits the procedure. We write two bytes per -		 * location, so we dont have to mess with 16 bit access. -		 */ -		do { -			chip->ops.len = chip->ops.ooblen = 2; -			chip->ops.datbuf = NULL; -			chip->ops.oobbuf = buf; -			chip->ops.ooboffs = chip->badblockpos & ~0x01; +		ops.datbuf = NULL; +		ops.oobbuf = buf; +		ops.ooboffs = chip->badblockpos; +		if (chip->options & NAND_BUSWIDTH_16) { +			ops.ooboffs &= ~0x01; +			ops.len = ops.ooblen = 2; +		} else { +			ops.len = ops.ooblen = 1; +		} +		ops.mode = MTD_OPS_PLACE_OOB; -			ret = nand_do_write_oob(mtd, ofs, &chip->ops); +		/* Write to first/last page(s) if necessary */ +		if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) +			wr_ofs += mtd->erasesize - mtd->writesize; +		do { +			res = nand_do_write_oob(mtd, wr_ofs, &ops); +			if (!ret) +				ret = res; -			if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) { -				chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS -					& ~0x01; -				ret = nand_do_write_oob(mtd, ofs, &chip->ops); -			}  			i++; -			ofs += mtd->writesize; -		} while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && -				i < 2); +			wr_ofs += mtd->writesize; +		} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);  		nand_release_device(mtd);  	} + +	/* Update flash-based bad block table */ +	if (chip->bbt_options & NAND_BBT_USE_FLASH) { +		res = nand_update_bbt(mtd, ofs); +		if (!ret) +			ret = res; +	} +  	if (!ret)  		mtd->ecc_stats.badblocks++; @@ -446,16 +471,16 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  /**   * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd:	MTD device structure - * Check, if the device is write protected + * @mtd: MTD device structure   * - * The function expects, that the device is already selected + * Check, if the device is write protected. The function expects, that the + * device is already selected.   */  static int nand_check_wp(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; -	/* broken xD cards report WP despite being writable */ +	/* Broken xD cards report WP despite being writable */  	if (chip->options & NAND_BROKEN_XD)  		return 0; @@ -466,10 +491,10 @@ static int nand_check_wp(struct mtd_info *mtd)  /**   * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd:	MTD device structure - * @ofs:	offset from device start - * @getchip:	0, if the chip is already selected - * @allowbbt:	1, if its allowed to access the bbt area + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected + * @allowbbt: 1, if its allowed to access the bbt area   *   * Check, if the block is bad. Either by reading the bad block table or   * calling of the scan function. @@ -491,10 +516,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,  	return nand_isbad_bbt(mtd, ofs, allowbbt);  } -/* - * Wait for the ready pin, after a command - * The timeout is catched later. - */ +/* Wait for the ready pin, after a command. The timeout is caught later. */  void nand_wait_ready(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; @@ -503,7 +525,7 @@ void nand_wait_ready(struct mtd_info *mtd)  	time_start = get_timer(0); -	/* wait until command is processed or timeout occures */ +	/* Wait until command is processed or timeout occurs */  	while (get_timer(time_start) < timeo) {  		if (chip->dev_ready)  			if (chip->dev_ready(mtd)) @@ -513,13 +535,13 @@ void nand_wait_ready(struct mtd_info *mtd)  /**   * nand_command - [DEFAULT] Send command to NAND device - * @mtd:	MTD device structure - * @command:	the command to be sent - * @column:	the column address for this command, -1 if none - * @page_addr:	the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none   * - * Send command to NAND device. This function is used for small page - * devices (256/512 Bytes per page) + * Send command to NAND device. This function is used for small page devices + * (256/512 Bytes per page).   */  static void nand_command(struct mtd_info *mtd, unsigned int command,  			 int column, int page_addr) @@ -528,9 +550,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;  	uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT; -	/* -	 * Write out the command to the device. -	 */ +	/* Write out the command to the device */  	if (command == NAND_CMD_SEQIN) {  		int readcmd; @@ -550,9 +570,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  	}  	chip->cmd_ctrl(mtd, command, ctrl); -	/* -	 * Address cycle, when necessary -	 */ +	/* Address cycle, when necessary */  	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;  	/* Serially input address */  	if (column != -1) { @@ -573,8 +591,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  	/* -	 * program and erase have their own busy handlers -	 * status and sequential in needs no delay +	 * Program and erase have their own busy handlers status and sequential +	 * in needs no delay  	 */  	switch (command) { @@ -608,8 +626,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  			return;  		}  	} -	/* Apply this short delay always to ensure that we do wait tWB in -	 * any case on any machine. */ +	/* +	 * Apply this short delay always to ensure that we do wait tWB in +	 * any case on any machine. +	 */  	ndelay(100);  	nand_wait_ready(mtd); @@ -617,14 +637,14 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  /**   * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd:	MTD device structure - * @command:	the command to be sent - * @column:	the column address for this command, -1 if none - * @page_addr:	the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none   *   * Send command to NAND device. This is the version for the new large page - * devices We dont have the separate regions as we have in the small page - * devices.  We must emulate NAND_CMD_READOOB to keep the code compatible. + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.   */  static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  			    int column, int page_addr) @@ -667,8 +687,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  	/* -	 * program and erase have their own busy handlers -	 * status, sequential in, and deplete1 need no delay +	 * Program and erase have their own busy handlers status, sequential +	 * in, and deplete1 need no delay.  	 */  	switch (command) { @@ -682,14 +702,12 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  	case NAND_CMD_DEPLETE1:  		return; -		/* -		 * read error status commands require only a short delay -		 */  	case NAND_CMD_STATUS_ERROR:  	case NAND_CMD_STATUS_ERROR0:  	case NAND_CMD_STATUS_ERROR1:  	case NAND_CMD_STATUS_ERROR2:  	case NAND_CMD_STATUS_ERROR3: +		/* Read error status commands require only a short delay */  		udelay(chip->chip_delay);  		return; @@ -723,7 +741,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  	default:  		/*  		 * If we don't have access to the busy pin, we apply the given -		 * command delay +		 * command delay.  		 */  		if (!chip->dev_ready) {  			udelay(chip->chip_delay); @@ -731,8 +749,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  		}  	} -	/* Apply this short delay always to ensure that we do wait tWB in -	 * any case on any machine. */ +	/* +	 * Apply this short delay always to ensure that we do wait tWB in +	 * any case on any machine. +	 */  	ndelay(100);  	nand_wait_ready(mtd); @@ -740,9 +760,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  /**   * nand_get_device - [GENERIC] Get chip for selected access - * @chip:	the nand chip descriptor - * @mtd:	MTD device structure - * @new_state:	the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested   *   * Get the device and lock it for exclusive access   */ @@ -754,13 +774,13 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)  }  /** - * nand_wait - [DEFAULT]  wait until the command is done - * @mtd:	MTD device structure - * @chip:	NAND chip structure + * nand_wait - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure   * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs + * Wait for command done. This applies to erase and program only. Erase can + * take up to 400ms and program up to 20ms according to general NAND and + * SmartMedia specs.   */  static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)  { @@ -804,34 +824,37 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)  }  /** - * nand_read_page_raw - [Intern] read raw page data without ecc - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_raw - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read   * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout.   */  static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, -			      uint8_t *buf, int page) +			      uint8_t *buf, int oob_required, int page)  {  	chip->read_buf(mtd, buf, mtd->writesize); -	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); +	if (oob_required) +		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);  	return 0;  }  /** - * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read   *   * We need a special oob layout and handling even when OOB isn't used.   */  static int nand_read_page_raw_syndrome(struct mtd_info *mtd, -					struct nand_chip *chip, -					uint8_t *buf, int page) +				       struct nand_chip *chip, uint8_t *buf, +				       int oob_required, int page)  {  	int eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -864,14 +887,15 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,  }  /** - * nand_read_page_swecc - [REPLACABLE] software ecc based page read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read   */  static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, -				uint8_t *buf, int page) +				uint8_t *buf, int oob_required, int page)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -881,7 +905,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  	uint8_t *ecc_code = chip->buffers->ecccode;  	uint32_t *eccpos = chip->ecc.layout->eccpos; -	chip->ecc.read_page_raw(mtd, chip, buf, page); +	chip->ecc.read_page_raw(mtd, chip, buf, 1, page);  	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)  		chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -905,12 +929,12 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @data_offs:	offset of requested data within the page - * @readlen:	data length - * @bufpoi:	buffer to store read data + * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @data_offs: offset of requested data within the page + * @readlen: data length + * @bufpoi: buffer to store read data   */  static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) @@ -923,12 +947,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;  	int index = 0; -	/* Column address wihin the page aligned to ECC size (256bytes). */ +	/* Column address within the page aligned to ECC size (256bytes) */  	start_step = data_offs / chip->ecc.size;  	end_step = (data_offs + readlen - 1) / chip->ecc.size;  	num_steps = end_step - start_step + 1; -	/* Data size aligned to ECC ecc.size*/ +	/* Data size aligned to ECC ecc.size */  	datafrag_len = num_steps * chip->ecc.size;  	eccfrag_len = num_steps * chip->ecc.bytes; @@ -940,13 +964,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  	p = bufpoi + data_col_addr;  	chip->read_buf(mtd, p, datafrag_len); -	/* Calculate  ECC */ +	/* Calculate ECC */  	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)  		chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); -	/* The performance is faster if to position offsets -	   according to ecc.pos. Let make sure here that -	   there are no gaps in ecc positions */ +	/* +	 * The performance is faster if we position offsets according to +	 * ecc.pos. Let's make sure that there are no gaps in ECC positions. +	 */  	for (i = 0; i < eccfrag_len - 1; i++) {  		if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=  			eccpos[i + start_step * chip->ecc.bytes + 1]) { @@ -958,8 +983,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);  		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);  	} else { -		/* send the command to read the particular ecc bytes */ -		/* take care about buswidth alignment in read_buf */ +		/* +		 * Send the command to read the particular ECC bytes take care +		 * about buswidth alignment in read_buf. +		 */  		index = start_step * chip->ecc.bytes;  		aligned_pos = eccpos[index] & ~(busw - 1); @@ -992,16 +1019,17 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read   * - * Not for syndrome calculating ecc controllers which need a special oob layout + * Not for syndrome calculating ECC controllers which need a special oob layout.   */  static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, -				uint8_t *buf, int page) +				uint8_t *buf, int oob_required, int page)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1037,21 +1065,21 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read   * - * Hardware ECC for large page chips, require OOB to be read first. - * For this ECC mode, the write_page method is re-used from ECC_HW. - * These methods read/write ECC from the OOB area, unlike the - * ECC_HW_SYNDROME support with multiple ECC steps, follows the - * "infix ECC" scheme and reads/writes ECC from the data area, by - * overwriting the NAND manufacturer bad block markings. + * Hardware ECC for large page chips, require OOB to be read first. For this + * ECC mode, the write_page method is re-used from ECC_HW. These methods + * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with + * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from + * the data area, by overwriting the NAND manufacturer bad block markings.   */  static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, -	struct nand_chip *chip, uint8_t *buf, int page) +	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1086,17 +1114,18 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,  }  /** - * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read   * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling.   */  static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, -				   uint8_t *buf, int page) +				   uint8_t *buf, int oob_required, int page)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1141,29 +1170,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_transfer_oob - [Internal] Transfer oob to client buffer - * @chip:	nand chip structure - * @oob:	oob destination address - * @ops:	oob ops structure - * @len:	size of oob to transfer + * nand_transfer_oob - [INTERN] Transfer oob to client buffer + * @chip: nand chip structure + * @oob: oob destination address + * @ops: oob ops structure + * @len: size of oob to transfer   */  static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,  				  struct mtd_oob_ops *ops, size_t len)  {  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_RAW:  		memcpy(oob, chip->oob_poi + ops->ooboffs, len);  		return oob + len; -	case MTD_OOB_AUTO: { +	case MTD_OPS_AUTO_OOB: {  		struct nand_oobfree *free = chip->ecc.layout->oobfree;  		uint32_t boffs = 0, roffs = ops->ooboffs;  		size_t bytes = 0;  		for (; free->length && len; free++, len -= bytes) { -			/* Read request not from offset 0 ? */ +			/* Read request not from offset 0? */  			if (unlikely(roffs)) {  				if (roffs >= free->length) {  					roffs -= free->length; @@ -1189,26 +1218,23 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,  }  /** - * nand_do_read_ops - [Internal] Read data with ECC - * - * @mtd:	MTD device structure - * @from:	offset to read from - * @ops:	oob ops structure + * nand_do_read_ops - [INTERN] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure   *   * Internal function. Called with chip held.   */  static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			    struct mtd_oob_ops *ops)  { -	int chipnr, page, realpage, col, bytes, aligned; +	int chipnr, page, realpage, col, bytes, aligned, oob_required;  	struct nand_chip *chip = mtd->priv;  	struct mtd_ecc_stats stats; -	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; -	int sndcmd = 1;  	int ret = 0;  	uint32_t readlen = ops->len;  	uint32_t oobreadlen = ops->ooblen; -	uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ? +	uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?  		mtd->oobavail : mtd->oobsize;  	uint8_t *bufpoi, *oob, *buf; @@ -1225,6 +1251,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  	buf = ops->datbuf;  	oob = ops->oobbuf; +	oob_required = oob ? 1 : 0;  	while (1) {  		WATCHDOG_RESET(); @@ -1232,41 +1259,46 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		bytes = min(mtd->writesize - col, readlen);  		aligned = (bytes == mtd->writesize); -		/* Is the current page in the buffer ? */ +		/* Is the current page in the buffer? */  		if (realpage != chip->pagebuf || oob) {  			bufpoi = aligned ? buf : chip->buffers->databuf; -			if (likely(sndcmd)) { -				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); -				sndcmd = 0; -			} +			chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);  			/* Now read the page into the buffer */ -			if (unlikely(ops->mode == MTD_OOB_RAW)) -				ret = chip->ecc.read_page_raw(mtd, chip, -							      bufpoi, page); +			if (unlikely(ops->mode == MTD_OPS_RAW)) +				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, +							      oob_required, +							      page);  			else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&  			    !oob)  				ret = chip->ecc.read_subpage(mtd, chip,  							col, bytes, bufpoi);  			else  				ret = chip->ecc.read_page(mtd, chip, bufpoi, -							  page); -			if (ret < 0) +							  oob_required, page); +			if (ret < 0) { +				if (!aligned) +					/* Invalidate page cache */ +					chip->pagebuf = -1;  				break; +			}  			/* Transfer not aligned data */  			if (!aligned) {  				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && -				    !(mtd->ecc_stats.failed - stats.failed)) +				    !(mtd->ecc_stats.failed - stats.failed) && +				    (ops->mode != MTD_OPS_RAW))  					chip->pagebuf = realpage; +				else +					/* Invalidate page cache */ +					chip->pagebuf = -1;  				memcpy(buf, chip->buffers->databuf + col, bytes);  			}  			buf += bytes;  			if (unlikely(oob)) { -  				int toread = min(oobreadlen, max_oobsize);  				if (toread) { @@ -1275,20 +1307,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  					oobreadlen -= toread;  				}  			} - -			if (!(chip->options & NAND_NO_READRDY)) { -				/* -				 * Apply delay or wait for ready/busy pin. Do -				 * this before the AUTOINCR check, so no -				 * problems arise if a chip which does auto -				 * increment is marked as NOAUTOINCR by the -				 * board driver. -				 */ -				if (!chip->dev_ready) -					udelay(chip->chip_delay); -				else -					nand_wait_ready(mtd); -			}  		} else {  			memcpy(buf, chip->buffers->databuf + col, bytes);  			buf += bytes; @@ -1299,7 +1317,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		if (!readlen)  			break; -		/* For subsequent reads align to page boundary. */ +		/* For subsequent reads align to page boundary */  		col = 0;  		/* Increment page address */  		realpage++; @@ -1311,12 +1329,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			chip->select_chip(mtd, -1);  			chip->select_chip(mtd, chipnr);  		} - -		/* Check, if the chip supports auto page increment -		 * or if we have hit a block boundary. -		 */ -		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) -			sndcmd = 1;  	}  	ops->retlen = ops->len - (size_t) readlen; @@ -1334,69 +1346,55 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  /**   * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd:	MTD device structure - * @from:	offset to read from - * @len:	number of bytes to read - * @retlen:	pointer to variable to store the number of read bytes - * @buf:	the databuffer to put data + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data   * - * Get hold of the chip and call nand_do_read + * Get hold of the chip and call nand_do_read.   */  static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,  		     size_t *retlen, uint8_t *buf)  {  	struct nand_chip *chip = mtd->priv; +	struct mtd_oob_ops ops;  	int ret; -	/* Do not allow reads past end of device */ -	if ((from + len) > mtd->size) -		return -EINVAL; -	if (!len) -		return 0; -  	nand_get_device(chip, mtd, FL_READING); - -	chip->ops.len = len; -	chip->ops.datbuf = buf; -	chip->ops.oobbuf = NULL; - -	ret = nand_do_read_ops(mtd, from, &chip->ops); - -	*retlen = chip->ops.retlen; - +	ops.len = len; +	ops.datbuf = buf; +	ops.oobbuf = NULL; +	ops.mode = MTD_OPS_PLACE_OOB; +	ret = nand_do_read_ops(mtd, from, &ops); +	*retlen = ops.retlen;  	nand_release_device(mtd); -  	return ret;  }  /** - * nand_read_oob_std - [REPLACABLE] the most common OOB data read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to read - * @sndcmd:	flag whether to issue read command or not + * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read   */  static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, -			     int page, int sndcmd) +			     int page)  { -	if (sndcmd) { -		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -		sndcmd = 0; -	} +	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);  	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -	return sndcmd; +	return 0;  }  /** - * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC + * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC   *			    with syndromes - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to read - * @sndcmd:	flag whether to issue read command or not + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read   */  static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, -				  int page, int sndcmd) +				  int page)  {  	uint8_t *buf = chip->oob_poi;  	int length = mtd->oobsize; @@ -1423,14 +1421,14 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  	if (length > 0)  		chip->read_buf(mtd, bufpoi, length); -	return 1; +	return 0;  }  /** - * nand_write_oob_std - [REPLACABLE] the most common OOB data write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to write + * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write   */  static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,  			      int page) @@ -1450,11 +1448,11 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC - *			     with syndrome - only for large page flash ! - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to write + * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC + *			     with syndrome - only for large page flash + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write   */  static int nand_write_oob_syndrome(struct mtd_info *mtd,  				   struct nand_chip *chip, int page) @@ -1509,27 +1507,30 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,  }  /** - * nand_do_read_oob - [Intern] NAND read out-of-band - * @mtd:	MTD device structure - * @from:	offset to read from - * @ops:	oob operations description structure + * nand_do_read_oob - [INTERN] NAND read out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure   * - * NAND read out-of-band data from the spare area + * NAND read out-of-band data from the spare area.   */  static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  			    struct mtd_oob_ops *ops)  { -	int page, realpage, chipnr, sndcmd = 1; +	int page, realpage, chipnr;  	struct nand_chip *chip = mtd->priv; -	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; +	struct mtd_ecc_stats stats;  	int readlen = ops->ooblen;  	int len;  	uint8_t *buf = ops->oobbuf; +	int ret = 0;  	MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n",  			__func__, (unsigned long long)from, readlen); -	if (ops->mode == MTD_OOB_AUTO) +	stats = mtd->ecc_stats; + +	if (ops->mode == MTD_OPS_AUTO_OOB)  		len = chip->ecc.layout->oobavail;  	else  		len = mtd->oobsize; @@ -1558,24 +1559,17 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  	while (1) {  		WATCHDOG_RESET(); -		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); +		if (ops->mode == MTD_OPS_RAW) +			ret = chip->ecc.read_oob_raw(mtd, chip, page); +		else +			ret = chip->ecc.read_oob(mtd, chip, page); + +		if (ret < 0) +			break;  		len = min(len, readlen);  		buf = nand_transfer_oob(chip, buf, ops, len); -		if (!(chip->options & NAND_NO_READRDY)) { -			/* -			 * Apply delay or wait for ready/busy pin. Do this -			 * before the AUTOINCR check, so no problems arise if a -			 * chip which does auto increment is marked as -			 * NOAUTOINCR by the board driver. -			 */ -			if (!chip->dev_ready) -				udelay(chip->chip_delay); -			else -				nand_wait_ready(mtd); -		} -  		readlen -= len;  		if (!readlen)  			break; @@ -1590,25 +1584,26 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  			chip->select_chip(mtd, -1);  			chip->select_chip(mtd, chipnr);  		} - -		/* Check, if the chip supports auto page increment -		 * or if we have hit a block boundary. -		 */ -		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) -			sndcmd = 1;  	} -	ops->oobretlen = ops->ooblen; -	return 0; +	ops->oobretlen = ops->ooblen - readlen; + +	if (ret < 0) +		return ret; + +	if (mtd->ecc_stats.failed - stats.failed) +		return -EBADMSG; + +	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;  }  /**   * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd:	MTD device structure - * @from:	offset to read from - * @ops:	oob operation description structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure   * - * NAND read data and/or out-of-band data + * NAND read data and/or out-of-band data.   */  static int nand_read_oob(struct mtd_info *mtd, loff_t from,  			 struct mtd_oob_ops *ops) @@ -1628,9 +1623,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,  	nand_get_device(chip, mtd, FL_READING);  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB: +	case MTD_OPS_RAW:  		break;  	default: @@ -1649,31 +1644,36 @@ out:  /** - * nand_write_page_raw - [Intern] raw page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_raw - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB   * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout.   */ -static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, -				const uint8_t *buf) +static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, +				const uint8_t *buf, int oob_required)  {  	chip->write_buf(mtd, buf, mtd->writesize); -	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +	if (oob_required) +		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + +	return 0;  }  /** - * nand_write_page_raw_syndrome - [Intern] raw page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_raw_syndrome - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB   *   * We need a special oob layout and handling even when ECC isn't checked.   */ -static void nand_write_page_raw_syndrome(struct mtd_info *mtd, +static int nand_write_page_raw_syndrome(struct mtd_info *mtd,  					struct nand_chip *chip, -					const uint8_t *buf) +					const uint8_t *buf, int oob_required)  {  	int eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1701,15 +1701,18 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,  	size = mtd->oobsize - (oob - chip->oob_poi);  	if (size)  		chip->write_buf(mtd, oob, size); + +	return 0;  }  /** - * nand_write_page_swecc - [REPLACABLE] software ecc based page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB   */ -static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, -				  const uint8_t *buf) +static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, +				  const uint8_t *buf, int oob_required)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1718,24 +1721,25 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  	const uint8_t *p = buf;  	uint32_t *eccpos = chip->ecc.layout->eccpos; -	/* Software ecc calculation */ +	/* Software ECC calculation */  	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)  		chip->ecc.calculate(mtd, p, &ecc_calc[i]);  	for (i = 0; i < chip->ecc.total; i++)  		chip->oob_poi[eccpos[i]] = ecc_calc[i]; -	chip->ecc.write_page_raw(mtd, chip, buf); +	return chip->ecc.write_page_raw(mtd, chip, buf, 1);  }  /** - * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB   */ -static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, -				  const uint8_t *buf) +static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, +				  const uint8_t *buf, int oob_required)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1754,19 +1758,23 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  		chip->oob_poi[eccpos[i]] = ecc_calc[i];  	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + +	return 0;  }  /** - * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB   * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling.   */ -static void nand_write_page_syndrome(struct mtd_info *mtd, -				    struct nand_chip *chip, const uint8_t *buf) +static int nand_write_page_syndrome(struct mtd_info *mtd, +				    struct nand_chip *chip, +				    const uint8_t *buf, int oob_required)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1798,32 +1806,39 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,  	i = mtd->oobsize - (oob - chip->oob_poi);  	if (i)  		chip->write_buf(mtd, oob, i); + +	return 0;  }  /**   * nand_write_page - [REPLACEABLE] write one page - * @mtd:	MTD device structure - * @chip:	NAND chip descriptor - * @buf:	the data to write - * @page:	page number to write - * @cached:	cached programming - * @raw:	use _raw version of write_page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * @cached: cached programming + * @raw: use _raw version of write_page   */  static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, -			   const uint8_t *buf, int page, int cached, int raw) +			   const uint8_t *buf, int oob_required, int page, +			   int cached, int raw)  {  	int status;  	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);  	if (unlikely(raw)) -		chip->ecc.write_page_raw(mtd, chip, buf); +		status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);  	else -		chip->ecc.write_page(mtd, chip, buf); +		status = chip->ecc.write_page(mtd, chip, buf, oob_required); + +	if (status < 0) +		return status;  	/* -	 * Cached progamming disabled for now, Not sure if its worth the -	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) +	 * Cached progamming disabled for now. Not sure if it's worth the +	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).  	 */  	cached = 0; @@ -1833,7 +1848,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  		status = chip->waitfunc(mtd, chip);  		/*  		 * See if operation failed and additional status checks are -		 * available +		 * available.  		 */  		if ((status & NAND_STATUS_FAIL) && (chip->errstat))  			status = chip->errstat(mtd, chip, FL_WRITING, status, @@ -1852,34 +1867,45 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  	if (chip->verify_buf(mtd, buf, mtd->writesize))  		return -EIO; + +	/* Make sure the next page prog is preceded by a status read */ +	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);  #endif  	return 0;  }  /** - * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip:	nand chip structure - * @oob:	oob data buffer - * @len:	oob data write length - * @ops:	oob ops structure + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @mtd: MTD device structure + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure   */ -static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, -						struct mtd_oob_ops *ops) +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, +			      struct mtd_oob_ops *ops)  { +	struct nand_chip *chip = mtd->priv; + +	/* +	 * Initialise to all 0xFF, to avoid the possibility of left over OOB +	 * data from a previous OOB read. +	 */ +	memset(chip->oob_poi, 0xff, mtd->oobsize); +  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_RAW:  		memcpy(chip->oob_poi + ops->ooboffs, oob, len);  		return oob + len; -	case MTD_OOB_AUTO: { +	case MTD_OPS_AUTO_OOB: {  		struct nand_oobfree *free = chip->ecc.layout->oobfree;  		uint32_t boffs = 0, woffs = ops->ooboffs;  		size_t bytes = 0;  		for (; free->length && len; free++, len -= bytes) { -			/* Write request not from offset 0 ? */ +			/* Write request not from offset 0? */  			if (unlikely(woffs)) {  				if (woffs >= free->length) {  					woffs -= free->length; @@ -1907,12 +1933,12 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,  #define NOTALIGNED(x)	((x & (chip->subpagesize - 1)) != 0)  /** - * nand_do_write_ops - [Internal] NAND write with ECC - * @mtd:	MTD device structure - * @to:		offset to write to - * @ops:	oob operations description structure + * nand_do_write_ops - [INTERN] NAND write with ECC + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operations description structure   * - * NAND write with ECC + * NAND write with ECC.   */  static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  			     struct mtd_oob_ops *ops) @@ -1922,12 +1948,13 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	uint32_t writelen = ops->len;  	uint32_t oobwritelen = ops->ooblen; -	uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ? +	uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?  				mtd->oobavail : mtd->oobsize;  	uint8_t *oob = ops->oobbuf;  	uint8_t *buf = ops->datbuf;  	int ret, subpage; +	int oob_required = oob ? 1 : 0;  	ops->retlen = 0;  	if (!writelen) @@ -1957,10 +1984,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	    (chip->pagebuf << chip->page_shift) < (to + ops->len))  		chip->pagebuf = -1; -	/* If we're not given explicit OOB data, let it be 0xFF */ -	if (likely(!oob)) -		memset(chip->oob_poi, 0xff, mtd->oobsize); -  	/* Don't allow multipage oob writes with offset */  	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))  		return -EINVAL; @@ -1972,8 +1995,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  		int cached = writelen > bytes && page != blockmask;  		uint8_t *wbuf = buf; -		/* Partial page write ? */ -		if (unlikely(column || writelen < (mtd->writesize - 1))) { +		/* Partial page write? */ +		if (unlikely(column || writelen < mtd->writesize)) {  			cached = 0;  			bytes = min_t(int, bytes - column, (int) writelen);  			chip->pagebuf = -1; @@ -1984,12 +2007,15 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  		if (unlikely(oob)) {  			size_t len = min(oobwritelen, oobmaxlen); -			oob = nand_fill_oob(chip, oob, len, ops); +			oob = nand_fill_oob(mtd, oob, len, ops);  			oobwritelen -= len; +		} else { +			/* We still need to erase leftover OOB data */ +			memset(chip->oob_poi, 0xff, mtd->oobsize);  		} -		ret = chip->write_page(mtd, chip, wbuf, page, cached, -				       (ops->mode == MTD_OOB_RAW)); +		ret = chip->write_page(mtd, chip, wbuf, oob_required, page, +				       cached, (ops->mode == MTD_OPS_RAW));  		if (ret)  			break; @@ -2018,48 +2044,39 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  /**   * nand_write - [MTD Interface] NAND write with ECC - * @mtd:	MTD device structure - * @to:		offset to write to - * @len:	number of bytes to write - * @retlen:	pointer to variable to store the number of written bytes - * @buf:	the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write   * - * NAND write with ECC + * NAND write with ECC.   */  static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,  			  size_t *retlen, const uint8_t *buf)  {  	struct nand_chip *chip = mtd->priv; +	struct mtd_oob_ops ops;  	int ret; -	/* Do not allow writes past end of device */ -	if ((to + len) > mtd->size) -		return -EINVAL; -	if (!len) -		return 0; -  	nand_get_device(chip, mtd, FL_WRITING); - -	chip->ops.len = len; -	chip->ops.datbuf = (uint8_t *)buf; -	chip->ops.oobbuf = NULL; - -	ret = nand_do_write_ops(mtd, to, &chip->ops); - -	*retlen = chip->ops.retlen; - +	ops.len = len; +	ops.datbuf = (uint8_t *)buf; +	ops.oobbuf = NULL; +	ops.mode = MTD_OPS_PLACE_OOB; +	ret = nand_do_write_ops(mtd, to, &ops); +	*retlen = ops.retlen;  	nand_release_device(mtd); -  	return ret;  }  /**   * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd:	MTD device structure - * @to:		offset to write to - * @ops:	oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure   * - * NAND write out-of-band + * NAND write out-of-band.   */  static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  			     struct mtd_oob_ops *ops) @@ -2070,7 +2087,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",  			 __func__, (unsigned int)to, (int)ops->ooblen); -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		len = chip->ecc.layout->oobavail;  	else  		len = mtd->oobsize; @@ -2120,10 +2137,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	if (page == chip->pagebuf)  		chip->pagebuf = -1; -	memset(chip->oob_poi, 0xff, mtd->oobsize); -	nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); -	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); -	memset(chip->oob_poi, 0xff, mtd->oobsize); +	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); + +	if (ops->mode == MTD_OPS_RAW) +		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); +	else +		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);  	if (status)  		return status; @@ -2135,9 +2154,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  /**   * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd:	MTD device structure - * @to:		offset to write to - * @ops:	oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure   */  static int nand_write_oob(struct mtd_info *mtd, loff_t to,  			  struct mtd_oob_ops *ops) @@ -2157,9 +2176,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,  	nand_get_device(chip, mtd, FL_WRITING);  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB: +	case MTD_OPS_RAW:  		break;  	default: @@ -2177,11 +2196,11 @@ out:  }  /** - * single_erease_cmd - [GENERIC] NAND standard block erase command function - * @mtd:	MTD device structure - * @page:	the page address of the block which will be erased + * single_erase_cmd - [GENERIC] NAND standard block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased   * - * Standard erase command for NAND chips + * Standard erase command for NAND chips.   */  static void single_erase_cmd(struct mtd_info *mtd, int page)  { @@ -2192,12 +2211,11 @@ static void single_erase_cmd(struct mtd_info *mtd, int page)  }  /** - * multi_erease_cmd - [GENERIC] AND specific block erase command function - * @mtd:	MTD device structure - * @page:	the page address of the block which will be erased + * multi_erase_cmd - [GENERIC] AND specific block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased   * - * AND multi block erase command function - * Erase 4 consecutive blocks + * AND multi block erase command function. Erase 4 consecutive blocks.   */  static void multi_erase_cmd(struct mtd_info *mtd, int page)  { @@ -2212,10 +2230,10 @@ static void multi_erase_cmd(struct mtd_info *mtd, int page)  /**   * nand_erase - [MTD Interface] erase block(s) - * @mtd:	MTD device structure - * @instr:	erase instruction + * @mtd: MTD device structure + * @instr: erase instruction   * - * Erase one ore more blocks + * Erase one ore more blocks.   */  static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)  { @@ -2224,12 +2242,12 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)  #define BBT_PAGE_MASK	0xffffff3f  /** - * nand_erase_nand - [Internal] erase block(s) - * @mtd:	MTD device structure - * @instr:	erase instruction - * @allowbbt:	allow erasing the bbt area + * nand_erase_nand - [INTERN] erase block(s) + * @mtd: MTD device structure + * @instr: erase instruction + * @allowbbt: allow erasing the bbt area   * - * Erase one ore more blocks + * Erase one ore more blocks.   */  int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		    int allowbbt) @@ -2247,8 +2265,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	if (check_offs_len(mtd, instr->addr, instr->len))  		return -EINVAL; -	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; -  	/* Grab the lock and see if the device is available */  	nand_get_device(chip, mtd, FL_ERASING); @@ -2274,7 +2290,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	 * If BBT requires refresh, set the BBT page mask to see if the BBT  	 * should be rewritten. Otherwise the mask is set to 0xffffffff which  	 * can not be matched. This is also done when the bbt is actually -	 * erased to avoid recusrsive updates +	 * erased to avoid recursive updates.  	 */  	if (chip->options & BBT_AUTO_REFRESH && !allowbbt)  		bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2286,20 +2302,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	while (len) {  		WATCHDOG_RESET(); -		/* -		 * heck if we have a bad block, we do not erase bad blocks ! -		 */ +		/* Check if we have a bad block, we do not erase bad blocks! */  		if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<  					chip->page_shift, 0, allowbbt)) { -			printk(KERN_WARNING "%s: attempt to erase a bad block " -					"at page 0x%08x\n", __func__, page); +			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", +				   __func__, page);  			instr->state = MTD_ERASE_FAILED;  			goto erase_exit;  		}  		/*  		 * Invalidate the page cache, if we erase the block which -		 * contains the current cached page +		 * contains the current cached page.  		 */  		if (page <= chip->pagebuf && chip->pagebuf <  		    (page + pages_per_block)) @@ -2329,7 +2343,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		/*  		 * If BBT requires refresh, set the BBT rewrite flag to the -		 * page being erased +		 * page being erased.  		 */  		if (bbt_masked_page != 0xffffffff &&  		    (page & BBT_PAGE_MASK) == bbt_masked_page) @@ -2348,7 +2362,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  			/*  			 * If BBT requires refresh and BBT-PERCHIP, set the BBT -			 * page mask to see if this BBT should be rewritten +			 * page mask to see if this BBT should be rewritten.  			 */  			if (bbt_masked_page != 0xffffffff &&  			    (chip->bbt_td->options & NAND_BBT_PERCHIP)) @@ -2371,7 +2385,7 @@ erase_exit:  	/*  	 * If BBT requires refresh and erase was successful, rewrite any -	 * selected bad block tables +	 * selected bad block tables.  	 */  	if (bbt_masked_page == 0xffffffff || ret)  		return ret; @@ -2379,7 +2393,7 @@ erase_exit:  	for (chipnr = 0; chipnr < chip->numchips; chipnr++) {  		if (!rewrite_bbt[chipnr])  			continue; -		/* update the BBT for chip */ +		/* Update the BBT for chip */  		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt "  			"(%d:0x%0llx 0x%0x)\n", __func__, chipnr,  			rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); @@ -2392,9 +2406,9 @@ erase_exit:  /**   * nand_sync - [MTD Interface] sync - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Sync is actually a wait for chip ready function + * Sync is actually a wait for chip ready function.   */  static void nand_sync(struct mtd_info *mtd)  { @@ -2410,22 +2424,18 @@ static void nand_sync(struct mtd_info *mtd)  /**   * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd:	MTD device structure - * @offs:	offset relative to mtd start + * @mtd: MTD device structure + * @offs: offset relative to mtd start   */  static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)  { -	/* Check for invalid offset */ -	if (offs > mtd->size) -		return -EINVAL; -  	return nand_block_checkbad(mtd, offs, 1, 0);  }  /**   * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd:	MTD device structure - * @ofs:	offset relative to mtd start + * @mtd: MTD device structure + * @ofs: offset relative to mtd start   */  static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)  { @@ -2434,7 +2444,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)  	ret = nand_block_isbad(mtd, ofs);  	if (ret) { -		/* If it was bad already, return success and do nothing. */ +		/* If it was bad already, return success and do nothing */  		if (ret > 0)  			return 0;  		return ret; @@ -2443,9 +2453,51 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)  	return chip->block_markbad(mtd, ofs);  } -/* - * Set default functions + /** + * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand + * @mtd: MTD device structure + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. + */ +static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, +			int addr, uint8_t *subfeature_param) +{ +	int status; + +	if (!chip->onfi_version) +		return -EINVAL; + +	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); +	chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); +	status = chip->waitfunc(mtd, chip); +	if (status & NAND_STATUS_FAIL) +		return -EIO; +	return 0; +} + +/** + * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand + * @mtd: MTD device structure + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array.   */ +static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, +			int addr, uint8_t *subfeature_param) +{ +	if (!chip->onfi_version) +		return -EINVAL; + +	/* clear the sub feature parameters */ +	memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); + +	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); +	chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); +	return 0; +} + +/* Set default functions */  static void nand_set_defaults(struct nand_chip *chip, int busw)  {  	/* check for proper chip_delay setup, set 20us if not */ @@ -2483,23 +2535,21 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)  }  #ifdef CONFIG_SYS_NAND_ONFI_DETECTION -/* - * sanitize ONFI strings so we can safely print them - */ +/* Sanitize ONFI strings so we can safely print them */  static void sanitize_string(char *s, size_t len)  {  	ssize_t i; -	/* null terminate */ +	/* Null terminate */  	s[len - 1] = 0; -	/* remove non printable chars */ +	/* Remove non printable chars */  	for (i = 0; i < len - 1; i++) {  		if (s[i] < ' ' || s[i] > 127)  			s[i] = '?';  	} -	/* remove trailing spaces */ +	/* Remove trailing spaces */  	strim(s);  } @@ -2516,7 +2566,7 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)  }  /* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.   */  static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  					int *busw) @@ -2525,20 +2575,18 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  	int i;  	int val; -	/* try ONFI for unknow chip or LP */ +	/* Try ONFI for unknown chip or LP */  	chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);  	if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||  		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')  		return 0; -	MTDDEBUG(MTD_DEBUG_LEVEL0, "ONFI flash detected\n");  	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);  	for (i = 0; i < 3; i++) {  		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));  		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==  				le16_to_cpu(p->crc)) { -			MTDDEBUG(MTD_DEBUG_LEVEL0, -				 "ONFI param page %d valid\n", i); +			pr_info("ONFI param page %d valid\n", i);  			break;  		}  	} @@ -2546,7 +2594,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  	if (i == 3)  		return 0; -	/* check version */ +	/* Check version */  	val = le16_to_cpu(p->revision);  	if (val & (1 << 5))  		chip->onfi_version = 23; @@ -2562,8 +2610,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  		chip->onfi_version = 0;  	if (!chip->onfi_version) { -		printk(KERN_INFO "%s: unsupported ONFI version: %d\n", -								__func__, val); +		pr_info("%s: unsupported ONFI version: %d\n", __func__, val);  		return 0;  	} @@ -2580,8 +2627,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  	if (le16_to_cpu(p->features) & 1)  		*busw = NAND_BUSWIDTH_16; -	chip->options |= NAND_NO_READRDY | NAND_NO_AUTOINCR; - +	pr_info("ONFI flash detected\n");  	return 1;  }  #else @@ -2594,7 +2640,248 @@ static inline int nand_flash_detect_onfi(struct mtd_info *mtd,  #endif  /* - * Get the flash and manufacturer id and lookup if the type is supported + * nand_id_has_period - Check if an ID string has a given wraparound period + * @id_data: the ID string + * @arrlen: the length of the @id_data array + * @period: the period of repitition + * + * Check if an ID string is repeated within a given sequence of bytes at + * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a + * period of 2). This is a helper function for nand_id_len(). Returns non-zero + * if the repetition has a period of @period; otherwise, returns zero. + */ +static int nand_id_has_period(u8 *id_data, int arrlen, int period) +{ +	int i, j; +	for (i = 0; i < period; i++) +		for (j = i + period; j < arrlen; j += period) +			if (id_data[i] != id_data[j]) +				return 0; +	return 1; +} + +/* + * nand_id_len - Get the length of an ID string returned by CMD_READID + * @id_data: the ID string + * @arrlen: the length of the @id_data array + + * Returns the length of the ID string, according to known wraparound/trailing + * zero patterns. If no pattern exists, returns the length of the array. + */ +static int nand_id_len(u8 *id_data, int arrlen) +{ +	int last_nonzero, period; + +	/* Find last non-zero byte */ +	for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--) +		if (id_data[last_nonzero]) +			break; + +	/* All zeros */ +	if (last_nonzero < 0) +		return 0; + +	/* Calculate wraparound period */ +	for (period = 1; period < arrlen; period++) +		if (nand_id_has_period(id_data, arrlen, period)) +			break; + +	/* There's a repeated pattern */ +	if (period < arrlen) +		return period; + +	/* There are trailing zeros */ +	if (last_nonzero < arrlen - 1) +		return last_nonzero + 1; + +	/* No pattern detected */ +	return arrlen; +} + +/* + * Many new NAND share similar device ID codes, which represent the size of the + * chip. The rest of the parameters must be decoded according to generic or + * manufacturer-specific "extended ID" decoding patterns. + */ +static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, +				u8 id_data[8], int *busw) +{ +	int extid, id_len; +	/* The 3rd id byte holds MLC / multichip data */ +	chip->cellinfo = id_data[2]; +	/* The 4th id byte is the important one */ +	extid = id_data[3]; + +	id_len = nand_id_len(id_data, 8); + +	/* +	 * Field definitions are in the following datasheets: +	 * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) +	 * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) +	 * Hynix MLC   (6 byte ID): Hynix H27UBG8T2B (p.22) +	 * +	 * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung +	 * ID to decide what to do. +	 */ +	if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && +			(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && +			id_data[5] != 0x00) { +		/* Calc pagesize */ +		mtd->writesize = 2048 << (extid & 0x03); +		extid >>= 2; +		/* Calc oobsize */ +		switch (((extid >> 2) & 0x04) | (extid & 0x03)) { +		case 1: +			mtd->oobsize = 128; +			break; +		case 2: +			mtd->oobsize = 218; +			break; +		case 3: +			mtd->oobsize = 400; +			break; +		case 4: +			mtd->oobsize = 436; +			break; +		case 5: +			mtd->oobsize = 512; +			break; +		case 6: +		default: /* Other cases are "reserved" (unknown) */ +			mtd->oobsize = 640; +			break; +		} +		extid >>= 2; +		/* Calc blocksize */ +		mtd->erasesize = (128 * 1024) << +			(((extid >> 1) & 0x04) | (extid & 0x03)); +		*busw = 0; +	} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX && +			(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { +		unsigned int tmp; + +		/* Calc pagesize */ +		mtd->writesize = 2048 << (extid & 0x03); +		extid >>= 2; +		/* Calc oobsize */ +		switch (((extid >> 2) & 0x04) | (extid & 0x03)) { +		case 0: +			mtd->oobsize = 128; +			break; +		case 1: +			mtd->oobsize = 224; +			break; +		case 2: +			mtd->oobsize = 448; +			break; +		case 3: +			mtd->oobsize = 64; +			break; +		case 4: +			mtd->oobsize = 32; +			break; +		case 5: +			mtd->oobsize = 16; +			break; +		default: +			mtd->oobsize = 640; +			break; +		} +		extid >>= 2; +		/* Calc blocksize */ +		tmp = ((extid >> 1) & 0x04) | (extid & 0x03); +		if (tmp < 0x03) +			mtd->erasesize = (128 * 1024) << tmp; +		else if (tmp == 0x03) +			mtd->erasesize = 768 * 1024; +		else +			mtd->erasesize = (64 * 1024) << tmp; +		*busw = 0; +	} else { +		/* Calc pagesize */ +		mtd->writesize = 1024 << (extid & 0x03); +		extid >>= 2; +		/* Calc oobsize */ +		mtd->oobsize = (8 << (extid & 0x01)) * +			(mtd->writesize >> 9); +		extid >>= 2; +		/* Calc blocksize. Blocksize is multiples of 64KiB */ +		mtd->erasesize = (64 * 1024) << (extid & 0x03); +		extid >>= 2; +		/* Get buswidth information */ +		*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; +	} +} + + /* + * Old devices have chip data hardcoded in the device ID table. nand_decode_id + * decodes a matching ID table entry and assigns the MTD size parameters for + * the chip. + */ +static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip, +				const struct nand_flash_dev *type, u8 id_data[8], +				int *busw) +{ +	int maf_id = id_data[0]; + +	mtd->erasesize = type->erasesize; +	mtd->writesize = type->pagesize; +	mtd->oobsize = mtd->writesize / 32; +	*busw = type->options & NAND_BUSWIDTH_16; + +	/* +	 * Check for Spansion/AMD ID + repeating 5th, 6th byte since +	 * some Spansion chips have erasesize that conflicts with size +	 * listed in nand_ids table. +	 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) +	 */ +	if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00 +			&& id_data[6] == 0x00 && id_data[7] == 0x00 +			&& mtd->writesize == 512) { +		mtd->erasesize = 128 * 1024; +		mtd->erasesize <<= ((id_data[3] & 0x03) << 1); +	} +} + + /* + * Set the bad block marker/indicator (BBM/BBI) patterns according to some + * heuristic patterns using various detected parameters (e.g., manufacturer, + * page size, cell-type information). + */ +static void nand_decode_bbm_options(struct mtd_info *mtd, +				    struct nand_chip *chip, u8 id_data[8]) +{ +	int maf_id = id_data[0]; + +	/* Set the bad block position */ +	if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) +		chip->badblockpos = NAND_LARGE_BADBLOCK_POS; +	else +		chip->badblockpos = NAND_SMALL_BADBLOCK_POS; + +	/* +	 * Bad block marker is stored in the last page of each block on Samsung +	 * and Hynix MLC devices; stored in first two pages of each block on +	 * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba, +	 * AMD/Spansion, and Macronix.  All others scan only the first page. +	 */ +	if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && +			(maf_id == NAND_MFR_SAMSUNG || +			 maf_id == NAND_MFR_HYNIX)) +		chip->bbt_options |= NAND_BBT_SCANLASTPAGE; +	else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && +				(maf_id == NAND_MFR_SAMSUNG || +				 maf_id == NAND_MFR_HYNIX || +				 maf_id == NAND_MFR_TOSHIBA || +				 maf_id == NAND_MFR_AMD || +				 maf_id == NAND_MFR_MACRONIX)) || +			(mtd->writesize == 2048 && +			 maf_id == NAND_MFR_MICRON)) +		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; +} + +/* + * Get the flash and manufacturer id and lookup if the type is supported.   */  static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  						  struct nand_chip *chip, @@ -2605,14 +2892,13 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	const char *name;  	int i, maf_idx;  	u8 id_data[8]; -	int ret;  	/* Select the device */  	chip->select_chip(mtd, 0);  	/*  	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) -	 * after power-up +	 * after power-up.  	 */  	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); @@ -2623,7 +2909,8 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	*maf_id = chip->read_byte(mtd);  	*dev_id = chip->read_byte(mtd); -	/* Try again to make sure, as some systems the bus-hold or other +	/* +	 * Try again to make sure, as some systems the bus-hold or other  	 * interface concerns can cause random data which looks like a  	 * possibly credible NAND flash to appear. If the two results do  	 * not match, ignore the device completely. @@ -2631,13 +2918,14 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); -	for (i = 0; i < 2; i++) +	/* Read entire ID string */ +	for (i = 0; i < 8; i++)  		id_data[i] = chip->read_byte(mtd);  	if (id_data[0] != *maf_id || id_data[1] != *dev_id) { -		printk(KERN_INFO "%s: second ID read did not match " -		       "%02x,%02x against %02x,%02x\n", __func__, -		       *maf_id, *dev_id, id_data[0], id_data[1]); +		pr_info("%s: second ID read did not match " +			"%02x,%02x against %02x,%02x\n", __func__, +			*maf_id, *dev_id, id_data[0], id_data[1]);  		return ERR_PTR(-ENODEV);  	} @@ -2651,18 +2939,10 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	chip->onfi_version = 0;  	if (!type->name || !type->pagesize) {  		/* Check is chip is ONFI compliant */ -		ret = nand_flash_detect_onfi(mtd, chip, &busw); -		if (ret) +		if (nand_flash_detect_onfi(mtd, chip, &busw))  			goto ident_done;  	} -	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - -	/* Read entire ID string */ - -	for (i = 0; i < 8; i++) -		id_data[i] = chip->read_byte(mtd); -  	if (!type->name)  		return ERR_PTR(-ENODEV); @@ -2672,101 +2952,25 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	chip->chipsize = (uint64_t)type->chipsize << 20;  	if (!type->pagesize && chip->init_size) { -		/* set the pagesize, oobsize, erasesize by the driver*/ +		/* Set the pagesize, oobsize, erasesize by the driver */  		busw = chip->init_size(mtd, chip, id_data);  	} else if (!type->pagesize) { -		int extid; -		/* The 3rd id byte holds MLC / multichip data */ -		chip->cellinfo = id_data[2]; -		/* The 4th id byte is the important one */ -		extid = id_data[3]; - -		/* -		 * Field definitions are in the following datasheets: -		 * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) -		 * New style   (6 byte ID): Samsung K9GBG08U0M (p.40) -		 * -		 * Check for wraparound + Samsung ID + nonzero 6th byte -		 * to decide what to do. -		 */ -		if (id_data[0] == id_data[6] && id_data[1] == id_data[7] && -				id_data[0] == NAND_MFR_SAMSUNG && -				(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && -				id_data[5] != 0x00) { -			/* Calc pagesize */ -			mtd->writesize = 2048 << (extid & 0x03); -			extid >>= 2; -			/* Calc oobsize */ -			switch (extid & 0x03) { -			case 1: -				mtd->oobsize = 128; -				break; -			case 2: -				mtd->oobsize = 218; -				break; -			case 3: -				mtd->oobsize = 400; -				break; -			default: -				mtd->oobsize = 436; -				break; -			} -			extid >>= 2; -			/* Calc blocksize */ -			mtd->erasesize = (128 * 1024) << -				(((extid >> 1) & 0x04) | (extid & 0x03)); -			busw = 0; -		} else { -			/* Calc pagesize */ -			mtd->writesize = 1024 << (extid & 0x03); -			extid >>= 2; -			/* Calc oobsize */ -			mtd->oobsize = (8 << (extid & 0x01)) * -				(mtd->writesize >> 9); -			extid >>= 2; -			/* Calc blocksize. Blocksize is multiples of 64KiB */ -			mtd->erasesize = (64 * 1024) << (extid & 0x03); -			extid >>= 2; -			/* Get buswidth information */ -			busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; -		} +		/* Decode parameters from extended ID */ +		nand_decode_ext_id(mtd, chip, id_data, &busw);  	} else { -		/* -		 * Old devices have chip data hardcoded in the device id table -		 */ -		mtd->erasesize = type->erasesize; -		mtd->writesize = type->pagesize; -		mtd->oobsize = mtd->writesize / 32; -		busw = type->options & NAND_BUSWIDTH_16; - -		/* -		 * Check for Spansion/AMD ID + repeating 5th, 6th byte since -		 * some Spansion chips have erasesize that conflicts with size -		 * listed in nand_ids table -		 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) -		 */ -		if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && -				id_data[5] == 0x00 && id_data[6] == 0x00 && -				id_data[7] == 0x00 && mtd->writesize == 512) { -			mtd->erasesize = 128 * 1024; -			mtd->erasesize <<= ((id_data[3] & 0x03) << 1); -		} +		nand_decode_id(mtd, chip, type, id_data, &busw);  	}  	/* Get chip options, preserve non chip based options */  	chip->options |= type->options; -	/* Check if chip is a not a samsung device. Do not clear the -	 * options for chips which are not having an extended id. +	/* +	 * Check if chip is not a Samsung device. Do not clear the +	 * options for chips which do not have an extended id.  	 */  	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)  		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;  ident_done: -	/* -	 * Set chip as a default. Board drivers can override it, if necessary -	 */ -	chip->options |= NAND_NO_AUTOINCR; -  	/* Try to identify manufacturer */  	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {  		if (nand_manuf_ids[maf_idx].id == *maf_id) @@ -2775,21 +2979,23 @@ ident_done:  	/*  	 * Check, if buswidth is correct. Hardware drivers should set -	 * chip correct ! +	 * chip correct!  	 */  	if (busw != (chip->options & NAND_BUSWIDTH_16)) { -		printk(KERN_INFO "NAND device: Manufacturer ID:" -		       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, -		       *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); -		printk(KERN_WARNING "NAND bus width %d instead %d bit\n", -		       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, -		       busw ? 16 : 8); +		pr_info("NAND device: Manufacturer ID:" +			" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, +			*dev_id, nand_manuf_ids[maf_idx].name, mtd->name); +		pr_warn("NAND bus width %d instead %d bit\n", +			   (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, +			   busw ? 16 : 8);  		return ERR_PTR(-EINVAL);  	} +	nand_decode_bbm_options(mtd, chip, id_data); +  	/* Calculate the address shift from the page size */  	chip->page_shift = ffs(mtd->writesize) - 1; -	/* Convert chipsize to number of pages per chip -1. */ +	/* Convert chipsize to number of pages per chip -1 */  	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;  	chip->bbt_erase_shift = chip->phys_erase_shift = @@ -2803,73 +3009,38 @@ ident_done:  	chip->badblockbits = 8; -	/* Set the bad block position */ -	if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) -		chip->badblockpos = NAND_LARGE_BADBLOCK_POS; -	else -		chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - -	/* -	 * Bad block marker is stored in the last page of each block -	 * on Samsung and Hynix MLC devices; stored in first two pages -	 * of each block on Micron devices with 2KiB pages and on -	 * SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan -	 * only the first page. -	 */ -	if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && -			(*maf_id == NAND_MFR_SAMSUNG || -			 *maf_id == NAND_MFR_HYNIX)) -		chip->options |= NAND_BBT_SCANLASTPAGE; -	else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && -				(*maf_id == NAND_MFR_SAMSUNG || -				 *maf_id == NAND_MFR_HYNIX || -				 *maf_id == NAND_MFR_TOSHIBA || -				 *maf_id == NAND_MFR_AMD)) || -			(mtd->writesize == 2048 && -			 *maf_id == NAND_MFR_MICRON)) -		chip->options |= NAND_BBT_SCAN2NDPAGE; - -	/* -	 * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 -	 */ -	if (!(busw & NAND_BUSWIDTH_16) && -			*maf_id == NAND_MFR_STMICRO && -			mtd->writesize == 2048) { -		chip->options |= NAND_BBT_SCANBYTE1AND6; -		chip->badblockpos = 0; -	} -  	/* Check for AND chips with 4 page planes */  	if (chip->options & NAND_4PAGE_ARRAY)  		chip->erase_cmd = multi_erase_cmd;  	else  		chip->erase_cmd = single_erase_cmd; -	/* Do not replace user supplied command function ! */ +	/* Do not replace user supplied command function! */  	if (mtd->writesize > 512 && chip->cmdfunc == nand_command)  		chip->cmdfunc = nand_command_lp; -	/* TODO onfi flash name */  	name = type->name;  #ifdef CONFIG_SYS_NAND_ONFI_DETECTION  	if (chip->onfi_version)  		name = chip->onfi_params.model;  #endif -	MTDDEBUG(MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:" -		 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, -		 nand_manuf_ids[maf_idx].name, name); +	pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," +		" page size: %d, OOB size: %d\n", +		*maf_id, *dev_id, nand_manuf_ids[maf_idx].name, +		name, +		mtd->writesize, mtd->oobsize);  	return type;  }  /**   * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd:	     MTD device structure - * @maxchips:	     Number of chips to scan for - * @table:	     Alternative NAND ID table + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * @table: alternative NAND ID table   * - * This is the first phase of the normal nand_scan() function. It - * reads the flash ID and sets up MTD fields accordingly. + * This is the first phase of the normal nand_scan() function. It reads the + * flash ID and sets up MTD fields accordingly.   *   * The mtd->owner field must be set to the module of the caller.   */ @@ -2891,7 +3062,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  	if (IS_ERR(type)) {  #ifndef CONFIG_SYS_NAND_QUIET_TEST -		printk(KERN_WARNING "No NAND device found!!!\n"); +		pr_warn("No NAND device found\n");  #endif  		chip->select_chip(mtd, -1);  		return PTR_ERR(type); @@ -2911,7 +3082,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  	}  #ifdef DEBUG  	if (i > 1) -		printk(KERN_INFO "%d NAND chips detected\n", i); +		pr_info("%d NAND chips detected\n", i);  #endif  	/* Store the number of chips and calc total size for mtd */ @@ -2924,17 +3095,21 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  /**   * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd:	    MTD device structure + * @mtd: MTD device structure   * - * This is the second phase of the normal nand_scan() function. It - * fills out all the uninitialized function pointers with the defaults - * and scans for a bad block table if appropriate. + * This is the second phase of the normal nand_scan() function. It fills out + * all the uninitialized function pointers with the defaults and scans for a + * bad block table if appropriate.   */  int nand_scan_tail(struct mtd_info *mtd)  {  	int i;  	struct nand_chip *chip = mtd->priv; +	/* New bad blocks should be marked in OOB, flash-based BBT, or both */ +	BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && +			!(chip->bbt_options & NAND_BBT_USE_FLASH)); +  	if (!(chip->options & NAND_OWN_BUFFERS))  		chip->buffers = memalign(ARCH_DMA_MINALIGN,  					 sizeof(*chip->buffers)); @@ -2945,7 +3120,7 @@ int nand_scan_tail(struct mtd_info *mtd)  	chip->oob_poi = chip->buffers->databuf + mtd->writesize;  	/* -	 * If no default placement scheme is given, select an appropriate one +	 * If no default placement scheme is given, select an appropriate one.  	 */  	if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {  		switch (mtd->oobsize) { @@ -2962,16 +3137,22 @@ int nand_scan_tail(struct mtd_info *mtd)  			chip->ecc.layout = &nand_oob_128;  			break;  		default: -			printk(KERN_WARNING "No oob scheme defined for " -			       "oobsize %d\n", mtd->oobsize); +			pr_warn("No oob scheme defined for oobsize %d\n", +				   mtd->oobsize);  		}  	}  	if (!chip->write_page)  		chip->write_page = nand_write_page; +	/* set for ONFI nand */ +	if (!chip->onfi_set_features) +		chip->onfi_set_features = nand_onfi_set_features; +	if (!chip->onfi_get_features) +		chip->onfi_get_features = nand_onfi_get_features; +  	/* -	 * check ECC mode, default to software if 3byte/512byte hardware ECC is +	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is  	 * selected and we have 256 byte pagesize fallback to software ECC  	 */ @@ -2980,15 +3161,15 @@ int nand_scan_tail(struct mtd_info *mtd)  		/* Similar to NAND_ECC_HW, but a separate read_page handle */  		if (!chip->ecc.calculate || !chip->ecc.correct ||  		     !chip->ecc.hwctl) { -			printk(KERN_WARNING "No ECC functions supplied; " -			       "Hardware ECC not possible\n"); +			pr_warn("No ECC functions supplied; " +				   "hardware ECC not possible\n");  			BUG();  		}  		if (!chip->ecc.read_page)  			chip->ecc.read_page = nand_read_page_hwecc_oob_first;  	case NAND_ECC_HW: -		/* Use standard hwecc read page function ? */ +		/* Use standard hwecc read page function? */  		if (!chip->ecc.read_page)  			chip->ecc.read_page = nand_read_page_hwecc;  		if (!chip->ecc.write_page) @@ -3009,11 +3190,11 @@ int nand_scan_tail(struct mtd_info *mtd)  		     chip->ecc.read_page == nand_read_page_hwecc ||  		     !chip->ecc.write_page ||  		     chip->ecc.write_page == nand_write_page_hwecc)) { -			printk(KERN_WARNING "No ECC functions supplied; " -			       "Hardware ECC not possible\n"); +			pr_warn("No ECC functions supplied; " +				   "hardware ECC not possible\n");  			BUG();  		} -		/* Use standard syndrome read/write page function ? */ +		/* Use standard syndrome read/write page function? */  		if (!chip->ecc.read_page)  			chip->ecc.read_page = nand_read_page_syndrome;  		if (!chip->ecc.write_page) @@ -3027,11 +3208,16 @@ int nand_scan_tail(struct mtd_info *mtd)  		if (!chip->ecc.write_oob)  			chip->ecc.write_oob = nand_write_oob_syndrome; -		if (mtd->writesize >= chip->ecc.size) +		if (mtd->writesize >= chip->ecc.size) { +			if (!chip->ecc.strength) { +				pr_warn("Driver must set ecc.strength when using hardware ECC\n"); +				BUG(); +			}  			break; -		printk(KERN_WARNING "%d byte HW ECC not possible on " -		       "%d byte page size, fallback to SW ECC\n", -		       chip->ecc.size, mtd->writesize); +		} +		pr_warn("%d byte HW ECC not possible on " +			   "%d byte page size, fallback to SW ECC\n", +			   chip->ecc.size, mtd->writesize);  		chip->ecc.mode = NAND_ECC_SOFT;  	case NAND_ECC_SOFT: @@ -3047,11 +3233,12 @@ int nand_scan_tail(struct mtd_info *mtd)  		if (!chip->ecc.size)  			chip->ecc.size = 256;  		chip->ecc.bytes = 3; +		chip->ecc.strength = 1;  		break;  	case NAND_ECC_SOFT_BCH:  		if (!mtd_nand_has_bch()) { -			printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); +			pr_warn("CONFIG_MTD_ECC_BCH not enabled\n");  			return -EINVAL;  		}  		chip->ecc.calculate = nand_bch_calculate_ecc; @@ -3066,8 +3253,8 @@ int nand_scan_tail(struct mtd_info *mtd)  		/*  		 * Board driver should supply ecc.size and ecc.bytes values to  		 * select how many bits are correctable; see nand_bch_init() -		 * for details. -		 * Otherwise, default to 4 bits for large page devices +		 * for details. Otherwise, default to 4 bits for large page +		 * devices.  		 */  		if (!chip->ecc.size && (mtd->oobsize >= 64)) {  			chip->ecc.size = 512; @@ -3078,13 +3265,14 @@ int nand_scan_tail(struct mtd_info *mtd)  					       chip->ecc.bytes,  					       &chip->ecc.layout);  		if (!chip->ecc.priv) -			printk(KERN_WARNING "BCH ECC initialization failed!\n"); - +			pr_warn("BCH ECC initialization failed!\n"); + 		chip->ecc.strength = +			chip->ecc.bytes * 8 / fls(8 * chip->ecc.size);  		break;  	case NAND_ECC_NONE: -		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " -		       "This is not recommended !!\n"); +		pr_warn("NAND_ECC_NONE selected by board driver. " +		        "This is not recommended !!\n");  		chip->ecc.read_page = nand_read_page_raw;  		chip->ecc.write_page = nand_write_page_raw;  		chip->ecc.read_oob = nand_read_oob_std; @@ -3096,14 +3284,19 @@ int nand_scan_tail(struct mtd_info *mtd)  		break;  	default: -		printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", -		       chip->ecc.mode); +		pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode);  		BUG();  	} +	/* For many systems, the standard OOB write also works for raw */ +	if (!chip->ecc.read_oob_raw) +		chip->ecc.read_oob_raw = chip->ecc.read_oob; +	if (!chip->ecc.write_oob_raw) +		chip->ecc.write_oob_raw = chip->ecc.write_oob; +  	/*  	 * The number of bytes available for a client to place data into -	 * the out of band area +	 * the out of band area.  	 */  	chip->ecc.layout->oobavail = 0;  	for (i = 0; chip->ecc.layout->oobfree[i].length @@ -3114,19 +3307,16 @@ int nand_scan_tail(struct mtd_info *mtd)  	/*  	 * Set the number of read / write steps for one page depending on ECC -	 * mode +	 * mode.  	 */  	chip->ecc.steps = mtd->writesize / chip->ecc.size;  	if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { -		printk(KERN_WARNING "Invalid ecc parameters\n"); +		pr_warn("Invalid ECC parameters\n");  		BUG();  	}  	chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; -	/* -	 * Allow subpage writes up to ecc.steps. Not possible for MLC -	 * FLASH. -	 */ +	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */  	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&  	    !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {  		switch (chip->ecc.steps) { @@ -3159,21 +3349,29 @@ int nand_scan_tail(struct mtd_info *mtd)  	mtd->type = MTD_NANDFLASH;  	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :  						MTD_CAP_NANDFLASH; -	mtd->erase = nand_erase; -	mtd->point = NULL; -	mtd->unpoint = NULL; -	mtd->read = nand_read; -	mtd->write = nand_write; -	mtd->read_oob = nand_read_oob; -	mtd->write_oob = nand_write_oob; -	mtd->sync = nand_sync; -	mtd->lock = NULL; -	mtd->unlock = NULL; -	mtd->block_isbad = nand_block_isbad; -	mtd->block_markbad = nand_block_markbad; +	mtd->_erase = nand_erase; +	mtd->_point = NULL; +	mtd->_unpoint = NULL; +	mtd->_read = nand_read; +	mtd->_write = nand_write; +	mtd->_read_oob = nand_read_oob; +	mtd->_write_oob = nand_write_oob; +	mtd->_sync = nand_sync; +	mtd->_lock = NULL; +	mtd->_unlock = NULL; +	mtd->_block_isbad = nand_block_isbad; +	mtd->_block_markbad = nand_block_markbad; -	/* propagate ecc.layout to mtd_info */ +	/* propagate ecc info to mtd_info */  	mtd->ecclayout = chip->ecc.layout; +	mtd->ecc_strength = chip->ecc.strength; +	/* +	 * Initialize bitflip_threshold to its default prior scan_bbt() call. +	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be +	 * properly set. +	 */ +	if (!mtd->bitflip_threshold) +		mtd->bitflip_threshold = mtd->ecc_strength;  	/* Check, if we should skip the bad block table scan */  	if (chip->options & NAND_SKIP_BBTSCAN) @@ -3184,15 +3382,13 @@ int nand_scan_tail(struct mtd_info *mtd)  /**   * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd:	MTD device structure - * @maxchips:	Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * @mtd: MTD device structure + * @maxchips: number of chips to scan for   * + * This fills out all the uninitialized function pointers with the defaults. + * The flash ID is read and the mtd/chip structures are filled with the + * appropriate values. The mtd->owner field must be set to the module of the + * caller.   */  int nand_scan(struct mtd_info *mtd, int maxchips)  { @@ -3206,8 +3402,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips)  /**   * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd:	MTD device structure -*/ + * @mtd: MTD device structure + */  void nand_release(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 74a7061b0..8ef58451d 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -4,7 +4,7 @@   *  Overview:   *   Bad block table support for the NAND driver   * - *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) + *  Copyright © 2004 Thomas Gleixner (tglx@linutronix.de)   *   * 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 @@ -14,7 +14,7 @@   *   * When nand_scan_bbt is called, then it tries to find the bad block table   * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory   * marked good / bad blocks. This information is used to create a memory BBT.   * Once a new bad block is discovered then the "factory" information is updated   * on the device. @@ -22,7 +22,7 @@   * BBT on flash. If a BBT is found then the contents are read and the memory   * based BBT is created. If a mirrored BBT is selected then the mirror is   * searched too and the versions are compared. If the mirror has a greater - * version number than the mirror BBT is used to build the memory based BBT. + * version number, then the mirror BBT is used to build the memory based BBT.   * If the tables are not versioned, then we "or" the bad block information.   * If one of the BBTs is out of date or does not exist it is (re)created.   * If no BBT exists at all then the device is scanned for factory marked @@ -36,9 +36,9 @@   * The table is marked in the OOB area with an ident pattern and a version   * number which indicates which of both tables is more up to date. If the NAND   * controller needs the complete OOB area for the ECC information then the - * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern - * and the version byte into the data area and the OOB area will remain - * untouched. + * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of + * course): it moves the ident pattern and the version byte into the data area + * and the OOB area will remain untouched.   *   * The table uses 2 bits per block   * 11b:		block is good @@ -63,126 +63,81 @@  #include <malloc.h>  #include <linux/compat.h>  #include <linux/mtd/mtd.h> +#include <linux/mtd/bbm.h>  #include <linux/mtd/nand.h>  #include <linux/mtd/nand_ecc.h>  #include <linux/bitops.h> +#include <linux/string.h>  #include <asm/errno.h>  static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)  { -	int ret; - -	ret = memcmp(buf, td->pattern, td->len); -	if (!ret) -		return ret; -	return -1; +	if (memcmp(buf, td->pattern, td->len)) +		return -1; +	return 0;  }  /**   * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf:	the buffer to search - * @len:	the length of buffer to search - * @paglen:	the pagelength - * @td:		search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. - * If the SCAN_EMPTY option is set then check, if all bytes except the - * pattern area contain 0xff + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor   * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if + * all bytes except the pattern area contain 0xff. + */  static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)  { -	int i, end = 0; +	int end = 0;  	uint8_t *p = buf;  	if (td->options & NAND_BBT_NO_OOB)  		return check_pattern_no_oob(buf, td);  	end = paglen + td->offs; -	if (td->options & NAND_BBT_SCANEMPTY) { -		for (i = 0; i < end; i++) { -			if (p[i] != 0xff) -				return -1; -		} -	} +	if (td->options & NAND_BBT_SCANEMPTY) +		if (memchr_inv(p, 0xff, end)) +			return -1;  	p += end;  	/* Compare the pattern */ -	for (i = 0; i < td->len; i++) { -		if (p[i] != td->pattern[i]) -			return -1; -	} - -	/* Check both positions 1 and 6 for pattern? */ -	if (td->options & NAND_BBT_SCANBYTE1AND6) { -		if (td->options & NAND_BBT_SCANEMPTY) { -			p += td->len; -			end += NAND_SMALL_BADBLOCK_POS - td->offs; -			/* Check region between positions 1 and 6 */ -			for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; -					i++) { -				if (*p++ != 0xff) -					return -1; -			} -		} -		else { -			p += NAND_SMALL_BADBLOCK_POS - td->offs; -		} -		/* Compare the pattern */ -		for (i = 0; i < td->len; i++) { -			if (p[i] != td->pattern[i]) -				return -1; -		} -	} +	if (memcmp(p, td->pattern, td->len)) +		return -1;  	if (td->options & NAND_BBT_SCANEMPTY) {  		p += td->len;  		end += td->len; -		for (i = end; i < len; i++) { -			if (*p++ != 0xff) -				return -1; -		} +		if (memchr_inv(p, 0xff, len - end)) +			return -1;  	}  	return 0;  }  /**   * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf:	the buffer to search - * @td:		search pattern descriptor + * @buf: the buffer to search + * @td:	search pattern descriptor   * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but - * no optional empty check - * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. Same as check_pattern, but no optional empty + * check. + */  static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)  { -	int i; -	uint8_t *p = buf; -  	/* Compare the pattern */ -	for (i = 0; i < td->len; i++) { -		if (p[td->offs + i] != td->pattern[i]) -			return -1; -	} -	/* Need to check location 1 AND 6? */ -	if (td->options & NAND_BBT_SCANBYTE1AND6) { -		for (i = 0; i < td->len; i++) { -			if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) -				return -1; -		} -	} +	if (memcmp(buf + td->offs, td->pattern, td->len)) +		return -1;  	return 0;  }  /**   * add_marker_len - compute the length of the marker in data area - * @td:		BBT descriptor used for computation + * @td: BBT descriptor used for computation   * - * The length will be 0 if the markeris located in OOB area. + * The length will be 0 if the marker is located in OOB area.   */  static u32 add_marker_len(struct nand_bbt_descr *td)  { @@ -199,34 +154,33 @@ static u32 add_marker_len(struct nand_bbt_descr *td)  /**   * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @page:	the starting page - * @num:	the number of bbt descriptors to read - * @td:		the bbt describtion table - * @offs:	offset in the memory table + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table   *   * Read the bad block table starting from page. - *   */  static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  		struct nand_bbt_descr *td, int offs)  { -	int res, i, j, act = 0; +	int res, ret = 0, i, j, act = 0;  	struct nand_chip *this = mtd->priv;  	size_t retlen, len, totlen;  	loff_t from;  	int bits = td->options & NAND_BBT_NRBITS_MSK; -	uint8_t msk = (uint8_t) ((1 << bits) - 1); +	uint8_t msk = (uint8_t)((1 << bits) - 1);  	u32 marker_len;  	int reserved_block_code = td->reserved_block_code;  	totlen = (num * bits) >> 3;  	marker_len = add_marker_len(td); -	from = ((loff_t) page) << this->page_shift; +	from = ((loff_t)page) << this->page_shift;  	while (totlen) { -		len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); +		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));  		if (marker_len) {  			/*  			 * In case the BBT marker is not in the OOB area it @@ -236,13 +190,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  			from += marker_len;  			marker_len = 0;  		} -		res = mtd->read(mtd, from, len, &retlen, buf); +		res = mtd_read(mtd, from, len, &retlen, buf);  		if (res < 0) { -			if (retlen != len) { -				printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); +			if (mtd_is_eccerr(res)) { +				pr_info("nand_bbt: ECC error in BBT at " +					"0x%012llx\n", from & ~mtd->writesize); +				return res; +			} else if (mtd_is_bitflip(res)) { +				pr_info("nand_bbt: corrected error in BBT at " +					"0x%012llx\n", from & ~mtd->writesize); +				ret = res; +			} else { +				pr_info("nand_bbt: error reading BBT\n");  				return res;  			} -			printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");  		}  		/* Analyse data */ @@ -253,17 +214,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  				if (tmp == msk)  					continue;  				if (reserved_block_code && (tmp == reserved_block_code)) { -					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", -					       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); +					pr_info("nand_read_bbt: reserved block at 0x%012llx\n", +						 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);  					mtd->ecc_stats.bbtblocks++;  					continue;  				} -				MTDDEBUG(MTD_DEBUG_LEVEL0, "nand_read_bbt: " \ -					"Bad block at 0x%012llx\n", +				pr_info("nand_read_bbt: Bad block at 0x%012llx\n",  					(loff_t)((offs << 2) + (act >> 1))  					<< this->bbt_erase_shift); -				/* Factory marked bad or worn out ? */ +				/* Factory marked bad or worn out? */  				if (tmp == 0)  					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);  				else @@ -274,20 +234,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  		totlen -= len;  		from += len;  	} -	return 0; +	return ret;  }  /**   * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @chip:	read the table for a specific chip, -1 read all chips. - *		Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips; applies only if + *        NAND_BBT_PERCHIP option is set   * - * Read the bad block table for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. -*/ + * Read the bad block table for all chips starting at a given page. We assume + * that the bbt bits are in consecutive order. + */  static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)  {  	struct nand_chip *this = mtd->priv; @@ -313,10 +273,8 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  	return 0;  } -/* - * BBT marker is in the first page, no OOB. - */ -static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +/* BBT marker is in the first page, no OOB */ +static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  			 struct nand_bbt_descr *td)  {  	size_t retlen; @@ -326,70 +284,73 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  	if (td->options & NAND_BBT_VERSION)  		len++; -	return mtd->read(mtd, offs, len, &retlen, buf); +	return mtd_read(mtd, offs, len, &retlen, buf);  } -/* - * Scan read raw data from flash +/** + * scan_read_oob - [GENERIC] Scan data+OOB region to buffer + * @mtd: MTD device structure + * @buf: temporary buffer + * @offs: offset at which to scan + * @len: length of data region to read + * + * Scan read data from data+OOB. May traverse multiple pages, interleaving + * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" + * ECC condition (error or bitflip). May quit on the first (non-ECC) error.   */ -static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  			 size_t len)  {  	struct mtd_oob_ops ops; -	int res; +	int res, ret = 0; -	ops.mode = MTD_OOB_RAW; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = 0;  	ops.ooblen = mtd->oobsize; -  	while (len > 0) { -		if (len <= mtd->writesize) { -			ops.oobbuf = buf + len; -			ops.datbuf = buf; -			ops.len = len; -			return mtd->read_oob(mtd, offs, &ops); -		} else { -			ops.oobbuf = buf + mtd->writesize; -			ops.datbuf = buf; -			ops.len = mtd->writesize; -			res = mtd->read_oob(mtd, offs, &ops); +		ops.datbuf = buf; +		ops.len = min(len, (size_t)mtd->writesize); +		ops.oobbuf = buf + ops.len; -			if (res) +		res = mtd_read_oob(mtd, offs, &ops); +		if (res) { +			if (!mtd_is_bitflip_or_eccerr(res))  				return res; +			else if (mtd_is_eccerr(res) || !ret) +				ret = res;  		}  		buf += mtd->oobsize + mtd->writesize;  		len -= mtd->writesize; +		offs += mtd->writesize;  	} -	return 0; +	return ret;  } -static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  			 size_t len, struct nand_bbt_descr *td)  {  	if (td->options & NAND_BBT_NO_OOB) -		return scan_read_raw_data(mtd, buf, offs, td); +		return scan_read_data(mtd, buf, offs, td);  	else -		return scan_read_raw_oob(mtd, buf, offs, len); +		return scan_read_oob(mtd, buf, offs, len);  } -/* - * Scan write data with oob to flash - */ +/* Scan write data with oob to flash */  static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,  			  uint8_t *buf, uint8_t *oob)  {  	struct mtd_oob_ops ops; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = 0;  	ops.ooblen = mtd->oobsize;  	ops.datbuf = buf;  	ops.oobbuf = oob;  	ops.len = len; -	return mtd->write_oob(mtd, offs, &ops); +	return mtd_write_oob(mtd, offs, &ops);  }  static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) @@ -403,65 +364,60 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)  /**   * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @md:		descriptor for the bad block table mirror - * - * Read the bad block table(s) for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md:	descriptor for the bad block table mirror   * -*/ -static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, -			 struct nand_bbt_descr *td, struct nand_bbt_descr *md) + * Read the bad block table(s) for all chips starting at a given page. We + * assume that the bbt bits are in consecutive order. + */ +static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, +			  struct nand_bbt_descr *td, struct nand_bbt_descr *md)  {  	struct nand_chip *this = mtd->priv;  	/* Read the primary version, if available */  	if (td->options & NAND_BBT_VERSION) { -		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, +		scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,  			      mtd->writesize, td);  		td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; -		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", -		       td->pages[0], td->version[0]); +		pr_info("Bad block table at page %d, version 0x%02X\n", +			 td->pages[0], td->version[0]);  	}  	/* Read the mirror version, if available */  	if (md && (md->options & NAND_BBT_VERSION)) { -		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, -			      mtd->writesize, td); +		scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, +			      mtd->writesize, md);  		md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; -		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", -		       md->pages[0], md->version[0]); +		pr_info("Bad block table at page %d, version 0x%02X\n", +			 md->pages[0], md->version[0]);  	} -	return 1;  } -/* - * Scan a given block full - */ +/* Scan a given block full */  static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,  			   loff_t offs, uint8_t *buf, size_t readlen, -			   int scanlen, int len) +			   int scanlen, int numpages)  {  	int ret, j; -	ret = scan_read_raw_oob(mtd, buf, offs, readlen); -	if (ret) +	ret = scan_read_oob(mtd, buf, offs, readlen); +	/* Ignore ECC errors when checking for BBM */ +	if (ret && !mtd_is_bitflip_or_eccerr(ret))  		return ret; -	for (j = 0; j < len; j++, buf += scanlen) { +	for (j = 0; j < numpages; j++, buf += scanlen) {  		if (check_pattern(buf, scanlen, mtd->writesize, bd))  			return 1;  	}  	return 0;  } -/* - * Scan a given block partially - */ +/* Scan a given block partially */  static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, -			   loff_t offs, uint8_t *buf, int len) +			   loff_t offs, uint8_t *buf, int numpages)  {  	struct mtd_oob_ops ops;  	int j, ret; @@ -470,16 +426,16 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,  	ops.oobbuf = buf;  	ops.ooboffs = 0;  	ops.datbuf = NULL; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB; -	for (j = 0; j < len; j++) { +	for (j = 0; j < numpages; j++) {  		/* -		 * Read the full oob until read_oob is fixed to -		 * handle single byte reads for 16 bit -		 * buswidth +		 * Read the full oob until read_oob is fixed to handle single +		 * byte reads for 16 bit buswidth.  		 */ -		ret = mtd->read_oob(mtd, offs, &ops); -		if (ret) +		ret = mtd_read_oob(mtd, offs, &ops); +		/* Ignore ECC errors when checking for BBM */ +		if (ret && !mtd_is_bitflip_or_eccerr(ret))  			return ret;  		if (check_short_pattern(buf, bd)) @@ -492,32 +448,32 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,  /**   * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @bd:		descriptor for the good/bad block search pattern - * @chip:	create the table for a specific chip, -1 read all chips. - *		Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + *        if NAND_BBT_PERCHIP option is set   * - * Create a bad block table by scanning the device - * for the given good/bad block identify pattern + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern.   */  static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	struct nand_bbt_descr *bd, int chip)  {  	struct nand_chip *this = mtd->priv; -	int i, numblocks, len, scanlen; +	int i, numblocks, numpages, scanlen;  	int startblock;  	loff_t from;  	size_t readlen; -	MTDDEBUG(MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n"); +	pr_info("Scanning device for bad blocks\n");  	if (bd->options & NAND_BBT_SCANALLPAGES) -		len = 1 << (this->bbt_erase_shift - this->page_shift); +		numpages = 1 << (this->bbt_erase_shift - this->page_shift);  	else if (bd->options & NAND_BBT_SCAN2NDPAGE) -		len = 2; +		numpages = 2;  	else -		len = 1; +		numpages = 1;  	if (!(bd->options & NAND_BBT_SCANEMPTY)) {  		/* We need only read few bytes from the OOB area */ @@ -526,18 +482,20 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	} else {  		/* Full page content should be read */  		scanlen = mtd->writesize + mtd->oobsize; -		readlen = len * mtd->writesize; +		readlen = numpages * mtd->writesize;  	}  	if (chip == -1) { -		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 -		 * below as it makes shifting and masking less painful */ +		/* +		 * Note that numblocks is 2 * (real numblocks) here, see i+=2 +		 * below as it makes shifting and masking less painful +		 */  		numblocks = mtd->size >> (this->bbt_erase_shift - 1);  		startblock = 0;  		from = 0;  	} else {  		if (chip >= this->numchips) { -			printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", +			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",  			       chip + 1, this->numchips);  			return -EINVAL;  		} @@ -547,8 +505,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		from = (loff_t)startblock << (this->bbt_erase_shift - 1);  	} -	if (this->options & NAND_BBT_SCANLASTPAGE) -		from += mtd->erasesize - (mtd->writesize * len); +	if (this->bbt_options & NAND_BBT_SCANLASTPAGE) +		from += mtd->erasesize - (mtd->writesize * numpages);  	for (i = startblock; i < numblocks;) {  		int ret; @@ -557,17 +515,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (bd->options & NAND_BBT_SCANALLPAGES)  			ret = scan_block_full(mtd, bd, from, buf, readlen, -					      scanlen, len); +					      scanlen, numpages);  		else -			ret = scan_block_fast(mtd, bd, from, buf, len); +			ret = scan_block_fast(mtd, bd, from, buf, numpages);  		if (ret < 0)  			return ret;  		if (ret) {  			this->bbt[i >> 3] |= 0x03 << (i & 0x6); -			MTDDEBUG(MTD_DEBUG_LEVEL0, -				  "Bad eraseblock %d at 0x%012llx\n", +			pr_warn("Bad eraseblock %d at 0x%012llx\n",  				  i >> 1, (unsigned long long)from);  			mtd->ecc_stats.badblocks++;  		} @@ -580,20 +537,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  /**   * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table   * - * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of - * the device downwards. The search starts always at the start of a - * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched - * for a bbt, which contains the bad block information of this chip. - * This is necessary to provide support for certain DOC devices. + * Read the bad block table by searching for a given ident pattern. Search is + * preformed either from the beginning up or from the end of the device + * downwards. The search starts always at the start of a block. If the option + * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains + * the bad block information of this chip. This is necessary to provide support + * for certain DOC devices.   * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page in a block.   */  static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)  { @@ -604,7 +559,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  	int bbtblocks;  	int blocktopage = this->bbt_erase_shift - this->page_shift; -	/* Search direction top -> down ? */ +	/* Search direction top -> down? */  	if (td->options & NAND_BBT_LASTBLOCK) {  		startblock = (mtd->size >> this->bbt_erase_shift) - 1;  		dir = -1; @@ -613,7 +568,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  		dir = 1;  	} -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP) {  		chips = this->numchips;  		bbtblocks = this->chipsize >> this->bbt_erase_shift; @@ -634,7 +589,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;  			/* Read first page */ -			scan_read_raw(mtd, buf, offs, mtd->writesize, td); +			scan_read(mtd, buf, offs, mtd->writesize, td);  			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {  				td->pages[i] = actblock << blocktopage;  				if (td->options & NAND_BBT_VERSION) { @@ -649,10 +604,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  	/* Check, if we found a bbt for each requested chip */  	for (i = 0; i < chips; i++) {  		if (td->pages[i] == -1) -			printk(KERN_WARNING "Bad block table not found for chip %d\n", i); +			pr_warn("Bad block table not found for chip %d\n", i);  		else -			MTDDEBUG(MTD_DEBUG_LEVEL0, "Bad block table found " \ -				"at page %d, version 0x%02X\n", td->pages[i], +			pr_info("Bad block table found at page %d, version 0x%02X\n", td->pages[i],  				td->version[i]);  	}  	return 0; @@ -660,14 +614,16 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  /**   * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @md:		descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror   * - * Search and read the bad block table(s) -*/ -static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) + * Search and read the bad block table(s). + */ +static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, +			     struct nand_bbt_descr *td, +			     struct nand_bbt_descr *md)  {  	/* Search the primary table */  	search_bbt(mtd, buf, td); @@ -675,23 +631,18 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt  	/* Search the mirror table */  	if (md)  		search_bbt(mtd, buf, md); - -	/* Force result check */ -	return 1;  }  /**   * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all   * - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @md:		descriptor for the bad block table mirror - * @chipsel:	selector for a specific chip, -1 for all - * - * (Re)write the bad block table - * -*/ + * (Re)write the bad block table. + */  static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,  		     int chipsel) @@ -710,14 +661,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  	ops.ooblen = mtd->oobsize;  	ops.ooboffs = 0;  	ops.datbuf = NULL; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	if (!rcode)  		rcode = 0xff; -	/* Write bad block table per chip rather than per device ? */ +	/* Write bad block table per chip rather than per device? */  	if (td->options & NAND_BBT_PERCHIP) {  		numblocks = (int)(this->chipsize >> this->bbt_erase_shift); -		/* Full device write or specific chip ? */ +		/* Full device write or specific chip? */  		if (chipsel == -1) {  			nrchips = this->numchips;  		} else { @@ -731,8 +682,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  	/* Loop through the chips */  	for (; chip < nrchips; chip++) { - -		/* There was already a version of the table, reuse the page +		/* +		 * There was already a version of the table, reuse the page  		 * This applies for absolute placement too, as we have the  		 * page nr. in td->pages.  		 */ @@ -741,8 +692,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			goto write;  		} -		/* Automatic placement of the bad block table */ -		/* Search direction top -> down ? */ +		/* +		 * Automatic placement of the bad block table. Search direction +		 * top -> down? +		 */  		if (td->options & NAND_BBT_LASTBLOCK) {  			startblock = numblocks * (chip + 1) - 1;  			dir = -1; @@ -766,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			if (!md || md->pages[chip] != page)  				goto write;  		} -		printk(KERN_ERR "No space left to write bad block table\n"); +		pr_err("No space left to write bad block table\n");  		return -ENOSPC;  	write: @@ -791,29 +744,27 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		bbtoffs = chip * (numblocks >> 2); -		to = ((loff_t) page) << this->page_shift; +		to = ((loff_t)page) << this->page_shift; -		/* Must we save the block contents ? */ +		/* Must we save the block contents? */  		if (td->options & NAND_BBT_SAVECONTENT) {  			/* Make it block aligned */ -			to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); +			to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));  			len = 1 << this->bbt_erase_shift; -			res = mtd->read(mtd, to, len, &retlen, buf); +			res = mtd_read(mtd, to, len, &retlen, buf);  			if (res < 0) {  				if (retlen != len) { -					printk(KERN_INFO "nand_bbt: Error " -					       "reading block for writing " -					       "the bad block table\n"); +					pr_info("nand_bbt: error reading block " +						"for writing the bad block table\n");  					return res;  				} -				printk(KERN_WARNING "nand_bbt: ECC error " -				       "while reading block for writing " -				       "bad block table\n"); +				pr_warn("nand_bbt: ECC error while reading " +					"block for writing bad block table\n");  			}  			/* Read oob data */  			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;  			ops.oobbuf = &buf[len]; -			res = mtd->read_oob(mtd, to + mtd->writesize, &ops); +			res = mtd_read_oob(mtd, to + mtd->writesize, &ops);  			if (res < 0 || ops.oobretlen != ops.ooblen)  				goto outerr; @@ -821,19 +772,19 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			pageoffs = page - (int)(to >> this->page_shift);  			offs = pageoffs << this->page_shift;  			/* Preset the bbt area with 0xff */ -			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); +			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));  			ooboffs = len + (pageoffs * mtd->oobsize);  		} else if (td->options & NAND_BBT_NO_OOB) {  			ooboffs = 0;  			offs = td->len; -			/* the version byte */ +			/* The version byte */  			if (td->options & NAND_BBT_VERSION)  				offs++;  			/* Calc length */ -			len = (size_t) (numblocks >> sft); +			len = (size_t)(numblocks >> sft);  			len += offs; -			/* Make it page aligned ! */ +			/* Make it page aligned! */  			len = ALIGN(len, mtd->writesize);  			/* Preset the buffer with 0xff */  			memset(buf, 0xff, len); @@ -841,8 +792,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			memcpy(buf, td->pattern, td->len);  		} else {  			/* Calc length */ -			len = (size_t) (numblocks >> sft); -			/* Make it page aligned ! */ +			len = (size_t)(numblocks >> sft); +			/* Make it page aligned! */  			len = ALIGN(len, mtd->writesize);  			/* Preset the buffer with 0xff */  			memset(buf, 0xff, len + @@ -856,13 +807,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (td->options & NAND_BBT_VERSION)  			buf[ooboffs + td->veroffs] = td->version[chip]; -		/* walk through the memory table */ +		/* Walk through the memory table */  		for (i = 0; i < numblocks;) {  			uint8_t dat;  			dat = this->bbt[bbtoffs + (i >> 2)];  			for (j = 0; j < 4; j++, i++) {  				int sftcnt = (i << (3 - sft)) & sftmsk; -				/* Do not store the reserved bbt blocks ! */ +				/* Do not store the reserved bbt blocks! */  				buf[offs + (i >> sft)] &=  					~(msk[dat & 0x03] << sftcnt);  				dat >>= 2; @@ -883,8 +834,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (res < 0)  			goto outerr; -		printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " -		       "0x%02X\n", (unsigned long long)to, td->version[chip]); +		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", +			 (unsigned long long)to, td->version[chip]);  		/* Mark it as used */  		td->pages[chip] = page; @@ -892,19 +843,18 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  	return 0;   outerr: -	printk(KERN_WARNING -	       "nand_bbt: Error while writing bad block table %d\n", res); +	pr_warn("nand_bbt: error while writing bad block table %d\n", res);  	return res;  }  /**   * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd:	MTD device structure - * @bd:		descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern   * - * The function creates a memory based bbt by scanning the device - * for manufacturer / software marked good / bad blocks -*/ + * The function creates a memory based bbt by scanning the device for + * manufacturer / software marked good / bad blocks. + */  static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  {  	struct nand_chip *this = mtd->priv; @@ -915,25 +865,24 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b  /**   * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @bd:		descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern   * - * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if necessary - * Creation is necessary if no bbt was found for the chip/device - * Update is necessary if one of the tables is missing or the - * version nr. of one table is less than the other -*/ + * The function checks the results of the previous call to read_bbt and creates + * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found + * for the chip/device. Update is necessary if one of the tables is missing or + * the version nr. of one table is less than the other. + */  static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)  { -	int i, chips, writeops, chipsel, res; +	int i, chips, writeops, create, chipsel, res, res2;  	struct nand_chip *this = mtd->priv;  	struct nand_bbt_descr *td = this->bbt_td;  	struct nand_bbt_descr *md = this->bbt_md;  	struct nand_bbt_descr *rd, *rd2; -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP)  		chips = this->numchips;  	else @@ -941,86 +890,98 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  	for (i = 0; i < chips; i++) {  		writeops = 0; +		create = 0;  		rd = NULL;  		rd2 = NULL; -		/* Per chip or per device ? */ +		res = res2 = 0; +		/* Per chip or per device? */  		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; -		/* Mirrored table available ? */ +		/* Mirrored table available? */  		if (md) {  			if (td->pages[i] == -1 && md->pages[i] == -1) { +				create = 1;  				writeops = 0x03; -				goto create; -			} - -			if (td->pages[i] == -1) { +			} else if (td->pages[i] == -1) {  				rd = md; -				td->version[i] = md->version[i]; -				writeops = 1; -				goto writecheck; -			} - -			if (md->pages[i] == -1) { +				writeops = 0x01; +			} else if (md->pages[i] == -1) {  				rd = td; -				md->version[i] = td->version[i]; -				writeops = 2; -				goto writecheck; -			} - -			if (td->version[i] == md->version[i]) { +				writeops = 0x02; +			} else if (td->version[i] == md->version[i]) {  				rd = td;  				if (!(td->options & NAND_BBT_VERSION))  					rd2 = md; -				goto writecheck; -			} - -			if (((int8_t) (td->version[i] - md->version[i])) > 0) { +			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {  				rd = td; -				md->version[i] = td->version[i]; -				writeops = 2; +				writeops = 0x02;  			} else {  				rd = md; -				td->version[i] = md->version[i]; -				writeops = 1; +				writeops = 0x01;  			} - -			goto writecheck; -  		} else {  			if (td->pages[i] == -1) { +				create = 1;  				writeops = 0x01; -				goto create; +			} else { +				rd = td; +			} +		} + +		if (create) { +			/* Create the bad block table by scanning the device? */ +			if (!(td->options & NAND_BBT_CREATE)) +				continue; + +			/* Create the table in memory by scanning the chip(s) */ +			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) +				create_bbt(mtd, buf, bd, chipsel); + +			td->version[i] = 1; +			if (md) +				md->version[i] = 1; +		} + +		/* Read back first? */ +		if (rd) { +			res = read_abs_bbt(mtd, buf, rd, chipsel); +			if (mtd_is_eccerr(res)) { +				/* Mark table as invalid */ +				rd->pages[i] = -1; +				rd->version[i] = 0; +				i--; +				continue; +			} +		} +		/* If they weren't versioned, read both */ +		if (rd2) { +			res2 = read_abs_bbt(mtd, buf, rd2, chipsel); +			if (mtd_is_eccerr(res2)) { +				/* Mark table as invalid */ +				rd2->pages[i] = -1; +				rd2->version[i] = 0; +				i--; +				continue;  			} -			rd = td; -			goto writecheck;  		} -	create: -		/* Create the bad block table by scanning the device ? */ -		if (!(td->options & NAND_BBT_CREATE)) -			continue; -		/* Create the table in memory by scanning the chip(s) */ -		if (!(this->options & NAND_CREATE_EMPTY_BBT)) -			create_bbt(mtd, buf, bd, chipsel); +		/* Scrub the flash table(s)? */ +		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) +			writeops = 0x03; -		td->version[i] = 1; -		if (md) -			md->version[i] = 1; -	writecheck: -		/* read back first ? */ -		if (rd) -			read_abs_bbt(mtd, buf, rd, chipsel); -		/* If they weren't versioned, read both. */ -		if (rd2) -			read_abs_bbt(mtd, buf, rd2, chipsel); +		/* Update version numbers before writing */ +		if (md) { +			td->version[i] = max(td->version[i], md->version[i]); +			md->version[i] = td->version[i]; +		} -		/* Write the bad block table to the device ? */ +		/* Write the bad block table to the device? */  		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {  			res = write_bbt(mtd, buf, td, md, chipsel);  			if (res < 0)  				return res;  		} -		/* Write the mirror bad block table to the device ? */ +		/* Write the mirror bad block table to the device? */  		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {  			res = write_bbt(mtd, buf, md, td, chipsel);  			if (res < 0) @@ -1032,20 +993,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  /**   * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd:	MTD device structure - * @td:		bad block table descriptor + * @mtd: MTD device structure + * @td: bad block table descriptor   * - * The bad block table regions are marked as "bad" to prevent - * accidental erasures / writes. The regions are identified by - * the mark 0x02. -*/ + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */  static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  {  	struct nand_chip *this = mtd->priv;  	int i, j, chips, block, nrblocks, update;  	uint8_t oldval, newval; -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP) {  		chips = this->numchips;  		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); @@ -1082,9 +1042,11 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  				update = 1;  			block += 2;  		} -		/* If we want reserved blocks to be recorded to flash, and some -		   new ones have been marked, then we need to update the stored -		   bbts.  This should only happen once. */ +		/* +		 * If we want reserved blocks to be recorded to flash, and some +		 * new ones have been marked, then we need to update the stored +		 * bbts.  This should only happen once. +		 */  		if (update && td->reserved_block_code)  			nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));  	} @@ -1092,8 +1054,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  /**   * verify_bbt_descr - verify the bad block description - * @mtd:	MTD device structure - * @bd:		the table to verify + * @mtd: MTD device structure + * @bd: the table to verify   *   * This functions performs a few sanity checks on the bad block description   * table. @@ -1111,16 +1073,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	pattern_len = bd->len;  	bits = bd->options & NAND_BBT_NRBITS_MSK; -	BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && -			!(this->options & NAND_USE_FLASH_BBT)); +	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && +			!(this->bbt_options & NAND_BBT_USE_FLASH));  	BUG_ON(!bits);  	if (bd->options & NAND_BBT_VERSION)  		pattern_len++;  	if (bd->options & NAND_BBT_NO_OOB) { -		BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); -		BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); +		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); +		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));  		BUG_ON(bd->offs);  		if (bd->options & NAND_BBT_VERSION)  			BUG_ON(bd->veroffs != bd->len); @@ -1140,18 +1102,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)  /**   * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd:	MTD device structure - * @bd:		descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already - * available. If not it scans the device for manufacturer - * marked good / bad blocks and writes the bad block table(s) to - * the selected place. + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern   * - * The bad block table memory is allocated here. It must be freed - * by calling the nand_free_bbt function. + * The function checks, if a bad block table(s) is/are already available. If + * not it scans the device for manufacturer marked good / bad blocks and writes + * the bad block table(s) to the selected place.   * -*/ + * The bad block table memory is allocated here. It must be freed by calling + * the nand_free_bbt function. + */  int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  {  	struct nand_chip *this = mtd->priv; @@ -1161,19 +1121,21 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	struct nand_bbt_descr *md = this->bbt_md;  	len = mtd->size >> (this->bbt_erase_shift + 2); -	/* Allocate memory (2bit per block) and clear the memory bad block table */ +	/* +	 * Allocate memory (2bit per block) and clear the memory bad block +	 * table. +	 */  	this->bbt = kzalloc(len, GFP_KERNEL); -	if (!this->bbt) { -		printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); +	if (!this->bbt)  		return -ENOMEM; -	} -	/* If no primary table decriptor is given, scan the device -	 * to build a memory based bad block table +	/* +	 * If no primary table decriptor is given, scan the device to build a +	 * memory based bad block table.  	 */  	if (!td) {  		if ((res = nand_memory_bbt(mtd, bd))) { -			printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); +			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");  			kfree(this->bbt);  			this->bbt = NULL;  		} @@ -1187,22 +1149,20 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	len += (len >> this->page_shift) * mtd->oobsize;  	buf = vmalloc(len);  	if (!buf) { -		printk(KERN_ERR "nand_bbt: Out of memory\n");  		kfree(this->bbt);  		this->bbt = NULL;  		return -ENOMEM;  	} -	/* Is the bbt at a given page ? */ +	/* Is the bbt at a given page? */  	if (td->options & NAND_BBT_ABSPAGE) { -		res = read_abs_bbts(mtd, buf, td, md); +		read_abs_bbts(mtd, buf, td, md);  	} else {  		/* Search the bad block table using a pattern in oob */ -		res = search_read_bbts(mtd, buf, td, md); +		search_read_bbts(mtd, buf, td, md);  	} -	if (res) -		res = check_create(mtd, buf, bd); +	res = check_create(mtd, buf, bd);  	/* Prevent the bbt regions from erasing / writing */  	mark_bbt_region(mtd, td); @@ -1215,15 +1175,15 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  /**   * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd:	MTD device structure - * @offs:	the offset of the newly marked block + * @mtd: MTD device structure + * @offs: the offset of the newly marked block   * - * The function updates the bad block table(s) -*/ + * The function updates the bad block table(s). + */  int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  {  	struct nand_chip *this = mtd->priv; -	int len, res = 0, writeops = 0; +	int len, res = 0;  	int chip, chipsel;  	uint8_t *buf;  	struct nand_bbt_descr *td = this->bbt_td; @@ -1236,14 +1196,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  	len = (1 << this->bbt_erase_shift);  	len += (len >> this->page_shift) * mtd->oobsize;  	buf = kmalloc(len, GFP_KERNEL); -	if (!buf) { -		printk(KERN_ERR "nand_update_bbt: Out of memory\n"); +	if (!buf)  		return -ENOMEM; -	} -	writeops = md != NULL ? 0x03 : 0x01; - -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP) {  		chip = (int)(offs >> this->chip_shift);  		chipsel = chip; @@ -1256,14 +1212,14 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  	if (md)  		md->version[chip]++; -	/* Write the bad block table to the device ? */ -	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { +	/* Write the bad block table to the device? */ +	if (td->options & NAND_BBT_WRITE) {  		res = write_bbt(mtd, buf, td, md, chipsel);  		if (res < 0)  			goto out;  	} -	/* Write the mirror bad block table to the device ? */ -	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { +	/* Write the mirror bad block table to the device? */ +	if (md && (md->options & NAND_BBT_WRITE)) {  		res = write_bbt(mtd, buf, md, td, chipsel);  	} @@ -1272,8 +1228,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  	return res;  } -/* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks. */ +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */  static uint8_t scan_ff_pattern[] = { 0xff, 0xff };  static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; @@ -1285,8 +1243,7 @@ static struct nand_bbt_descr agand_flashbased = {  	.pattern = scan_agand_pattern  }; -/* Generic flash bbt decriptors -*/ +/* Generic flash bbt descriptors */  static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };  static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1296,7 +1253,7 @@ static struct nand_bbt_descr bbt_main_descr = {  	.offs =	8,  	.len = 4,  	.veroffs = 12, -	.maxblocks = 4, +	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,  	.pattern = bbt_pattern  }; @@ -1306,55 +1263,51 @@ static struct nand_bbt_descr bbt_mirror_descr = {  	.offs =	8,  	.len = 4,  	.veroffs = 12, -	.maxblocks = 4, +	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,  	.pattern = mirror_pattern  }; -static struct nand_bbt_descr bbt_main_no_bbt_descr = { +static struct nand_bbt_descr bbt_main_no_oob_descr = {  	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE  		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP  		| NAND_BBT_NO_OOB,  	.len = 4,  	.veroffs = 4, -	.maxblocks = 4, +	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,  	.pattern = bbt_pattern  }; -static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { +static struct nand_bbt_descr bbt_mirror_no_oob_descr = {  	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE  		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP  		| NAND_BBT_NO_OOB,  	.len = 4,  	.veroffs = 4, -	.maxblocks = 4, +	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,  	.pattern = mirror_pattern  }; -#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ -		NAND_BBT_SCANBYTE1AND6) +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)  /** - * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure - * @this:	NAND chip to create descriptor for + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure + * @this: NAND chip to create descriptor for   *   * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of "this". The new descriptor is stored in + * based on the properties of @this. The new descriptor is stored in   * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when   * passed to this function. - *   */ -static int nand_create_default_bbt_descr(struct nand_chip *this) +static int nand_create_badblock_pattern(struct nand_chip *this)  {  	struct nand_bbt_descr *bd;  	if (this->badblock_pattern) { -		printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); +		pr_warn("Bad block pattern already allocated; not replacing\n");  		return -EINVAL;  	}  	bd = kzalloc(sizeof(*bd), GFP_KERNEL); -	if (!bd) { -		printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); +	if (!bd)  		return -ENOMEM; -	} -	bd->options = this->options & BBT_SCAN_OPTIONS; +	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;  	bd->offs = this->badblockpos;  	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;  	bd->pattern = scan_ff_pattern; @@ -1365,22 +1318,20 @@ static int nand_create_default_bbt_descr(struct nand_chip *this)  /**   * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd:	MTD device structure - * - * This function selects the default bad block table - * support for the device and calls the nand_scan_bbt function + * @mtd: MTD device structure   * -*/ + * This function selects the default bad block table support for the device and + * calls the nand_scan_bbt function. + */  int nand_default_bbt(struct mtd_info *mtd)  {  	struct nand_chip *this = mtd->priv; -	/* Default for AG-AND. We must use a flash based -	 * bad block table as the devices have factory marked -	 * _good_ blocks. Erasing those blocks leads to loss -	 * of the good / bad information, so we _must_ store -	 * this information in a good / bad table during -	 * startup +	/* +	 * Default for AG-AND. We must use a flash based bad block table as the +	 * devices have factory marked _good_ blocks. Erasing those blocks +	 * leads to loss of the good / bad information, so we _must_ store this +	 * information in a good / bad table during startup.  	 */  	if (this->options & NAND_IS_AND) {  		/* Use the default pattern descriptors */ @@ -1388,17 +1339,17 @@ int nand_default_bbt(struct mtd_info *mtd)  			this->bbt_td = &bbt_main_descr;  			this->bbt_md = &bbt_mirror_descr;  		} -		this->options |= NAND_USE_FLASH_BBT; +		this->bbt_options |= NAND_BBT_USE_FLASH;  		return nand_scan_bbt(mtd, &agand_flashbased);  	} -	/* Is a flash based bad block table requested ? */ -	if (this->options & NAND_USE_FLASH_BBT) { +	/* Is a flash based bad block table requested? */ +	if (this->bbt_options & NAND_BBT_USE_FLASH) {  		/* Use the default pattern descriptors */  		if (!this->bbt_td) { -			if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { -				this->bbt_td = &bbt_main_no_bbt_descr; -				this->bbt_md = &bbt_mirror_no_bbt_descr; +			if (this->bbt_options & NAND_BBT_NO_OOB) { +				this->bbt_td = &bbt_main_no_oob_descr; +				this->bbt_md = &bbt_mirror_no_oob_descr;  			} else {  				this->bbt_td = &bbt_main_descr;  				this->bbt_md = &bbt_mirror_descr; @@ -1410,18 +1361,17 @@ int nand_default_bbt(struct mtd_info *mtd)  	}  	if (!this->badblock_pattern) -		nand_create_default_bbt_descr(this); +		nand_create_badblock_pattern(this);  	return nand_scan_bbt(mtd, this->badblock_pattern);  }  /**   * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd:	MTD device structure - * @offs:	offset in the device - * @allowbbt:	allow access to bad block table region - * -*/ + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + */  int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)  {  	struct nand_chip *this = mtd->priv; diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 39535497f..f856778b5 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -71,14 +71,15 @@ const struct nand_flash_dev nand_flash_ids[] = {  	 * These are the new chips with large page size. The pagesize and the  	 * erasesize is determined from the extended id bytes  	 */ -#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR) +#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS  #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) -	/*512 Megabit */ +	/* 512 Megabit */  	{"NAND 64MiB 1,8V 8-bit",	0xA2, 0,  64, 0, LP_OPTIONS},  	{"NAND 64MiB 1,8V 8-bit",	0xA0, 0,  64, 0, LP_OPTIONS},  	{"NAND 64MiB 3,3V 8-bit",	0xF2, 0,  64, 0, LP_OPTIONS},  	{"NAND 64MiB 3,3V 8-bit",	0xD0, 0,  64, 0, LP_OPTIONS}, +	{"NAND 64MiB 3,3V 8-bit",	0xF0, 0,  64, 0, LP_OPTIONS},  	{"NAND 64MiB 1,8V 16-bit",	0xB2, 0,  64, 0, LP_OPTIONS16},  	{"NAND 64MiB 1,8V 16-bit",	0xB0, 0,  64, 0, LP_OPTIONS16},  	{"NAND 64MiB 3,3V 16-bit",	0xC2, 0,  64, 0, LP_OPTIONS16}, @@ -157,9 +158,7 @@ const struct nand_flash_dev nand_flash_ids[] = {  	 * writes possible, but not implemented now  	 */  	{"AND 128MiB 3,3V 8-bit",	0x01, 2048, 128, 0x4000, -	 NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | -	 BBT_AUTO_REFRESH -	}, +	 NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},  	{NULL,}  }; @@ -176,6 +175,9 @@ const struct nand_manufacturers nand_manuf_ids[] = {  	{NAND_MFR_STMICRO, "ST Micro"},  	{NAND_MFR_HYNIX, "Hynix"},  	{NAND_MFR_MICRON, "Micron"}, -	{NAND_MFR_AMD, "AMD"}, +	{NAND_MFR_AMD, "AMD/Spansion"}, +	{NAND_MFR_MACRONIX, "Macronix"}, +	{NAND_MFR_EON, "Eon"},  	{0x0, "Unknown"}  }; + diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 4727f9c98..1d22b5240 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -120,8 +120,12 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)  		WATCHDOG_RESET(); +		if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { +			puts("Size of erase exceeds limit\n"); +			return -EFBIG; +		}  		if (!opts->scrub && bbtest) { -			int ret = meminfo->block_isbad(meminfo, erase.addr); +			int ret = mtd_block_isbad(meminfo, erase.addr);  			if (ret > 0) {  				if (!opts->quiet)  					printf("\rSkipping bad block at  " @@ -144,7 +148,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)  		erased_length++; -		result = meminfo->erase(meminfo, &erase); +		result = mtd_erase(meminfo, &erase);  		if (result != 0) {  			printf("\n%s: MTD Erase failure: %d\n",  			       mtd_device, result); @@ -153,15 +157,16 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)  		/* format for JFFS2 ? */  		if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) { -			chip->ops.ooblen = 8; -			chip->ops.datbuf = NULL; -			chip->ops.oobbuf = (uint8_t *)&cleanmarker; -			chip->ops.ooboffs = 0; -			chip->ops.mode = MTD_OOB_AUTO; +			struct mtd_oob_ops ops; +			ops.ooblen = 8; +			ops.datbuf = NULL; +			ops.oobbuf = (uint8_t *)&cleanmarker; +			ops.ooboffs = 0; +			ops.mode = MTD_OPS_AUTO_OOB; -			result = meminfo->write_oob(meminfo, +			result = mtd_write_oob(meminfo,  			                            erase.addr, -			                            &chip->ops); +			                            &ops);  			if (result != 0) {  				printf("\n%s: MTD writeoob failure: %d\n",  				       mtd_device, result); @@ -458,7 +463,8 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length,  static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,  			const size_t *len)  { -	size_t i, l = *len; +	size_t l = *len; +	ssize_t i;  	for (i = l - 1; i >= 0; i--)  		if (buf[i] != 0xFF) @@ -604,7 +610,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,  			ops.len = pagesize;  			ops.ooblen = nand->oobsize; -			ops.mode = MTD_OOB_AUTO; +			ops.mode = MTD_OPS_AUTO_OOB;  			ops.ooboffs = 0;  			pages = write_size / pagesize_oob; @@ -614,7 +620,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,  				ops.datbuf = p_buffer;  				ops.oobbuf = ops.datbuf + pagesize; -				rval = nand->write_oob(nand, offset, &ops); +				rval = mtd_write_oob(nand, offset, &ops);  				if (rval != 0)  					break; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 213d2c945..94b90332d 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -216,6 +216,7 @@ int board_nand_init(struct nand_chip *nand)  	nand->ecc.mode = NAND_ECC_HW;  	nand->ecc.size = 256;  	nand->ecc.bytes = 3; +	nand->ecc.strength = 1;  	nand->select_chip = ndfc_select_chip;  #ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT diff --git a/drivers/mtd/nand/nomadik.c b/drivers/mtd/nand/nomadik.c index b76f4cbb5..dc8e51373 100644 --- a/drivers/mtd/nand/nomadik.c +++ b/drivers/mtd/nand/nomadik.c @@ -212,6 +212,7 @@ int board_nand_init(struct nand_chip *chip)  	chip->ecc.mode = NAND_ECC_HW;  	chip->ecc.bytes = 3;  	chip->ecc.size = 512; +	chip->ecc.strength = 1;  	chip->ecc.layout = &nomadik_ecc_layout;  	chip->ecc.calculate = nomadik_ecc_calculate;  	chip->ecc.hwctl = nomadik_ecc_hwctl; diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index bc1bcad3b..5d088227e 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -590,11 +590,12 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data + * @oob_required: caller expects OOB data read to chip->oob_poi   * @page:	page number to read   *   */  static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, -				uint8_t *buf, int page) +				uint8_t *buf, int oob_required, int page)  {  	int i, eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -804,6 +805,7 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)  	nand->ecc.hwctl = NULL;  	nand->ecc.correct = NULL;  	nand->ecc.calculate = NULL; +	nand->ecc.strength = eccstrength;  	/* Setup the ecc configurations again */  	if (hardware) { @@ -901,7 +903,7 @@ int board_nand_init(struct nand_chip *nand)  	nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;  	nand->cmd_ctrl = omap_nand_hwcontrol; -	nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR; +	nand->options = NAND_NO_PADDING | NAND_CACHEPRG;  	/* If we are 16 bit dev, our gpmc config tells us that */  	if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)  		nand->options |= NAND_BUSWIDTH_16; @@ -934,6 +936,7 @@ int board_nand_init(struct nand_chip *nand)  	nand->ecc.layout = &hw_bch8_nand_oob;  	nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;  	nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; +	nand->ecc.strength = 8;  	nand->ecc.hwctl = omap_enable_ecc_bch;  	nand->ecc.correct = omap_correct_data_bch;  	nand->ecc.calculate = omap_calculate_ecc_bch; @@ -952,6 +955,7 @@ int board_nand_init(struct nand_chip *nand)  	nand->ecc.hwctl = omap_enable_hwecc;  	nand->ecc.correct = omap_correct_data;  	nand->ecc.calculate = omap_calculate_ecc; +	nand->ecc.strength = 1;  	omap_hwecc_init(nand);  #endif  #endif diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c index e1a459b00..1187b9fee 100644 --- a/drivers/mtd/nand/s3c2410_nand.c +++ b/drivers/mtd/nand/s3c2410_nand.c @@ -173,14 +173,13 @@ int board_nand_init(struct nand_chip *nand)  	nand->ecc.mode = NAND_ECC_HW;  	nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;  	nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; +	nand->ecc.strength = 1;  #else  	nand->ecc.mode = NAND_ECC_SOFT;  #endif  #ifdef CONFIG_S3C2410_NAND_BBT -	nand->options = NAND_USE_FLASH_BBT; -#else -	nand->options = 0; +	nand->bbt_options |= NAND_BBT_USE_FLASH;  #endif  	debug("end of nand_init\n"); diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index 4d94cc6f5..6afbec61e 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -707,7 +707,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,   *		-EIO when command timeout   */  static int nand_read_page_hwecc(struct mtd_info *mtd, -	struct nand_chip *chip, uint8_t *buf, int page) +	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)  {  	return nand_rw_page(mtd, chip, buf, page, 1, 0);  } @@ -719,8 +719,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd,   * @param chip	nand chip info structure   * @param buf	data buffer   */ -static void nand_write_page_hwecc(struct mtd_info *mtd, -	struct nand_chip *chip, const uint8_t *buf) +static int nand_write_page_hwecc(struct mtd_info *mtd, +	struct nand_chip *chip, const uint8_t *buf, int oob_required)  {  	int page;  	struct nand_drv *info; @@ -731,6 +731,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd,  		(readl(&info->reg->addr_reg2) << 16);  	nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1); +	return 0;  } @@ -746,7 +747,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd,   *		-EIO when command timeout   */  static int nand_read_page_raw(struct mtd_info *mtd, -	struct nand_chip *chip, uint8_t *buf, int page) +	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)  {  	return nand_rw_page(mtd, chip, buf, page, 0, 0);  } @@ -758,8 +759,8 @@ static int nand_read_page_raw(struct mtd_info *mtd,   * @param chip	nand chip info structure   * @param buf	data buffer   */ -static void nand_write_page_raw(struct mtd_info *mtd, -		struct nand_chip *chip,	const uint8_t *buf) +static int nand_write_page_raw(struct mtd_info *mtd, +		struct nand_chip *chip,	const uint8_t *buf, int oob_required)  {  	int page;  	struct nand_drv *info; @@ -769,6 +770,7 @@ static void nand_write_page_raw(struct mtd_info *mtd,  		(readl(&info->reg->addr_reg2) << 16);  	nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1); +	return 0;  }  /** @@ -873,19 +875,13 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,   * @param mtd		mtd info structure   * @param chip		nand chip info structure   * @param page		page number to read - * @param sndcmd	flag whether to issue read command or not - * @return	1 - issue read command next time - *		0 - not to issue   */  static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, -	int page, int sndcmd) +	int page)  { -	if (sndcmd) { -		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -		sndcmd = 0; -	} +	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);  	nand_rw_oob(mtd, chip, page, 0, 0); -	return sndcmd; +	return 0;  }  /** @@ -1018,6 +1014,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)  	nand->ecc.write_page_raw = nand_write_page_raw;  	nand->ecc.read_oob = nand_read_oob;  	nand->ecc.write_oob = nand_write_oob; +	nand->ecc.strength = 1;  	nand->select_chip = nand_select_chip;  	nand->dev_ready  = nand_dev_ready;  	nand->priv = &nand_ctrl; diff --git a/drivers/mtd/nand/tegra_nand.h b/drivers/mtd/nand/tegra_nand.h index 7e74be75f..622b86980 100644 --- a/drivers/mtd/nand/tegra_nand.h +++ b/drivers/mtd/nand/tegra_nand.h @@ -224,7 +224,7 @@ enum {  #define BCH_DEC_STATUS_MAX_CORR_CNT_MASK	(0x1f << 8)  #define BCH_DEC_STATUS_PAGE_NUMBER_MASK		0xFF -#define LP_OPTIONS (NAND_NO_READRDY | NAND_NO_AUTOINCR) +#define LP_OPTIONS	0  struct nand_ctlr {  	u32	command;	/* offset 00h */ diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 858e32274..ddfe7e7c7 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -743,7 +743,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 @@ -807,7 +807,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 */ @@ -847,7 +847,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (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; @@ -914,7 +914,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, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -929,7 +929,7 @@ static int onenand_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;  		} @@ -950,7 +950,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;  		}  	} @@ -987,7 +987,7 @@ 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; @@ -998,7 +998,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,  	/* 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; @@ -1041,7 +1041,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,  			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, 0, ONENAND_SPARERAM, buf, column, thislen); @@ -1115,10 +1115,10 @@ 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; @@ -1337,7 +1337,7 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,  #define NOTALIGNED(x)	((x & (this->subpagesize - 1)) != 0)  /** - * 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 @@ -1404,19 +1404,13 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  	ops->retlen = 0;  	ops->oobretlen = 0; -	/* Do not allow writes past end of device */ -	if (unlikely((to + len) > mtd->size)) { -		printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n"); -		return -EINVAL; -	} -  	/* Reject writes, which are not page aligned */  	if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {  		printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");  		return -EINVAL;  	} -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1450,7 +1444,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); @@ -1502,7 +1496,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 @@ -1521,7 +1515,7 @@ 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; @@ -1530,7 +1524,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,  	/* 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; @@ -1571,7 +1565,7 @@ 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); @@ -1661,10 +1655,10 @@ 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; @@ -1720,13 +1714,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)  	MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",  			(unsigned int) addr, len); -	/* Do not allow erase past end of device */ -	if (unlikely((len + addr) > mtd->size)) { -		MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:" -					"Erase past end of device\n"); -		return -EINVAL; -	} -  	if (FLEXONENAND(this)) {  		/* Find the eraseregion of this address */  		i = flexonenand_region(mtd, addr); @@ -1762,8 +1749,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)  		return -EINVAL;  	} -	instr->fail_addr = 0xffffffff; -  	/* Grab the lock and see if the device is available */  	onenand_get_device(mtd, FL_ERASING); @@ -1889,7 +1874,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, @@ -1915,7 +1900,6 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)   */  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); @@ -1926,7 +1910,7 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)  		return ret;  	} -	ret = this->block_markbad(mtd, ofs); +	ret = mtd_block_markbad(mtd, ofs);  	return ret;  } @@ -2386,7 +2370,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd,  	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, @@ -2645,14 +2629,14 @@ int onenand_probe(struct mtd_info *mtd)  		mtd->size = this->chipsize;  	mtd->flags = MTD_CAP_NANDFLASH; -	mtd->erase = onenand_erase; -	mtd->read = onenand_read; -	mtd->write = onenand_write; -	mtd->read_oob = onenand_read_oob; -	mtd->write_oob = onenand_write_oob; -	mtd->sync = onenand_sync; -	mtd->block_isbad = onenand_block_isbad; -	mtd->block_markbad = onenand_block_markbad; +	mtd->_erase = onenand_erase; +	mtd->_read = onenand_read; +	mtd->_write = onenand_write; +	mtd->_read_oob = onenand_read_oob; +	mtd->_write_oob = onenand_write_oob; +	mtd->_sync = onenand_sync; +	mtd->_block_isbad = onenand_block_isbad; +	mtd->_block_markbad = onenand_block_markbad;  	return 0;  } diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 9d5da5470..0267c2c5c 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -87,7 +87,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,  	startblock = 0;  	from = 0; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooblen = readlen;  	ops.oobbuf = buf;  	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -200,10 +200,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	len = this->chipsize >> (this->erase_shift + 2);  	/* Allocate memory (2bit per block) */  	bbm->bbt = malloc(len); -	if (!bbm->bbt) { -		printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); +	if (!bbm->bbt)  		return -ENOMEM; -	}  	/* Clear the memory bad block table */  	memset(bbm->bbt, 0x00, len); diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index dad30b54c..3ec2151b3 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -90,18 +90,32 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = {  		.name = "S25FL032P",  	},  	{ +		.idcode1 = 0x0216, +		.idcode2 = 0x4d00, +		.pages_per_sector = 256, +		.nr_sectors = 128, +		.name = "S25FL064P", +	}, +	{  		.idcode1 = 0x2018,  		.idcode2 = 0x4d01,  		.pages_per_sector = 256,  		.nr_sectors = 256, -		.name = "S25FL129P_64K/S25FL128S", +		.name = "S25FL129P_64K/S25FL128S_64K",  	},  	{  		.idcode1 = 0x0219,  		.idcode2 = 0x4d01,  		.pages_per_sector = 256,  		.nr_sectors = 512, -		.name = "S25FL256S", +		.name = "S25FL256S_64K", +	}, +	{ +		.idcode1 = 0x0220, +		.idcode2 = 0x4d01, +		.pages_per_sector = 256, +		.nr_sectors = 1024, +		.name = "S25FL512S_64K",  	},  }; diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 6507aa34b..6a6fe37e0 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -68,17 +68,60 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,  	return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);  } -int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, -		size_t len, const void *buf) +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)  { -	unsigned long page_addr, byte_addr, page_size; -	size_t chunk_len, actual; +	struct spi_slave *spi = flash->spi; +	unsigned long timebase;  	int ret; -	u8 cmd[4]; +	u8 status; +	u8 check_status = 0x0; +	u8 poll_bit = STATUS_WIP; +	u8 cmd = flash->poll_cmd; -	page_size = flash->page_size; -	page_addr = offset / page_size; -	byte_addr = offset % page_size; +	if (cmd == CMD_FLAG_STATUS) { +		poll_bit = STATUS_PEC; +		check_status = poll_bit; +	} + +	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); +	if (ret) { +		debug("SF: fail to read %s status register\n", +			cmd == CMD_READ_STATUS ? "read" : "flag"); +		return ret; +	} + +	timebase = get_timer(0); +	do { +		WATCHDOG_RESET(); + +		ret = spi_xfer(spi, 8, NULL, &status, 0); +		if (ret) +			return -1; + +		if ((status & poll_bit) == check_status) +			break; + +	} while (get_timer(timebase) < timeout); + +	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + +	if ((status & poll_bit) == check_status) +		return 0; + +	/* Timed out */ +	debug("SF: time out!\n"); +	return -1; +} + +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, +		size_t cmd_len, const void *buf, size_t buf_len) +{ +	struct spi_slave *spi = flash->spi; +	unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; +	int ret; + +	if (buf == NULL) +		timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;  	ret = spi_claim_bus(flash->spi);  	if (ret) { @@ -86,48 +129,122 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,  		return ret;  	} +	ret = spi_flash_cmd_write_enable(flash); +	if (ret < 0) { +		debug("SF: enabling write failed\n"); +		return ret; +	} + +	ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); +	if (ret < 0) { +		debug("SF: write cmd failed\n"); +		return ret; +	} + +	ret = spi_flash_cmd_wait_ready(flash, timeout); +	if (ret < 0) { +		debug("SF: write %s timed out\n", +			timeout == SPI_FLASH_PROG_TIMEOUT ? +			"program" : "page erase"); +		return ret; +	} + +	spi_release_bus(spi); + +	return ret; +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +{ +	u32 erase_size; +	u8 cmd[4]; +	int ret = -1; + +	erase_size = flash->sector_size; +	if (offset % erase_size || len % erase_size) { +		debug("SF: Erase offset/length not multiple of erase size\n"); +		return -1; +	} + +	if (erase_size == 4096) +		cmd[0] = CMD_ERASE_4K; +	else +		cmd[0] = CMD_ERASE_64K; + +	while (len) { +#ifdef CONFIG_SPI_FLASH_BAR +		u8 bank_sel; + +		bank_sel = offset / SPI_FLASH_16MB_BOUN; + +		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); +		if (ret) { +			debug("SF: fail to set bank%d\n", bank_sel); +			return ret; +		} +#endif +		spi_flash_addr(offset, cmd); + +		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], +		      cmd[2], cmd[3], offset); + +		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); +		if (ret < 0) { +			debug("SF: erase failed\n"); +			break; +		} + +		offset += erase_size; +		len -= erase_size; +	} + +	return ret; +} + +int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, +		size_t len, const void *buf) +{ +	unsigned long byte_addr, page_size; +	size_t chunk_len, actual; +	u8 cmd[4]; +	int ret = -1; + +	page_size = flash->page_size; +  	cmd[0] = CMD_PAGE_PROGRAM;  	for (actual = 0; actual < len; actual += chunk_len) { +#ifdef CONFIG_SPI_FLASH_BAR +		u8 bank_sel; + +		bank_sel = offset / SPI_FLASH_16MB_BOUN; + +		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); +		if (ret) { +			debug("SF: fail to set bank%d\n", bank_sel); +			return ret; +		} +#endif +		byte_addr = offset % page_size;  		chunk_len = min(len - actual, page_size - byte_addr);  		if (flash->spi->max_write_size)  			chunk_len = min(chunk_len, flash->spi->max_write_size); -		cmd[1] = page_addr >> 8; -		cmd[2] = page_addr; -		cmd[3] = byte_addr; +		spi_flash_addr(offset, cmd);  		debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",  		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); -		ret = spi_flash_cmd_write_enable(flash); -		if (ret < 0) { -			debug("SF: enabling write failed\n"); -			break; -		} - -		ret = spi_flash_cmd_write(flash->spi, cmd, 4, -					  buf + actual, chunk_len); +		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), +					buf + actual, chunk_len);  		if (ret < 0) {  			debug("SF: write failed\n");  			break;  		} -		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); -		if (ret) -			break; - -		byte_addr += chunk_len; -		if (byte_addr == page_size) { -			page_addr++; -			byte_addr = 0; -		} +		offset += chunk_len;  	} -	debug("SF: program %s %zu bytes @ %#x\n", -	      ret ? "failure" : "success", len, offset); - -	spi_release_bus(flash->spi);  	return ret;  } @@ -137,8 +254,18 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,  	struct spi_slave *spi = flash->spi;  	int ret; -	spi_claim_bus(spi); +	ret = spi_claim_bus(flash->spi); +	if (ret) { +		debug("SF: unable to claim SPI bus\n"); +		return ret; +	} +  	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); +	if (ret < 0) { +		debug("SF: read cmd failed\n"); +		return ret; +	} +  	spi_release_bus(spi);  	return ret; @@ -147,140 +274,125 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,  		size_t len, void *data)  { -	u8 cmd[5]; +	u8 cmd[5], bank_sel = 0; +	u32 remain_len, read_len; +	int ret = -1;  	/* Handle memory-mapped SPI */ -	if (flash->memory_map) +	if (flash->memory_map) {  		memcpy(data, flash->memory_map + offset, len); +		return 0; +	}  	cmd[0] = CMD_READ_ARRAY_FAST; -	spi_flash_addr(offset, cmd);  	cmd[4] = 0x00; -	return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len); -} +	while (len) { +#ifdef CONFIG_SPI_FLASH_BAR +		bank_sel = offset / SPI_FLASH_16MB_BOUN; -int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, -			   u8 cmd, u8 poll_bit) -{ -	struct spi_slave *spi = flash->spi; -	unsigned long timebase; -	int ret; -	u8 status; - -	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); -	if (ret) { -		debug("SF: Failed to send command %02x: %d\n", cmd, ret); -		return ret; -	} - -	timebase = get_timer(0); -	do { -		WATCHDOG_RESET(); +		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); +		if (ret) { +			debug("SF: fail to set bank%d\n", bank_sel); +			return ret; +		} +#endif +		remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); +		if (len < remain_len) +			read_len = len; +		else +			read_len = remain_len; -		ret = spi_xfer(spi, 8, NULL, &status, 0); -		if (ret) -			return -1; +		spi_flash_addr(offset, cmd); -		if ((status & poll_bit) == 0) +		ret = spi_flash_read_common(flash, cmd, sizeof(cmd), +							data, read_len); +		if (ret < 0) { +			debug("SF: read failed\n");  			break; +		} -	} while (get_timer(timebase) < timeout); - -	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - -	if ((status & poll_bit) == 0) -		return 0; - -	/* Timed out */ -	debug("SF: time out!\n"); -	return -1; -} +		offset += read_len; +		len -= read_len; +		data += read_len; +	} -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ -	return spi_flash_cmd_poll_bit(flash, timeout, -		CMD_READ_STATUS, STATUS_WIP); +	return ret;  } -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)  { -	u32 start, end, erase_size; +	u8 cmd;  	int ret; -	u8 cmd[4]; - -	erase_size = flash->sector_size; -	if (offset % erase_size || len % erase_size) { -		debug("SF: Erase offset/length not multiple of erase size\n"); -		return -1; -	} -	ret = spi_claim_bus(flash->spi); -	if (ret) { -		debug("SF: Unable to claim SPI bus\n"); +	cmd = CMD_WRITE_STATUS; +	ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); +	if (ret < 0) { +		debug("SF: fail to write status register\n");  		return ret;  	} -	if (erase_size == 4096) -		cmd[0] = CMD_ERASE_4K; -	else -		cmd[0] = CMD_ERASE_64K; -	start = offset; -	end = start + len; - -	while (offset < end) { -		spi_flash_addr(offset, cmd); -		offset += erase_size; - -		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], -		      cmd[2], cmd[3], offset); - -		ret = spi_flash_cmd_write_enable(flash); -		if (ret) -			goto out; - -		ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); -		if (ret) -			goto out; - -		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); -		if (ret) -			goto out; -	} - -	debug("SF: Successfully erased %zu bytes @ %#x\n", len, start); - - out: -	spi_release_bus(flash->spi); -	return ret; +	return 0;  } -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +#ifdef CONFIG_SPI_FLASH_BAR +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)  {  	u8 cmd;  	int ret; -	ret = spi_flash_cmd_write_enable(flash); +	if (flash->bank_curr == bank_sel) { +		debug("SF: not require to enable bank%d\n", bank_sel); +		return 0; +	} + +	cmd = flash->bank_write_cmd; +	ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);  	if (ret < 0) { -		debug("SF: enabling write failed\n"); +		debug("SF: fail to write bank register\n");  		return ret;  	} +	flash->bank_curr = bank_sel; -	cmd = CMD_WRITE_STATUS; -	ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &sr, 1); -	if (ret) { -		debug("SF: fail to write status register\n"); -		return ret; +	return 0; +} + +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) +{ +	u8 cmd; +	u8 curr_bank = 0; + +	/* discover bank cmds */ +	switch (idcode0) { +	case SPI_FLASH_SPANSION_IDCODE0: +		flash->bank_read_cmd = CMD_BANKADDR_BRRD; +		flash->bank_write_cmd = CMD_BANKADDR_BRWR; +		break; +	case SPI_FLASH_STMICRO_IDCODE0: +	case SPI_FLASH_WINBOND_IDCODE0: +		flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; +		flash->bank_write_cmd = CMD_EXTNADDR_WREAR; +		break; +	default: +		printf("SF: Unsupported bank commands %02x\n", idcode0); +		return -1;  	} -	ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); -	if (ret < 0) { -		debug("SF: write status register timed out\n"); -		return ret; +	/* read the bank reg - on which bank the flash is in currently */ +	cmd = flash->bank_read_cmd; +	if (flash->size > SPI_FLASH_16MB_BOUN) { +		if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { +			debug("SF: fail to read bank addr register\n"); +			return -1; +		} +		flash->bank_curr = curr_bank; +	} else { +		flash->bank_curr = curr_bank;  	}  	return 0;  } +#endif  #ifdef CONFIG_OF_CONTROL  int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) @@ -429,6 +541,13 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,  		goto err_manufacturer_probe;  	} +#ifdef CONFIG_SPI_FLASH_BAR +	/* Configure the BAR - disover bank cmds and read current bank  */ +	ret = spi_flash_bank_config(flash, *idp); +	if (ret < 0) +		goto err_manufacturer_probe; +#endif +  #ifdef CONFIG_OF_CONTROL  	if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {  		debug("SF: FDT decode error\n"); @@ -441,6 +560,12 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,  	if (flash->memory_map)  		printf(", mapped at %p", flash->memory_map);  	puts("\n"); +#ifndef CONFIG_SPI_FLASH_BAR +	if (flash->size > SPI_FLASH_16MB_BOUN) { +		puts("SF: Warning - Only lower 16MiB accessible,"); +		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); +	} +#endif  	spi_release_bus(spi); @@ -471,6 +596,7 @@ void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi,  	/* Set up some basic fields - caller will sort out sizes */  	flash->spi = spi;  	flash->name = name; +	flash->poll_cmd = CMD_READ_STATUS;  	flash->read = spi_flash_cmd_read_fast;  	flash->write = spi_flash_cmd_write_multi; diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index e0afbc3d8..af1afa96c 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -22,14 +22,31 @@  #define CMD_PAGE_PROGRAM		0x02  #define CMD_WRITE_DISABLE		0x04  #define CMD_READ_STATUS			0x05 +#define CMD_FLAG_STATUS			0x70  #define CMD_WRITE_ENABLE		0x06  #define CMD_ERASE_4K			0x20  #define CMD_ERASE_32K			0x52  #define CMD_ERASE_64K			0xd8  #define CMD_ERASE_CHIP			0xc7 +#define SPI_FLASH_16MB_BOUN		0x1000000 + +/* Manufacture ID's */ +#define SPI_FLASH_SPANSION_IDCODE0	0x01 +#define SPI_FLASH_STMICRO_IDCODE0	0x20 +#define SPI_FLASH_WINBOND_IDCODE0	0xef + +#ifdef CONFIG_SPI_FLASH_BAR +/* Bank addr access commands */ +# define CMD_BANKADDR_BRWR		0x17 +# define CMD_BANKADDR_BRRD		0x16 +# define CMD_EXTNADDR_WREAR		0xC5 +# define CMD_EXTNADDR_RDEAR		0xC8 +#endif +  /* Common status */  #define STATUS_WIP			0x01 +#define STATUS_PEC			0x80  /* Send a single-byte command to the device and read the response */  int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); @@ -77,16 +94,30 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)  /* Program the status register. */  int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); +#ifdef CONFIG_SPI_FLASH_BAR +/* Program the bank address register */ +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel); + +/* Configure the BAR - discover the bank cmds */ +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0); +#endif +  /*   * Same as spi_flash_cmd_read() except it also claims/releases the SPI   * bus. Used as common part of the ->read() operation.   */  int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,  		size_t cmd_len, void *data, size_t data_len); - -/* Send a command to the device and wait for some bit to clear itself. */ -int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, -			   u8 cmd, u8 poll_bit); +/* + * Used for spi_flash write operation + * - SPI claim + * - spi_flash_cmd_write_enable + * - spi_flash_cmd_write + * - spi_flash_cmd_wait_ready + * - SPI release + */ +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, +		size_t cmd_len, const void *buf, size_t buf_len);  /*   * Send the read status command to the device and wait for the wip diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 2a9972bd4..7e41ee132 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -140,6 +140,30 @@ static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {  		.nr_sectors = 512,  		.name = "N25Q256A",  	}, +	{ +		.id = 0xba20, +		.pages_per_sector = 256, +		.nr_sectors = 1024, +		.name = "N25Q512", +	}, +	{ +		.id = 0xbb20, +		.pages_per_sector = 256, +		.nr_sectors = 1024, +		.name = "N25Q512A", +	}, +	{ +		.id = 0xba21, +		.pages_per_sector = 256, +		.nr_sectors = 2048, +		.name = "N25Q1024", +	}, +	{ +		.id = 0xbb21, +		.pages_per_sector = 256, +		.nr_sectors = 2048, +		.name = "N25Q1024A", +	},  };  struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) @@ -186,5 +210,9 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)  	flash->sector_size = 256 * params->pages_per_sector;  	flash->size = flash->sector_size * params->nr_sectors; +	/* for >= 512MiB flashes, use flag status instead of read_status */ +	if (flash->size >= 0x4000000) +		flash->poll_cmd = CMD_FLAG_STATUS; +  	return flash;  } diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 27162091c..c399bf14d 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -18,6 +18,21 @@ struct winbond_spi_flash_params {  static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {  	{ +		.id			= 0x2014, +		.nr_blocks		= 16, +		.name			= "W25P80", +	}, +	{ +		.id			= 0x2015, +		.nr_blocks		= 32, +		.name			= "W25P16", +	}, +	{ +		.id			= 0x2016, +		.nr_blocks		= 64, +		.name			= "W25P32", +	}, +	{  		.id			= 0x3013,  		.nr_blocks		= 8,  		.name			= "W25X40", @@ -40,42 +55,57 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {  	{  		.id			= 0x4014,  		.nr_blocks		= 16, -		.name			= "W25Q80BL", +		.name			= "W25Q80BL/W25Q80BV",  	},  	{  		.id			= 0x4015,  		.nr_blocks		= 32, -		.name			= "W25Q16", +		.name			= "W25Q16CL/W25Q16DV",  	},  	{  		.id			= 0x4016,  		.nr_blocks		= 64, -		.name			= "W25Q32", +		.name			= "W25Q32BV/W25Q32FV_SPI",  	},  	{  		.id			= 0x4017,  		.nr_blocks		= 128, -		.name			= "W25Q64", +		.name			= "W25Q64CV/W25Q64FV_SPI",  	},  	{  		.id			= 0x4018,  		.nr_blocks		= 256, -		.name			= "W25Q128", +		.name			= "W25Q128BV/W25Q128FV_SPI", +	}, +	{ +		.id			= 0x4019, +		.nr_blocks		= 512, +		.name			= "W25Q256",  	},  	{  		.id			= 0x5014, -		.nr_blocks		= 128, -		.name			= "W25Q80", +		.nr_blocks		= 16, +		.name			= "W25Q80BW", +	}, +	{ +		.id			= 0x6015, +		.nr_blocks		= 32, +		.name			= "W25Q16DW",  	},  	{  		.id			= 0x6016, -		.nr_blocks		= 512, -		.name			= "W25Q32DW", +		.nr_blocks		= 64, +		.name			= "W25Q32DW/W25Q32FV_QPI",  	},  	{  		.id			= 0x6017,  		.nr_blocks		= 128, -		.name			= "W25Q64DW", +		.name			= "W25Q64DW/W25Q64FV_QPI", +	}, +	{ +		.id			= 0x6018, +		.nr_blocks		= 256, +		.name			= "W25Q128FW/W25Q128FV_QPI",  	},  }; @@ -104,7 +134,7 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)  	}  	flash->page_size = 256; -	flash->sector_size = 4096; +	flash->sector_size = (idcode[1] == 0x20) ? 65536 : 4096;  	flash->size = 4096 * 16 * params->nr_blocks;  	return flash; diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index a708162e4..25888220d 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -539,7 +539,7 @@ static int io_init(struct ubi_device *ubi)  	ubi->peb_count  = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);  	ubi->flash_size = ubi->mtd->size; -	if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) +	if (mtd_can_have_bb(ubi->mtd))  		ubi->bad_allowed = 1;  	ubi->min_io_size = ubi->mtd->writesize; diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index d523c94b1..d2d3c9c58 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -460,7 +460,7 @@ retry:  		if (err == UBI_IO_BITFLIPS) {  			scrub = 1;  			err = 0; -		} else if (err == -EBADMSG) { +		} else if (mtd_is_eccerr(err)) {  			if (vol->vol_type == UBI_DYNAMIC_VOLUME)  				goto out_unlock;  			scrub = 1; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 842389400..05de9aeb6 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -154,7 +154,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,  	addr = (loff_t)pnum * ubi->peb_size + offset;  retry: -	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); +	err = mtd_read(ubi->mtd, addr, len, &read, buf);  	if (err) {  		if (err == -EUCLEAN) {  			/* @@ -268,7 +268,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,  	}  	addr = (loff_t)pnum * ubi->peb_size + offset; -	err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); +	err = mtd_write(ubi->mtd, addr, len, &written, buf);  	if (err) {  		ubi_err("error %d while writing %d bytes to PEB %d:%d, written"  			" %zd bytes", err, len, pnum, offset, written); @@ -318,7 +318,7 @@ retry:  	ei.callback = erase_callback;  	ei.priv     = (unsigned long)&wq; -	err = ubi->mtd->erase(ubi->mtd, &ei); +	err = mtd_erase(ubi->mtd, &ei);  	if (err) {  		if (retries++ < UBI_IO_RETRIES) {  			dbg_io("error %d while erasing PEB %d, retry", @@ -516,7 +516,7 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum)  	if (ubi->bad_allowed) {  		int ret; -		ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size); +		ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size);  		if (ret < 0)  			ubi_err("error %d while checking if PEB %d is bad",  				ret, pnum); @@ -551,7 +551,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)  	if (!ubi->bad_allowed)  		return 0; -	err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size); +	err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size);  	if (err)  		ubi_err("cannot mark PEB %d bad, error %d", pnum, err);  	return err; @@ -1242,7 +1242,7 @@ static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,  	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;  	mutex_lock(&ubi->dbg_buf_mutex); -	err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); +	err = mtd_read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);  	if (err && err != -EUCLEAN) {  		ubi_err("error %d while reading %d bytes from PEB %d:%d, "  			"read %zd bytes", err, len, pnum, offset, read); diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 423d47915..e55318879 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -349,7 +349,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,  		return 0;  	err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); -	if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { +	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {  		ubi_warn("mark volume %d as corrupted", vol_id);  		vol->corrupted = 1;  	} diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index a6410bfb6..e8660d997 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -82,7 +82,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)  		err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);  		if (err) { -			if (err == -EBADMSG) +			if (mtd_is_eccerr(err))  				err = 1;  			break;  		} diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index f679f0649..29d232001 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -388,7 +388,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,  		err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,  				       ubi->vtbl_size); -		if (err == UBI_IO_BITFLIPS || err == -EBADMSG) +		if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))  			/*  			 * Scrub the PEB later. Note, -EBADMSG indicates an  			 * uncorrectable ECC error, but we have our own CRC and |