NAND: Enable nand lock, unlock feature
Enable nand lock, unlock and status of lock feature. Not every device and platform requires this, hence, it is under define for CONFIG_CMD_NAND_LOCK_UNLOCK Nand unlock and status operate on block boundary instead of page boundary. Details in: http://www.micron.com/products/partdetail?part=MT29C2G24MAKLAJG-6%20IT Intial solution provided by Vikram Pandita <vikram.pandita@ti.com> Includes preliminary suggestions from Scott Wood Signed-off-by: Nishanth Menon <nm@ti.com> Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
parent
69fb8be4fc
commit
50657c2732
|
@ -164,6 +164,47 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
|
||||
static void print_status(ulong start, ulong end, ulong erasesize, int status)
|
||||
{
|
||||
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) ? "UNLOCK " : ""));
|
||||
}
|
||||
|
||||
static void do_nand_status(nand_info_t *nand)
|
||||
{
|
||||
ulong block_start = 0;
|
||||
ulong off;
|
||||
int last_status = -1;
|
||||
|
||||
struct nand_chip *nand_chip = nand->priv;
|
||||
/* check the WP bit */
|
||||
nand_chip->cmdfunc(nand, NAND_CMD_STATUS, -1, -1);
|
||||
printf("device is %swrite protected\n",
|
||||
(nand_chip->read_byte(nand) & 0x80 ?
|
||||
"NOT " : ""));
|
||||
|
||||
for (off = 0; off < nand->size; off += nand->erasesize) {
|
||||
int s = nand_get_lock_status(nand, off);
|
||||
|
||||
/* print message only if status has changed */
|
||||
if (s != last_status && off != 0) {
|
||||
print_status(block_start, off, nand->erasesize,
|
||||
last_status);
|
||||
block_start = off;
|
||||
}
|
||||
last_status = s;
|
||||
}
|
||||
/* Print the last block info */
|
||||
print_status(block_start, off, nand->erasesize, last_status);
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
int i, dev, ret = 0;
|
||||
|
@ -383,8 +424,9 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
|
||||
if (strcmp(cmd, "lock") == 0) {
|
||||
int tight = 0;
|
||||
int tight = 0;
|
||||
int status = 0;
|
||||
if (argc == 3) {
|
||||
if (!strcmp("tight", argv[2]))
|
||||
|
@ -392,44 +434,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
|||
if (!strcmp("status", argv[2]))
|
||||
status = 1;
|
||||
}
|
||||
/*
|
||||
* ! BROKEN !
|
||||
*
|
||||
* TODO: must be implemented and tested by someone with HW
|
||||
*/
|
||||
#if 0
|
||||
if (status) {
|
||||
ulong block_start = 0;
|
||||
ulong off;
|
||||
int last_status = -1;
|
||||
|
||||
struct nand_chip *nand_chip = nand->priv;
|
||||
/* check the WP bit */
|
||||
nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);
|
||||
printf("device is %swrite protected\n",
|
||||
(nand_chip->read_byte(nand) & 0x80 ?
|
||||
"NOT " : ""));
|
||||
|
||||
for (off = 0; off < nand->size; off += nand->writesize) {
|
||||
int s = nand_get_lock_status(nand, off);
|
||||
|
||||
/* print message only if status has changed
|
||||
* or at end of chip
|
||||
*/
|
||||
if (off == nand->size - nand->writesize
|
||||
|| (s != last_status && off != 0)) {
|
||||
|
||||
printf("%08lx - %08lx: %8d pages %s%s%s\n",
|
||||
block_start,
|
||||
off-1,
|
||||
(off-block_start)/nand->writesize,
|
||||
((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
|
||||
((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
|
||||
((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
|
||||
}
|
||||
|
||||
last_status = s;
|
||||
}
|
||||
do_nand_status(nand);
|
||||
} else {
|
||||
if (!nand_lock(nand, tight)) {
|
||||
puts("NAND flash successfully locked\n");
|
||||
|
@ -438,7 +444,6 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -446,12 +451,6 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
|||
if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* ! BROKEN !
|
||||
*
|
||||
* TODO: must be implemented and tested by someone with HW
|
||||
*/
|
||||
#if 0
|
||||
if (!nand_unlock(nand, off, size)) {
|
||||
puts("NAND flash successfully unlocked\n");
|
||||
} else {
|
||||
|
@ -459,9 +458,9 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
|||
"write and erase will probably fail\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
usage:
|
||||
printf("Usage:\n%s\n", cmdtp->usage);
|
||||
|
@ -483,9 +482,12 @@ U_BOOT_CMD(nand, 5, 1, do_nand,
|
|||
"nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
|
||||
"nand markbad off - mark bad block at offset (UNSAFE)\n"
|
||||
"nand biterr off - make a bit error at offset (UNSAFE)\n"
|
||||
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
|
||||
"nand lock [tight] [status]\n"
|
||||
" bring nand to lock state or display locked pages\n"
|
||||
"nand unlock [offset] [size] - unlock section\n");
|
||||
"nand unlock [offset] [size] - unlock section\n"
|
||||
#endif
|
||||
);
|
||||
|
||||
static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
|
||||
ulong offset, ulong addr, char *cmd)
|
||||
|
|
|
@ -238,7 +238,8 @@ static struct nand_ecclayout autoplace_ecclayout = {
|
|||
#endif
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
|
||||
|
||||
/******************************************************************************
|
||||
* Support for locking / unlocking operations of some NAND devices
|
||||
*****************************************************************************/
|
||||
|
@ -253,7 +254,7 @@ static struct nand_ecclayout autoplace_ecclayout = {
|
|||
* nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
|
||||
* state
|
||||
*
|
||||
* @param meminfo nand mtd instance
|
||||
* @param mtd nand mtd instance
|
||||
* @param tight bring device in lock tight mode
|
||||
*
|
||||
* @return 0 on success, -1 in case of error
|
||||
|
@ -270,21 +271,21 @@ static struct nand_ecclayout autoplace_ecclayout = {
|
|||
* calls will fail. It is only posible to leave lock-tight state by
|
||||
* an hardware signal (low pulse on _WP pin) or by power down.
|
||||
*/
|
||||
int nand_lock(nand_info_t *meminfo, int tight)
|
||||
int nand_lock(struct mtd_info *mtd, int tight)
|
||||
{
|
||||
int ret = 0;
|
||||
int status;
|
||||
struct nand_chip *this = meminfo->priv;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
|
||||
/* select the NAND device */
|
||||
this->select_chip(meminfo, 0);
|
||||
chip->select_chip(mtd, 0);
|
||||
|
||||
this->cmdfunc(meminfo,
|
||||
chip->cmdfunc(mtd,
|
||||
(tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),
|
||||
-1, -1);
|
||||
|
||||
/* call wait ready function */
|
||||
status = this->waitfunc(meminfo, this, FL_WRITING);
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
|
||||
/* see if device thinks it succeeded */
|
||||
if (status & 0x01) {
|
||||
|
@ -292,7 +293,7 @@ int nand_lock(nand_info_t *meminfo, int tight)
|
|||
}
|
||||
|
||||
/* de-select the NAND device */
|
||||
this->select_chip(meminfo, -1);
|
||||
chip->select_chip(mtd, -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -300,7 +301,7 @@ int nand_lock(nand_info_t *meminfo, int tight)
|
|||
* nand_get_lock_status: - query current lock state from one page of NAND
|
||||
* flash
|
||||
*
|
||||
* @param meminfo nand mtd instance
|
||||
* @param mtd nand mtd instance
|
||||
* @param offset page address to query (muss be page aligned!)
|
||||
*
|
||||
* @return -1 in case of error
|
||||
|
@ -311,19 +312,19 @@ int nand_lock(nand_info_t *meminfo, int tight)
|
|||
* NAND_LOCK_STATUS_UNLOCK: page unlocked
|
||||
*
|
||||
*/
|
||||
int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
|
||||
int nand_get_lock_status(struct mtd_info *mtd, ulong offset)
|
||||
{
|
||||
int ret = 0;
|
||||
int chipnr;
|
||||
int page;
|
||||
struct nand_chip *this = meminfo->priv;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
|
||||
/* select the NAND device */
|
||||
chipnr = (int)(offset >> this->chip_shift);
|
||||
this->select_chip(meminfo, chipnr);
|
||||
chipnr = (int)(offset >> chip->chip_shift);
|
||||
chip->select_chip(mtd, chipnr);
|
||||
|
||||
|
||||
if ((offset & (meminfo->writesize - 1)) != 0) {
|
||||
if ((offset & (mtd->writesize - 1)) != 0) {
|
||||
printf ("nand_get_lock_status: "
|
||||
"Start address must be beginning of "
|
||||
"nand page!\n");
|
||||
|
@ -332,16 +333,16 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
|
|||
}
|
||||
|
||||
/* check the Lock Status */
|
||||
page = (int)(offset >> this->page_shift);
|
||||
this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask);
|
||||
page = (int)(offset >> chip->page_shift);
|
||||
chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask);
|
||||
|
||||
ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT
|
||||
ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT
|
||||
| NAND_LOCK_STATUS_LOCK
|
||||
| NAND_LOCK_STATUS_UNLOCK);
|
||||
|
||||
out:
|
||||
/* de-select the NAND device */
|
||||
this->select_chip(meminfo, -1);
|
||||
chip->select_chip(mtd, -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -349,59 +350,65 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
|
|||
* nand_unlock: - Unlock area of NAND pages
|
||||
* only one consecutive area can be unlocked at one time!
|
||||
*
|
||||
* @param meminfo nand mtd instance
|
||||
* @param mtd nand mtd instance
|
||||
* @param start start byte address
|
||||
* @param length number of bytes to unlock (must be a multiple of
|
||||
* page size nand->writesize)
|
||||
*
|
||||
* @return 0 on success, -1 in case of error
|
||||
*/
|
||||
int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
|
||||
int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
|
||||
{
|
||||
int ret = 0;
|
||||
int chipnr;
|
||||
int status;
|
||||
int page;
|
||||
struct nand_chip *this = meminfo->priv;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
printf ("nand_unlock: start: %08x, length: %d!\n",
|
||||
(int)start, (int)length);
|
||||
|
||||
/* select the NAND device */
|
||||
chipnr = (int)(start >> this->chip_shift);
|
||||
this->select_chip(meminfo, chipnr);
|
||||
chipnr = (int)(start >> chip->chip_shift);
|
||||
chip->select_chip(mtd, chipnr);
|
||||
|
||||
/* check the WP bit */
|
||||
this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1);
|
||||
if ((this->read_byte(meminfo) & 0x80) == 0) {
|
||||
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
||||
if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) {
|
||||
printf ("nand_unlock: Device is write protected!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((start & (meminfo->writesize - 1)) != 0) {
|
||||
if ((start & (mtd->erasesize - 1)) != 0) {
|
||||
printf ("nand_unlock: Start address must be beginning of "
|
||||
"nand page!\n");
|
||||
"nand block!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (length == 0 || (length & (meminfo->writesize - 1)) != 0) {
|
||||
printf ("nand_unlock: Length must be a multiple of nand page "
|
||||
"size!\n");
|
||||
if (length == 0 || (length & (mtd->erasesize - 1)) != 0) {
|
||||
printf ("nand_unlock: Length must be a multiple of nand block "
|
||||
"size %08x!\n", mtd->erasesize);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set length so that the last address is set to the
|
||||
* starting address of the last block
|
||||
*/
|
||||
length -= mtd->erasesize;
|
||||
|
||||
/* submit address of first page to unlock */
|
||||
page = (int)(start >> this->page_shift);
|
||||
this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
|
||||
page = (int)(start >> chip->page_shift);
|
||||
chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask);
|
||||
|
||||
/* submit ADDRESS of LAST page to unlock */
|
||||
page += (int)(length >> this->page_shift) - 1;
|
||||
this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
|
||||
page += (int)(length >> chip->page_shift);
|
||||
chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);
|
||||
|
||||
/* call wait ready function */
|
||||
status = this->waitfunc(meminfo, this, FL_WRITING);
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
/* see if device thinks it succeeded */
|
||||
if (status & 0x01) {
|
||||
/* there was an error */
|
||||
|
@ -411,7 +418,7 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
|
|||
|
||||
out:
|
||||
/* de-select the NAND device */
|
||||
this->select_chip(meminfo, -1);
|
||||
chip->select_chip(mtd, -1);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue