Skip to contentSkip to conversation

nand: Add support for unlock.invert

PATCH Superseded Joe Hershberger 3 participants 17 messages Aug 17, 2012 – Sep 18, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/3 nand: Add support for unlock.invert

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c |  9 ++++++---
 include/nand.h               |  4 ++--
 3 files changed, 18 insertions(+), 8 deletions(-)
common/cmd_nand.c +10 -3
index a91ccf4..9acac9f 100644
@@ -749,11 +749,18 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 		return 0;
 	}
 
-	if (strcmp(cmd, "unlock") == 0) {
+	if (strncmp(cmd, "unlock", 5) == 0) {
+		int invert = 0;
+
+		s = strchr(cmd, '.');
+
+		if (s && !strcmp(s, ".invert"))
+			invert = 1;
+
 		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0)
 			return 1;
 
-		if (!nand_unlock(&nand_info[dev], off, size)) {
+		if (!nand_unlock(&nand_info[dev], off, size, invert)) {
 			puts("NAND flash successfully unlocked\n");
 		} else {
 			puts("Error unlocking NAND flash, "
@@ -807,7 +814,7 @@ U_BOOT_CMD(
 	"\n"
 	"nand lock [tight] [status]\n"
 	"    bring nand to lock state or display locked pages\n"
-	"nand unlock [offset] [size] - unlock section"
+	"nand unlock[.invert] [offset] [size] - unlock section"
 #endif
 #ifdef CONFIG_ENV_OFFSET_OOB
 	"\n"
drivers/mtd/nand/nand_util.c +6 -3
index 7ed8b18..87caa62 100644
@@ -317,18 +317,19 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
  * @param start		start byte address
  * @param length	number of bytes to unlock (must be a multiple of
  *			page size nand->writesize)
+ * @param invert	if set, unlock everything not selected
  *
  * @return		0 on success, -1 in case of error
  */
-int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
+int nand_unlock(struct mtd_info *mtd, ulong start, ulong length, int invert)
 {
 	int ret = 0;
 	int chipnr;
 	int status;
 	int page;
 	struct nand_chip *chip = mtd->priv;
-	printf ("nand_unlock: start: %08x, length: %d!\n",
-		(int)start, (int)length);
+	printf("nand_unlock%s: start: %08x, length: %d!\n",
+		invert ? " (invert)" : "", (int)start, (int)length);
 
 	/* select the NAND device */
 	chipnr = (int)(start >> chip->chip_shift);
@@ -368,6 +369,8 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 
 	/* submit ADDRESS of LAST page to unlock */
 	page += (int)(length >> chip->page_shift);
+	if (invert)
+		page |= 1;
 	chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);
 
 	/* call wait ready function */
include/nand.h +2 -2
index a48b1b8..2c2f588 100644
@@ -144,8 +144,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
 #define NAND_LOCK_STATUS_LOCK	0x02
 #define NAND_LOCK_STATUS_UNLOCK 0x04
 
-int nand_lock( nand_info_t *meminfo, int tight );
-int nand_unlock( nand_info_t *meminfo, ulong start, ulong length );
+int nand_lock(nand_info_t *meminfo, int tight);
+int nand_unlock(nand_info_t *meminfo, ulong start, ulong length, int invert);
 int nand_get_lock_status(nand_info_t *meminfo, loff_t offset);
 
 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst);
Signature · 1 line
1.7.11.5
#1 lore raw

PATCH 2/3 nand: consolidate duplicated constants

NAND_CMD_ constants for lock/unlock should be in the header

---
 drivers/mtd/nand/nand_util.c | 6 ------
 include/linux/mtd/nand.h     | 2 ++
 2 files changed, 2 insertions(+), 6 deletions(-)
drivers/mtd/nand/nand_util.c +0 -6
index 87caa62..2c8ae98 100644
@@ -207,12 +207,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
  * Support for locking / unlocking operations of some NAND devices
  *****************************************************************************/
 
-#define NAND_CMD_LOCK		0x2a
-#define NAND_CMD_LOCK_TIGHT	0x2c
-#define NAND_CMD_UNLOCK1	0x23
-#define NAND_CMD_UNLOCK2	0x24
-#define NAND_CMD_LOCK_STATUS	0x7a
-
 /**
  * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
  *	      state
include/linux/mtd/nand.h +2 -0
index 82704de..6c40531 100644
@@ -85,8 +85,10 @@ extern void nand_wait_ready(struct mtd_info *mtd);
 #define NAND_CMD_RESET		0xff
 
 #define NAND_CMD_LOCK		0x2a
+#define NAND_CMD_LOCK_TIGHT	0x2c
 #define NAND_CMD_UNLOCK1	0x23
 #define NAND_CMD_UNLOCK2	0x24
+#define NAND_CMD_LOCK_STATUS	0x7a
 
 /* Extended commands for large page devices */
 #define NAND_CMD_READSTART	0x30
Signature · 1 line
1.7.11.5
#2 lore raw

PATCH 3/3 nand: Make NAND lock status compatible with Micron

In reply to Joe Hershberger

Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is not the same as others. Instead of bit 1 being lock, it is #lock_tight. To make the driver support either format, ignore bit 1 and use only bit 0 and bit 2.

---
 common/cmd_nand.c            | 2 +-
 drivers/mtd/nand/nand_util.c | 2 --
 include/nand.h               | 1 -
 3 files changed, 1 insertion(+), 4 deletions(-)
common/cmd_nand.c +1 -1
index 9acac9f..cd5dba4 100644
@@ -236,7 +236,7 @@ static void print_status(ulong start, ulong end, ulong erasesize, int status)
 		end - 1,
 		(end - start) / erasesize,
 		((status & NAND_LOCK_STATUS_TIGHT) ?  "TIGHT " : ""),
-		((status & NAND_LOCK_STATUS_LOCK) ?  "LOCK " : ""),
+		(!(status & NAND_LOCK_STATUS_UNLOCK) ?  "LOCK " : ""),
 		((status & NAND_LOCK_STATUS_UNLOCK) ?  "UNLOCK " : ""));
 }
 
drivers/mtd/nand/nand_util.c +0 -2
index 2c8ae98..d5b314a 100644
@@ -265,7 +265,6 @@ int nand_lock(struct mtd_info *mtd, int tight)
  *			>0 lock status:
  *			  bitfield with the following combinations:
  *			  NAND_LOCK_STATUS_TIGHT: page in tight state
- *			  NAND_LOCK_STATUS_LOCK:  page locked
  *			  NAND_LOCK_STATUS_UNLOCK: page unlocked
  *
  */
@@ -294,7 +293,6 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
 	chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask);
 
 	ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT
-					  | NAND_LOCK_STATUS_LOCK
 					  | NAND_LOCK_STATUS_UNLOCK);
 
  out:
