From c31de5436941dcda9b475962d418df76be070309 Mon Sep 17 00:00:00 2001 From: Sanghee Kim Date: Fri, 30 Apr 2010 13:37:46 +0900 Subject: [PATCH] onenand: add lock-tight and lock check --- common/cmd_onenand.c | 35 +++++++++++++++++++ drivers/mtd/onenand/onenand_base.c | 71 ++++++++++++++++++++++++++++++++++---- include/linux/mtd/onenand.h | 2 ++ 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c index 5c02575..7c02571 100644 --- a/common/cmd_onenand.c +++ b/common/cmd_onenand.c @@ -202,6 +202,26 @@ static int onenand_block_erase(u32 start, u32 size, int force) return 0; } +static int onenand_block_islock(u32 start, u32 size) +{ + struct onenand_chip *this = mtd->priv; + loff_t ofs; + int status; + int status_mask = ONENAND_WP_LS|ONENAND_WP_LTS; + + for (ofs = start; ofs < (start + size); ofs += mtd->erasesize) { + if (this->block_islock != NULL) + status = this->block_islock(mtd, ofs); + else + status = 0; + + if (status & status_mask) + return (status & status_mask); + } + + return 0; +} + static int onenand_block_test(u32 start, u32 size) { struct onenand_chip *this = mtd->priv; @@ -485,6 +505,21 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) return ret == 0 ? 1 : 0; } + if (strncmp(cmd, "lock", 4) == 0) { + printf("OneNAND lock: "); + if (argc < 4) { + ofs = 0x0; + len = mtd->size; + } else { + if (arg_off_size(argc-2, argv+2, &ofs, &len)) + return 1; + } + + ret = onenand_block_islock(ofs, len); + + return ret; + } + break; } diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 1bc9cbd..384988f 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -2062,11 +2062,11 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int /* Set end block address */ this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); - /* Write unlock command */ + /* Write lock command */ this->command(mtd, cmd, 0, 0); /* There's no return value */ - this->wait(mtd, FL_UNLOCKING); + this->wait(mtd, FL_LOCKING); /* Sanity check */ while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) @@ -2075,7 +2075,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int /* Check lock status */ status = this->read_word(this->base + ONENAND_REG_WP_STATUS); - if (!(status & ONENAND_WP_US)) + if (!(status & wp_status_mask)) printk(KERN_ERR "wp status = 0x%x\n", status); return 0; @@ -2093,11 +2093,11 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int /* Set start block address */ this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); - /* Write unlock command */ - this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); + /* Write lock command */ + this->command(mtd, cmd, 0, 0); /* There's no return value */ - this->wait(mtd, FL_UNLOCKING); + this->wait(mtd, FL_LOCKING); /* Sanity check */ while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) @@ -2106,7 +2106,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int /* Check lock status */ status = this->read_word(this->base + ONENAND_REG_WP_STATUS); - if (!(status & ONENAND_WP_US)) + if (!(status & wp_status_mask)) printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); } @@ -2226,6 +2226,59 @@ static void onenand_unlock_all(struct mtd_info *mtd) onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); } +/** + * onenand_lock_tight - [OneNAND Interface] Lock-tight block(s) + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * @param len number of bytes to lock-tight + * + * Lock-tight one or more blocks + */ +static int onenand_lock_tight(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + int ret; + + onenand_get_device(mtd, FL_LOCKING); + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK_TIGHT); + onenand_release_device(mtd); + return ret; +} + +/** + * onenand_block_islock - [MTD Interface] Check whether the block at the given offset is locked + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * + * Check whether the block is bad + */ +static int onenand_block_islock(struct mtd_info *mtd, loff_t ofs) +{ + struct onenand_chip *this = mtd->priv; + int block, value, status; + + /* Check for invalid offset */ + if (ofs > mtd->size) + return -EINVAL; + + onenand_get_device(mtd, FL_READING); + + block = onenand_block(this, ofs); + /* Set block address */ + value = onenand_block_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + /* Set start block address */ + this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); + + /* Check lock status */ + status = this->read_word(this->base + ONENAND_REG_WP_STATUS); + + onenand_release_device(mtd); + + return status; +} /** * onenand_check_features - Check and set OneNAND features @@ -2786,6 +2839,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->bbt_wait = onenand_bbt_wait; if (!this->unlock_all) this->unlock_all = onenand_unlock_all; + if (!this->lock_tight) + this->lock_tight = onenand_lock_tight; + if (!this->block_islock) + this->block_islock = onenand_block_islock; if (!this->read_bufferram) this->read_bufferram = onenand_read_bufferram; diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 5a4ed73..ce6d1fb 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -96,6 +96,8 @@ struct onenand_chip { int (*wait) (struct mtd_info *mtd, int state); int (*bbt_wait) (struct mtd_info *mtd, int state); void (*unlock_all)(struct mtd_info *mtd); + int (*lock_tight) (struct mtd_info *mtd, loff_t ofs, size_t len); + int (*block_islock) (struct mtd_info *mtd, loff_t ofs); int (*read_bufferram) (struct mtd_info *mtd, loff_t addr, int area, unsigned char *buffer, int offset, size_t count); int (*write_bufferram) (struct mtd_info *mtd, loff_t addr, int area, -- 2.7.4