mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	mtd: nand: add lock/unlock routines
Add nand lock / unlock routines. At least 'micron' parts support this. Signed-off-by: Vimal Singh <vimalsingh@ti.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
		
							parent
							
								
									6fe5a6acdc
								
							
						
					
					
						commit
						7d70f334ad
					
				| @ -863,6 +863,168 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * __nand_unlock - [REPLACABLE] unlocks specified locked blockes | ||||
|  * | ||||
|  * @param mtd - mtd info | ||||
|  * @param ofs - offset to start unlock from | ||||
|  * @param len - length to unlock | ||||
|  * @invert -  when = 0, unlock the range of blocks within the lower and | ||||
|  *                      upper boundary address | ||||
|  *            whne = 1, unlock the range of blocks outside the boundaries | ||||
|  *                      of the lower and upper boundary address | ||||
|  * | ||||
|  * @return - unlock status | ||||
|  */ | ||||
| static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, | ||||
| 					uint64_t len, int invert) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int status, page; | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 
 | ||||
| 	/* Submit address of first page to unlock */ | ||||
| 	page = ofs >> chip->page_shift; | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); | ||||
| 
 | ||||
| 	/* Submit address of last page to unlock */ | ||||
| 	page = (ofs + len) >> chip->page_shift; | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, | ||||
| 				(page | invert) & chip->pagemask); | ||||
| 
 | ||||
| 	/* Call wait ready function */ | ||||
| 	status = chip->waitfunc(mtd, chip); | ||||
| 	udelay(1000); | ||||
| 	/* See if device thinks it succeeded */ | ||||
| 	if (status & 0x01) { | ||||
| 		DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", | ||||
| 					__func__, status); | ||||
| 		ret = -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * nand_unlock - [REPLACABLE] unlocks specified locked blockes | ||||
|  * | ||||
|  * @param mtd - mtd info | ||||
|  * @param ofs - offset to start unlock from | ||||
|  * @param len - length to unlock | ||||
|  * | ||||
|  * @return - unlock status | ||||
|  */ | ||||
| int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int chipnr; | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 
 | ||||
| 	DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", | ||||
| 			__func__, (unsigned long long)ofs, len); | ||||
| 
 | ||||
| 	if (check_offs_len(mtd, ofs, len)) | ||||
| 		ret = -EINVAL; | ||||
| 
 | ||||
| 	/* Align to last block address if size addresses end of the device */ | ||||
| 	if (ofs + len == mtd->size) | ||||
| 		len -= mtd->erasesize; | ||||
| 
 | ||||
| 	nand_get_device(chip, mtd, FL_UNLOCKING); | ||||
| 
 | ||||
| 	/* Shift to get chip number */ | ||||
| 	chipnr = ofs >> chip->chip_shift; | ||||
| 
 | ||||
| 	chip->select_chip(mtd, chipnr); | ||||
| 
 | ||||
| 	/* Check, if it is write protected */ | ||||
| 	if (nand_check_wp(mtd)) { | ||||
| 		DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", | ||||
| 					__func__); | ||||
| 		ret = -EIO; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = __nand_unlock(mtd, ofs, len, 0); | ||||
| 
 | ||||
| out: | ||||
| 	/* de-select the NAND device */ | ||||
| 	chip->select_chip(mtd, -1); | ||||
| 
 | ||||
| 	nand_release_device(mtd); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * nand_lock - [REPLACABLE] locks all blockes present in the device | ||||
|  * | ||||
|  * @param mtd - mtd info | ||||
|  * @param ofs - offset to start unlock from | ||||
|  * @param len - length to unlock | ||||
|  * | ||||
|  * @return - lock status | ||||
|  * | ||||
|  * This feature is not support in many NAND parts. 'Micron' NAND parts | ||||
|  * do have this feature, but it allows only to lock all blocks not for | ||||
|  * specified range for block. | ||||
|  * | ||||
|  * Implementing 'lock' feature by making use of 'unlock', for now. | ||||
|  */ | ||||
| int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int chipnr, status, page; | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 
 | ||||
| 	DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", | ||||
| 			__func__, (unsigned long long)ofs, len); | ||||
| 
 | ||||
| 	if (check_offs_len(mtd, ofs, len)) | ||||
| 		ret = -EINVAL; | ||||
| 
 | ||||
| 	nand_get_device(chip, mtd, FL_LOCKING); | ||||
| 
 | ||||
| 	/* Shift to get chip number */ | ||||
| 	chipnr = ofs >> chip->chip_shift; | ||||
| 
 | ||||
| 	chip->select_chip(mtd, chipnr); | ||||
| 
 | ||||
| 	/* Check, if it is write protected */ | ||||
| 	if (nand_check_wp(mtd)) { | ||||
| 		DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", | ||||
| 					__func__); | ||||
| 		status = MTD_ERASE_FAILED; | ||||
| 		ret = -EIO; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Submit address of first page to lock */ | ||||
| 	page = ofs >> chip->page_shift; | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask); | ||||
| 
 | ||||
| 	/* Call wait ready function */ | ||||
| 	status = chip->waitfunc(mtd, chip); | ||||
| 	udelay(1000); | ||||
| 	/* See if device thinks it succeeded */ | ||||
| 	if (status & 0x01) { | ||||
| 		DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", | ||||
| 					__func__, status); | ||||
| 		ret = -EIO; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = __nand_unlock(mtd, ofs, len, 0x1); | ||||
| 
 | ||||
| out: | ||||
| 	/* de-select the NAND device */ | ||||
| 	chip->select_chip(mtd, -1); | ||||
| 
 | ||||
| 	nand_release_device(mtd); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * nand_read_page_raw - [Intern] read raw page data without ecc | ||||
|  * @mtd:	mtd info structure | ||||
| @ -3089,6 +3251,8 @@ void nand_release(struct mtd_info *mtd) | ||||
| 		kfree(chip->buffers); | ||||
| } | ||||
| 
 | ||||
| EXPORT_SYMBOL_GPL(nand_lock); | ||||
| EXPORT_SYMBOL_GPL(nand_unlock); | ||||
| EXPORT_SYMBOL_GPL(nand_scan); | ||||
| EXPORT_SYMBOL_GPL(nand_scan_ident); | ||||
| EXPORT_SYMBOL_GPL(nand_scan_tail); | ||||
|  | ||||
| @ -38,6 +38,12 @@ extern void nand_release (struct mtd_info *mtd); | ||||
| /* Internal helper for board drivers which need to override command function */ | ||||
| extern void nand_wait_ready(struct mtd_info *mtd); | ||||
| 
 | ||||
| /* locks all blockes present in the device */ | ||||
| extern int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); | ||||
| 
 | ||||
| /* unlocks specified locked blockes */ | ||||
| extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); | ||||
| 
 | ||||
| /* The maximum number of NAND chips in an array */ | ||||
| #define NAND_MAX_CHIPS		8 | ||||
| 
 | ||||
| @ -82,6 +88,10 @@ extern void nand_wait_ready(struct mtd_info *mtd); | ||||
| #define NAND_CMD_ERASE2		0xd0 | ||||
| #define NAND_CMD_RESET		0xff | ||||
| 
 | ||||
| #define NAND_CMD_LOCK		0x2a | ||||
| #define NAND_CMD_UNLOCK1	0x23 | ||||
| #define NAND_CMD_UNLOCK2	0x24 | ||||
| 
 | ||||
| /* Extended commands for large page devices */ | ||||
| #define NAND_CMD_READSTART	0x30 | ||||
| #define NAND_CMD_RNDOUTSTART	0xE0 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Vimal Singh
						Vimal Singh