include/nand.h +0 -1
index 2c2f588..ad2804d 100644
@@ -141,7 +141,6 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
 
 #define NAND_LOCK_STATUS_TIGHT	0x01
-#define NAND_LOCK_STATUS_LOCK	0x02
 #define NAND_LOCK_STATUS_UNLOCK 0x04
 
 int nand_lock(nand_info_t *meminfo, int tight);
Signature · 1 line
1.7.11.5
#3 lore raw

PATCH 3/3 nand: Make NAND lock status compatible with Micron

Quoted 4 lines · Joe Hershberger

Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is not the same as others. Instead of bit 1 being lock, it is #lock_tight. To make the driver support either format, ignore bit 1 and use only bit 0 and bit 2.

Please put a comment in the code as to why we're doing this.

-Scott

#4 lore raw

PATCH 1/3 nand: Add support for unlock.invert

In reply to Joe Hershberger
Quoted 17 lines · Joe Hershberger

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c |  9 ++++++---
 include/nand.h               |  4 ++--
 3 files changed, 18 insertions(+), 8 deletions(-)
common/cmd_nand.c +0 -0
index a91ccf4..9acac9f 100644
@@ -749,11 +749,18 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 		return 0;
 	}

common/cmd_nand.c int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) · line 759

Quoted 10 lines
common/cmd_nand.c +8 -1
 
