[U-Boot] [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.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com --- common/cmd_nand.c | 13 ++++++++++--- drivers/mtd/nand/nand_util.c | 9 ++++++--- include/nand.h | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index a91ccf4..9acac9f 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -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" diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 7ed8b18..87caa62 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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 */ diff --git a/include/nand.h b/include/nand.h index a48b1b8..2c2f588 100644 --- a/include/nand.h +++ b/include/nand.h @@ -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);

NAND_CMD_ constants for lock/unlock should be in the header
Signed-off-by: Joe Hershberger joe.hershberger@ni.com --- drivers/mtd/nand/nand_util.c | 6 ------ include/linux/mtd/nand.h | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 87caa62..2c8ae98 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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 diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 82704de..6c40531 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -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

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.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com --- common/cmd_nand.c | 2 +- drivers/mtd/nand/nand_util.c | 2 -- include/nand.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 9acac9f..cd5dba4 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -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 " : "")); }
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 2c8ae98..d5b314a 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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: diff --git a/include/nand.h b/include/nand.h index 2c2f588..ad2804d 100644 --- a/include/nand.h +++ b/include/nand.h @@ -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);

On 08/17/2012 03:31 PM, Joe Hershberger wrote:
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

On 08/17/2012 03:31 PM, Joe Hershberger wrote:
NAND unlock command allows an invert bit to be set to unlock all but the selected page range.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
common/cmd_nand.c | 13 ++++++++++--- drivers/mtd/nand/nand_util.c | 9 ++++++--- include/nand.h | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index a91ccf4..9acac9f 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -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;
How about something like ".allexcept"? "Invert" is less clear about what's being inverted.
if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0) return 1;
if (!nand_unlock(&nand_info[dev], off, size)) {
} else { puts("Error unlocking NAND flash, "if (!nand_unlock(&nand_info[dev], off, size, invert)) { puts("NAND flash successfully unlocked\n");
@@ -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" diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 7ed8b18..87caa62 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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.
{ 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).
/* 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)
chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);page |= 1;
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

Hi Scott,
On Fri, Aug 17, 2012 at 3:53 PM, Scott Wood scottwood@freescale.com wrote:
On 08/17/2012 03:31 PM, Joe Hershberger wrote:
NAND unlock command allows an invert bit to be set to unlock all but the selected page range.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
common/cmd_nand.c | 13 ++++++++++--- drivers/mtd/nand/nand_util.c | 9 ++++++--- include/nand.h | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-)
@@ -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?
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

On 08/22/2012 03:34 PM, Joe Hershberger wrote:
Hi Scott,
On Fri, Aug 17, 2012 at 3:53 PM, Scott Wood scottwood@freescale.com wrote:
On 08/17/2012 03:31 PM, Joe Hershberger wrote:
NAND unlock command allows an invert bit to be set to unlock all but the selected page range.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
common/cmd_nand.c | 13 ++++++++++--- drivers/mtd/nand/nand_util.c | 9 ++++++--- include/nand.h | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-)
@@ -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?
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

Hi Scott,
On Wed, Aug 22, 2012 at 8:38 PM, Scott Wood scottwood@freescale.com wrote:
On 08/22/2012 03:34 PM, Joe Hershberger wrote:
Hi Scott,
On Fri, Aug 17, 2012 at 3:53 PM, Scott Wood scottwood@freescale.com wrote:
On 08/17/2012 03:31 PM, Joe Hershberger wrote:
NAND unlock command allows an invert bit to be set to unlock all but the selected page range.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
common/cmd_nand.c | 13 ++++++++++--- drivers/mtd/nand/nand_util.c | 9 ++++++--- include/nand.h | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-)
@@ -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?
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

NAND unlock command allows an invert bit to be set to unlock all but the selected page range.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com --- 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(-)
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index a91ccf4..f737c06 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -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" diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 7ed8b18..21a011c 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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 */ diff --git a/include/nand.h b/include/nand.h index a48b1b8..9a30796 100644 --- a/include/nand.h +++ b/include/nand.h @@ -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);

Missed in previous cleanup.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com --- 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(-)
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 21a011c..6e57610 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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 */ diff --git a/include/nand.h b/include/nand.h index 9a30796..a516cb8 100644 --- a/include/nand.h +++ b/include/nand.h @@ -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);

On Wed, Aug 22, 2012 at 04:49:43PM -0500, Joe Hershberger wrote:
Missed in previous cleanup.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
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

NAND_CMD_ constants for lock/unlock should be in the header
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
drivers/mtd/nand/nand_util.c | 6 ------ include/linux/mtd/nand.h | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 6e57610..78a5987 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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 diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 82704de..6c40531 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -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

On Wed, Aug 22, 2012 at 04:49:44PM -0500, Joe Hershberger wrote:
NAND_CMD_ constants for lock/unlock should be in the header
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
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

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.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com --- 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(-)
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index f737c06..9c6dabe 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -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 " : "")); }
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 78a5987..7243d80 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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: diff --git a/include/nand.h b/include/nand.h index a516cb8..00d4254 100644 --- a/include/nand.h +++ b/include/nand.h @@ -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);

On Wed, Aug 22, 2012 at 04:49:45PM -0500, Joe Hershberger wrote:
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.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
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

On Wed, Aug 22, 2012 at 04:49:42PM -0500, Joe Hershberger wrote:
NAND unlock command allows an invert bit to be set to unlock all but the selected page range.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
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(-)
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).
--- a/doc/README.nand +++ b/doc/README.nand @@ -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. diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 21a011c..c66eeef 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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

Hi Scott,
On Mon, Sep 17, 2012 at 5:35 PM, Scott Wood scottwood@freescale.com wrote:
On Wed, Aug 22, 2012 at 04:49:42PM -0500, Joe Hershberger wrote:
NAND unlock command allows an invert bit to be set to unlock all but the selected page range.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
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(-)
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
participants (3)
-
Joe Hershberger
-
Joe Hershberger
-
Scott Wood