recovery: onenand: add lock-tight
authorSanghee Kim <sh0130.kim@samsung.com>
Fri, 30 Apr 2010 05:19:36 +0000 (14:19 +0900)
committerSanghee Kim <sh0130.kim@samsung.com>
Fri, 30 Apr 2010 05:19:36 +0000 (14:19 +0900)
recovery/drivers/onenand/onenand_base.c
recovery/onenand.c
recovery/onenand.h

index cc16326..d00d515 100644 (file)
@@ -2051,6 +2051,8 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
 
        if (cmd == ONENAND_CMD_LOCK)
                wp_status_mask = ONENAND_WP_LS;
+       else if (cmd == ONENAND_CMD_LOCK_TIGHT)
+               wp_status_mask = ONENAND_WP_LTS;
        else
                wp_status_mask = ONENAND_WP_US;
 
@@ -2062,11 +2064,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 +2077,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 +2095,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 +2108,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 +2228,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
@@ -2791,6 +2846,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;
@@ -2879,9 +2938,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 
        mtd->ecclayout = this->ecclayout;
 
-       /* Unlock whole block */
-       this->unlock_all(mtd);
-
        return this->scan_bbt(mtd);
 }
 
index e52f92e..3a6f939 100644 (file)
 
 #include <asm/io.h>
 
+#include "recovery.h"
 #include "onenand.h"
 
-#ifdef printk
-#undef printk
+#ifdef RECOVERY_DEBUG
+#define        PUTS(s) serial_puts(DEBUG_MARK"onenand: "s)
+#else
+#define PUTS(s)
 #endif
-#define printk(...)    do {} while (0)
-#define puts(...)      do {} while (0)
-#ifdef printf
-#undef printf
-#endif
-#define printf(...)    do {} while (0)
 
 struct mtd_info onenand_mtd;
 struct onenand_chip onenand_chip;
@@ -49,11 +46,14 @@ static int onenand_block_read(loff_t from, ssize_t len,
        while (len > 0) {
                thislen = min_t(ssize_t, len, blocksize);
                thislen = ALIGN(thislen, mtd->writesize);
+               if (ofs > mtd->size) {
+                       PUTS(" range overflow\n");
+                       break;
+               }
 
                ret = mtd->block_isbad(mtd, ofs);
                if (ret) {
-                       printf("Bad blocks %d at 0x%x\n",
-                              (u32)(ofs >> this->erase_shift), (u32)ofs);
+                       PUTS("Bad blocks\n");
                        ofs += blocksize;
                        /* FIXME need to check how to handle the 'len' */
                        len -= blocksize;
@@ -71,14 +71,15 @@ static int onenand_block_read(loff_t from, ssize_t len,
                ops.retlen = 0;
                ret = mtd->read_oob(mtd, ofs, &ops);
                if (ret) {
-                       printf("Read failed 0x%x, %d\n", (u32)ofs, ret);
+                       PUTS("read failed\n");
                        ofs += thislen;
                        continue;
                }
                ofs += thislen;
                buf += thislen;
                len -= thislen;
-               *retlen += ops.retlen;
+               if (retlen != NULL)
+                       *retlen += ops.retlen;
        }
 
        return 0;
@@ -90,6 +91,7 @@ static int onenand_block_write(loff_t to, ssize_t len,
        struct onenand_chip *this = mtd->priv;
        int blocksize = (1 << this->erase_shift);
        struct mtd_oob_ops ops = {
+               .mode           = MTD_OOB_PLACE,
                .retlen         = 0,
                .oobbuf         = NULL,
        };
@@ -109,11 +111,14 @@ static int onenand_block_write(loff_t to, ssize_t len,
        while (len > 0) {
                thislen = min_t(ssize_t, len, blocksize);
                thislen = ALIGN(thislen, mtd->writesize);
+               if (ofs > mtd->size) {
+                       PUTS(" range overflow\n");
+                       break;
+               }
 
                ret = mtd->block_isbad(mtd, ofs);
                if (ret) {
-                       printf("Bad blocks %d at 0x%x\n",
-                              (u32)(ofs >> this->erase_shift), (u32)ofs);
+                       PUTS("bad blocks\n");
                        skip_ofs += blocksize;
                        goto next;
                }
@@ -123,7 +128,7 @@ static int onenand_block_write(loff_t to, ssize_t len,
                ops.retlen = 0;
                ret = mtd->write_oob(mtd, ofs, &ops);
                if (ret) {
-                       printf("Write failed 0x%x, %d", (u32)ofs, ret);
+                       PUTS("write failed\n");
                        skip_ofs += thislen;
                        goto next;
                }
@@ -152,8 +157,7 @@ static int onenand_block_erase(u32 start, u32 size, int force)
        for (ofs = start; ofs < (start + size); ofs += blocksize) {
                ret = mtd->block_isbad(mtd, ofs);
                if (ret && !force) {
-                       printf("Skip erase bad block %d at 0x%x\n",
-                              (u32)(ofs >> this->erase_shift), (u32)ofs);
+                       PUTS("skip erase bad block \n");
                        continue;
                }
 
@@ -163,20 +167,30 @@ static int onenand_block_erase(u32 start, u32 size, int force)
                instr.mtd = mtd;
                ret = mtd->erase(mtd, &instr);
                if (ret) {
-                       printf("erase failed block %d at 0x%x\n",
-                              (u32)(ofs >> this->erase_shift), (u32)ofs);
-                       continue;
+                       PUTS("erase failed\n");
+                       return ret;
                }
        }
 
        return 0;
 }
 
+static int onenand_block_lock_tight(u32 start, u32 size)
+{
+       struct onenand_chip *this = mtd->priv;
+       int ret;
+
+       ret = this->lock_tight(mtd, start, size);
+
+       return ret;
+}
+
 void onenand_set_interface(struct onenand_op *onenand)
 {
        onenand->read = onenand_block_read;
        onenand->write = onenand_block_write;
        onenand->erase = onenand_block_erase;
+       onenand->lock_tight = onenand_block_lock_tight;
 
        onenand->mtd = &onenand_mtd;
        onenand->this = &onenand_chip;
index 5fe7831..6dbc720 100644 (file)
@@ -10,6 +10,7 @@ struct onenand_op {
        int (*read)(loff_t, ssize_t, ssize_t *, u_char *, int);
        int (*write)(loff_t, ssize_t, ssize_t *, u_char *);
        int (*erase)(u32, u32, int);
+       int (*lock_tight)(u32, u32);
 
        struct mtd_info *mtd;
        struct onenand_chip *this;