-	if (strcmp(cmd, "unlock") == 0) {
+	if (strncmp(cmd, "unlock", 5) == 0) {
+		int invert = 0;
+
+		s = strchr(cmd, '.');
+
+		if (s && !strcmp(s, ".invert"))
+			invert = 1;
+

How about something like ".allexcept"? "Invert" is less clear about what's being inverted.

Quoted 22 lines
common/cmd_nand.c +2 -2
 		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0)
 			return 1;
 
-		if (!nand_unlock(&nand_info[dev], off, size)) {
+		if (!nand_unlock(&nand_info[dev], off, size, invert)) {
 			puts("NAND flash successfully unlocked\n");
 		} else {
 			puts("Error unlocking NAND flash, "
@@ -807,7 +814,7 @@ U_BOOT_CMD(
 	"\n"
 	"nand lock [tight] [status]\n"
 	"    bring nand to lock state or display locked pages\n"
-	"nand unlock [offset] [size] - unlock section"
+	"nand unlock[.invert] [offset] [size] - unlock section"
 #endif
 #ifdef CONFIG_ENV_OFFSET_OOB
 	"\n"
drivers/mtd/nand/nand_util.c +0 -0
index 7ed8b18..87caa62 100644

drivers/mtd/nand/nand_util.c int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) · line 324

Quoted 9 lines
drivers/mtd/nand/nand_util.c +2 -1
@@ -317,18 +317,19 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
  * @param start		start byte address
  * @param length	number of bytes to unlock (must be a multiple of
  *			page size nand->writesize)
+ * @param invert	if set, unlock everything not selected
  *
  * @return		0 on success, -1 in case of error
  */
-int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
+int nand_unlock(struct mtd_info *mtd, ulong start, ulong length, int invert)

Hmm, seems this got missed in the loff_t conversion.

drivers/mtd/nand/nand_util.c int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) · line 332

Quoted 10 lines
drivers/mtd/nand/nand_util.c +2 -2
 {
 	int ret = 0;
 	int chipnr;
 	int status;
 	int page;
 	struct nand_chip *chip = mtd->priv;
-	printf ("nand_unlock: start: %08x, length: %d!\n",
-		(int)start, (int)length);
+	printf("nand_unlock%s: start: %08x, length: %d!\n",
+		invert ? " (invert)" : "", (int)start, (int)length);

This looks like it should be a debug message rather than a normal printf (and the (int) casts should go).

drivers/mtd/nand/nand_util.c int nand_unlock(struct mtd_info *mtd, ulong start, ulong length) · line 374

Quoted 9 lines
drivers/mtd/nand/nand_util.c +2 -0
 	/* select the NAND device */
 	chipnr = (int)(start >> chip->chip_shift);
@@ -368,6 +369,8 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 
 	/* submit ADDRESS of LAST page to unlock */
 	page += (int)(length >> chip->page_shift);
+	if (invert)
+		page |= 1;
 	chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);

Why |= 1? Is this some magic that the chip recognizes to implement "invert"? Do all chips that support lock/unlock support this (none of the NAND chip manuals I have document lock/unlock at all as far as I could find)? What if you want to unlock a non-inverted range that ends in a page with the low bit set?

-Scott

#5 lore raw

PATCH 1/3 nand: Add support for unlock.invert

Hi Scott,

Quoted 13 lines · Scott Wood
Quoted 12 lines · Joe Hershberger

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c |  9 ++++++---
 include/nand.h               |  4 ++--
 3 files changed, 18 insertions(+), 8 deletions(-)
(quoted diff) +0 -0
@@ -368,6 +369,8 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 
Quoted 11 lines

drivers/mtd/nand/nand_util.c int nand_unlock(struct mtd_info *mtd, ulong start, ulong length) · line 374

Quoted 5 lines
drivers/mtd/nand/nand_util.c +2 -0
      /* submit ADDRESS of LAST page to unlock */
      page += (int)(length >> chip->page_shift);
+     if (invert)
+             page |= 1;
      chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);

Why |= 1? Is this some magic that the chip recognizes to implement "invert"? Do all chips that support lock/unlock support this (none of the NAND chip manuals I have document lock/unlock at all as far as I could find)? What if you want to unlock a non-inverted range that ends in a page with the low bit set?

According to the data sheet for the part I'm working with (MT29F4G08ABADAH4) the unlock command has 2 commands... 0x23 and 0x24.
The invert bit only exists for 0x24 (NAND_CMD_UNLOCK2). The format
of the unlock commands specifys that block addresses are used, therefore the LSb would never be set. This bit-0 is defined to be "invert area" for 0x24 and always LOW for 0x23.

-Joe

#6 lore raw

PATCH 1/3 nand: Add support for unlock.invert

Quoted 28 lines · Joe Hershberger

Hi Scott,

Quoted 13 lines · Scott Wood
Quoted 12 lines · Joe Hershberger

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c |  9 ++++++---
 include/nand.h               |  4 ++--
 3 files changed, 18 insertions(+), 8 deletions(-)
(quoted diff) +0 -0
@@ -368,6 +369,8 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 
Quoted 11 lines

drivers/mtd/nand/nand_util.c int nand_unlock(struct mtd_info *mtd, ulong start, ulong length) · line 374

Quoted 5 lines
drivers/mtd/nand/nand_util.c +2 -0
      /* submit ADDRESS of LAST page to unlock */
      page += (int)(length >> chip->page_shift);
+     if (invert)
+             page |= 1;
      chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);

Why |= 1? Is this some magic that the chip recognizes to implement "invert"? Do all chips that support lock/unlock support this (none of the NAND chip manuals I have document lock/unlock at all as far as I could find)? What if you want to unlock a non-inverted range that ends in a page with the low bit set?

Quoted 6 lines

According to the data sheet for the part I'm working with (MT29F4G08ABADAH4) the unlock command has 2 commands... 0x23 and 0x24.
The invert bit only exists for 0x24 (NAND_CMD_UNLOCK2). The format
of the unlock commands specifys that block addresses are used, therefore the LSb would never be set. This bit-0 is defined to be "invert area" for 0x24 and always LOW for 0x23.

Please add a code comment to this effect.

-Scott

#7 lore raw

PATCH 1/3 nand: Add support for unlock.invert

Hi Scott,

Quoted 29 lines · Scott Wood
Quoted 28 lines · Joe Hershberger

Hi Scott,

Quoted 24 lines · Scott Wood
Quoted 11 lines · Joe Hershberger

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c |  9 ++++++---
 include/nand.h               |  4 ++--
 3 files changed, 18 insertions(+), 8 deletions(-)

drivers/mtd/nand/nand_util.c int nand_unlock(struct mtd_info *mtd, ulong start, ulong length) · line 374

Quoted 6 lines
drivers/mtd/nand/nand_util.c +2 -0
@@ -368,6 +369,8 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 
      /* submit ADDRESS of LAST page to unlock */
      page += (int)(length >> chip->page_shift);
+     if (invert)
+             page |= 1;
      chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);

Why |= 1? Is this some magic that the chip recognizes to implement "invert"? Do all chips that support lock/unlock support this (none of the NAND chip manuals I have document lock/unlock at all as far as I could find)? What if you want to unlock a non-inverted range that ends in a page with the low bit set?

Quoted 8 lines
Quoted 6 lines

According to the data sheet for the part I'm working with (MT29F4G08ABADAH4) the unlock command has 2 commands... 0x23 and 0x24.
The invert bit only exists for 0x24 (NAND_CMD_UNLOCK2). The format
of the unlock commands specifys that block addresses are used, therefore the LSb would never be set. This bit-0 is defined to be "invert area" for 0x24 and always LOW for 0x23.

Please add a code comment to this effect.

This is what the code does... Can you recommend a comment that you would like?

Thanks,
-Joe

#8 lore raw

PATCH v2 1/4 nand: Add support for unlock.invert

In reply to Joe Hershberger

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
Changes in v2:
- Changed invert to allexcept
- Changed unlock printf to debug print
- Dropped cast in unlock debug print

 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c | 10 +++++++---
 include/nand.h               |  4 ++--
 3 files changed, 19 insertions(+), 8 deletions(-)
common/cmd_nand.c +10 -3
index a91ccf4..f737c06 100644
@@ -749,11 +749,18 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 		return 0;
 	}
 
-	if (strcmp(cmd, "unlock") == 0) {
+	if (strncmp(cmd, "unlock", 5) == 0) {
+		int allexcept = 0;
+
+		s = strchr(cmd, '.');
+
+		if (s && !strcmp(s, ".allexcept"))
+			allexcept = 1;
+
 		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0)
 			return 1;
 
-		if (!nand_unlock(&nand_info[dev], off, size)) {
+		if (!nand_unlock(&nand_info[dev], off, size, allexcept)) {
 			puts("NAND flash successfully unlocked\n");
 		} else {
 			puts("Error unlocking NAND flash, "
@@ -807,7 +814,7 @@ U_BOOT_CMD(
 	"\n"
 	"nand lock [tight] [status]\n"
 	"    bring nand to lock state or display locked pages\n"
-	"nand unlock [offset] [size] - unlock section"
+	"nand unlock[.allexcept] [offset] [size] - unlock section"
 #endif
 #ifdef CONFIG_ENV_OFFSET_OOB
 	"\n"
drivers/mtd/nand/nand_util.c +7 -3
index 7ed8b18..21a011c 100644
@@ -317,18 +317,20 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
  * @param start		start byte address
  * @param length	number of bytes to unlock (must be a multiple of
  *			page size nand->writesize)
+ * @param allexcept	if set, unlock everything not selected
  *
  * @return		0 on success, -1 in case of error
  */
-int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
+int nand_unlock(struct mtd_info *mtd, ulong start, ulong length, int allexcept)
 {
 	int ret = 0;
 	int chipnr;
 	int status;
 	int page;
 	struct nand_chip *chip = mtd->priv;
-	printf ("nand_unlock: start: %08x, length: %d!\n",
-		(int)start, (int)length);
+
+	debug("nand_unlock%s: start: %08x, length: %d!\n",
+		allexcept ? " (allexcept)" : "", start, length);
 
 	/* select the NAND device */
 	chipnr = (int)(start >> chip->chip_shift);
@@ -368,6 +370,8 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 
 	/* submit ADDRESS of LAST page to unlock */
 	page += (int)(length >> chip->page_shift);
+	if (allexcept)
+		page |= 1;
 	chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);
 
 	/* call wait ready function */
include/nand.h +2 -2
index a48b1b8..9a30796 100644
@@ -144,8 +144,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
 #define NAND_LOCK_STATUS_LOCK	0x02
 #define NAND_LOCK_STATUS_UNLOCK 0x04
 
-int nand_lock( nand_info_t *meminfo, int tight );
-int nand_unlock( nand_info_t *meminfo, ulong start, ulong length );
+int nand_lock(nand_info_t *meminfo, int tight);
+int nand_unlock(nand_info_t *meminfo, ulong start, ulong length, int allexcept);
 int nand_get_lock_status(nand_info_t *meminfo, loff_t offset);
 
 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst);
Signature · 1 line
1.7.11.5
#9 lore raw

PATCH v2 2/4 nand: Change ulong to loff_t and size_t

Missed in previous cleanup.

---
Changes in v2:
- Added loff_t cleanup to series

 drivers/mtd/nand/nand_util.c | 5 +++--
 include/nand.h               | 3 ++-
 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/mtd/nand/nand_util.c +3 -2
index 21a011c..6e57610 100644
@@ -321,7 +321,8 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
  *
  * @return		0 on success, -1 in case of error
  */
-int nand_unlock(struct mtd_info *mtd, ulong start, ulong length, int allexcept)
+int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length,
+	int allexcept)
 {
 	int ret = 0;
 	int chipnr;
@@ -329,7 +330,7 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length, int allexcept)
 	int page;
 	struct nand_chip *chip = mtd->priv;
 
-	debug("nand_unlock%s: start: %08x, length: %d!\n",
+	debug("nand_unlock%s: start: %08llx, length: %d!\n",
 		allexcept ? " (allexcept)" : "", start, length);
 
 	/* select the NAND device */
include/nand.h +2 -1
index 9a30796..a516cb8 100644
@@ -145,7 +145,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
 #define NAND_LOCK_STATUS_UNLOCK 0x04
 
 int nand_lock(nand_info_t *meminfo, int tight);
-int nand_unlock(nand_info_t *meminfo, ulong start, ulong length, int allexcept);
+int nand_unlock(nand_info_t *meminfo, loff_t start, size_t length,
+	int allexcept);
 int nand_get_lock_status(nand_info_t *meminfo, loff_t offset);
 
 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst);
Signature · 1 line
1.7.11.5
#10 lore raw

PATCH v2 2/4 nand: Change ulong to loff_t and size_t

Quoted 10 lines · Joe Hershberger

Missed in previous cleanup.

---
Changes in v2:
- Added loff_t cleanup to series

 drivers/mtd/nand/nand_util.c | 5 +++--
 include/nand.h               | 3 ++-
 2 files changed, 5 insertions(+), 3 deletions(-)

Applied to u-boot-nand-flash.

-Scott

#11 lore raw

PATCH v2 3/4 nand: consolidate duplicated constants

In reply to Joe Hershberger

NAND_CMD_ constants for lock/unlock should be in the header

---

 drivers/mtd/nand/nand_util.c | 6 ------
 include/linux/mtd/nand.h     | 2 ++
 2 files changed, 2 insertions(+), 6 deletions(-)
drivers/mtd/nand/nand_util.c +0 -6
index 6e57610..78a5987 100644
@@ -207,12 +207,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
  * Support for locking / unlocking operations of some NAND devices
  *****************************************************************************/
 
-#define NAND_CMD_LOCK		0x2a
-#define NAND_CMD_LOCK_TIGHT	0x2c
-#define NAND_CMD_UNLOCK1	0x23
-#define NAND_CMD_UNLOCK2	0x24
-#define NAND_CMD_LOCK_STATUS	0x7a
-
 /**
  * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
  *	      state
include/linux/mtd/nand.h +2 -0
index 82704de..6c40531 100644
@@ -85,8 +85,10 @@ extern void nand_wait_ready(struct mtd_info *mtd);
 #define NAND_CMD_RESET		0xff
 
 #define NAND_CMD_LOCK		0x2a
+#define NAND_CMD_LOCK_TIGHT	0x2c
 #define NAND_CMD_UNLOCK1	0x23
 #define NAND_CMD_UNLOCK2	0x24
+#define NAND_CMD_LOCK_STATUS	0x7a
 
 /* Extended commands for large page devices */
 #define NAND_CMD_READSTART	0x30
Signature · 1 line
1.7.11.5
#12 lore raw

PATCH v2 3/4 nand: consolidate duplicated constants

Quoted 8 lines · Joe Hershberger

NAND_CMD_ constants for lock/unlock should be in the header

---

 drivers/mtd/nand/nand_util.c | 6 ------
 include/linux/mtd/nand.h     | 2 ++
 2 files changed, 2 insertions(+), 6 deletions(-)

Applied to u-boot-nand-flash.

-Scott

#13 lore raw

PATCH v2 4/4 nand: Make NAND lock status compatible with Micron

In reply to Joe Hershberger

Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is not the same as others. Instead of bit 1 being lock, it is #lock_tight. To make the driver support either format, ignore bit 1 and use only bit 0 and bit 2.

---
Changes in v2:
- Added comment about NAND status work-around

 common/cmd_nand.c            | 8 +++++++-
 drivers/mtd/nand/nand_util.c | 2 --
 include/nand.h               | 1 -
 3 files changed, 7 insertions(+), 4 deletions(-)
common/cmd_nand.c +7 -1
index f737c06..9c6dabe 100644
@@ -231,12 +231,18 @@ print:
 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
 static void print_status(ulong start, ulong end, ulong erasesize, int status)
 {
+	/*
+	 * Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is
+	 * not the same as others.  Instead of bit 1 being lock, it is
+	 * #lock_tight. To make the driver support either format, ignore bit 1
+	 * and use only bit 0 and bit 2.
+	 */
 	printf("%08lx - %08lx: %08lx blocks %s%s%s\n",
 		start,
 		end - 1,
 		(end - start) / erasesize,
 		((status & NAND_LOCK_STATUS_TIGHT) ?  "TIGHT " : ""),
-		((status & NAND_LOCK_STATUS_LOCK) ?  "LOCK " : ""),
+		(!(status & NAND_LOCK_STATUS_UNLOCK) ?  "LOCK " : ""),
 		((status & NAND_LOCK_STATUS_UNLOCK) ?  "UNLOCK " : ""));
 }
 
drivers/mtd/nand/nand_util.c +0 -2
index 78a5987..7243d80 100644
@@ -265,7 +265,6 @@ int nand_lock(struct mtd_info *mtd, int tight)
  *			>0 lock status:
  *			  bitfield with the following combinations:
  *			  NAND_LOCK_STATUS_TIGHT: page in tight state
- *			  NAND_LOCK_STATUS_LOCK:  page locked
  *			  NAND_LOCK_STATUS_UNLOCK: page unlocked
  *
  */
@@ -294,7 +293,6 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
 	chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask);
 
 	ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT
-					  | NAND_LOCK_STATUS_LOCK
 					  | NAND_LOCK_STATUS_UNLOCK);
 
  out:
include/nand.h +0 -1
index a516cb8..00d4254 100644
@@ -141,7 +141,6 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
 
 #define NAND_LOCK_STATUS_TIGHT	0x01
-#define NAND_LOCK_STATUS_LOCK	0x02
 #define NAND_LOCK_STATUS_UNLOCK 0x04
 
 int nand_lock(nand_info_t *meminfo, int tight);
Signature · 1 line
1.7.11.5
#14 lore raw

PATCH v2 4/4 nand: Make NAND lock status compatible with Micron

Quoted 6 lines · Joe Hershberger

Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is not the same as others. Instead of bit 1 being lock, it is #lock_tight. To make the driver support either format, ignore bit 1 and use only bit 0 and bit 2.

Quoted 8 lines

---
Changes in v2:
- Added comment about NAND status work-around

 common/cmd_nand.c            | 8 +++++++-
 drivers/mtd/nand/nand_util.c | 2 --
 include/nand.h               | 1 -
 3 files changed, 7 insertions(+), 4 deletions(-)

Applied to u-boot-nand-flash.

-Scott

#15 lore raw

PATCH v2 1/4 nand: Add support for unlock.invert

In reply to Joe Hershberger
Quoted 10 lines · Joe Hershberger

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
Changes in v2:
- Changed invert to allexcept
- Changed unlock printf to debug print
- Dropped cast in unlock debug print

Quoted 4 lines
 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c | 10 +++++++---
 include/nand.h               |  4 ++--
 3 files changed, 19 insertions(+), 8 deletions(-)

Applied to u-boot-nand-flash with the diff below. Do you know if all chips that support locking support the invert bit? If not, we should at least update the documentation to mention this (though runtime detection would be good if practical).

doc/README.nand +2 -0
@@ -228,6 +228,8 @@ NAND locking command (for chips with active LOCKPRE pin)
   "nand unlock [offset] [size]"
   unlock consecutive area (can be called multiple times for different areas)
 
+  "nand unlock.allexcept [offset] [size]"
+  unlock all except specified consecutive area
 
 I have tested the code with board containing 128MiB NAND large page chips
 and 32MiB small page chips.
drivers/mtd/nand/nand_util.c +7 -0
index 21a011c..c66eeef 100644
@@ -370,8 +370,15 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length, int allexcept)
 
 	/* submit ADDRESS of LAST page to unlock */
 	page += (int)(length >> chip->page_shift);
+
+	/*
+	 * Page addresses for unlocking are supposed to be block-aligned.
+	 * At least some NAND chips use the low bit to indicate that the
+	 * page range should be inverted.
+	 */
 	if (allexcept)
 		page |= 1;
+
 	chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);
 
 	/* call wait ready function */

-Scott

#16 lore raw

PATCH v2 1/4 nand: Add support for unlock.invert

Hi Scott,

Quoted 16 lines · Scott Wood
Quoted 10 lines · Joe Hershberger

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.

---
Changes in v2:
- Changed invert to allexcept
- Changed unlock printf to debug print
- Dropped cast in unlock debug print

Quoted 4 lines
 common/cmd_nand.c            | 13 ++++++++++---
 drivers/mtd/nand/nand_util.c | 10 +++++++---
 include/nand.h               |  4 ++--
 3 files changed, 19 insertions(+), 8 deletions(-)
Quoted 4 lines

Applied to u-boot-nand-flash with the diff below. Do you know if all chips that support locking support the invert bit? If not, we should at least update the documentation to mention this (though runtime detection would be good if practical).

I'm not aware of a part that supports lock and not the invert functionality. I'm also not aware of a way to detect at runtime if it is supported.

Thanks,
-Joe