|
@@ -1239,179 +1239,6 @@ int nand_reset(struct nand_chip *chip, int chipnr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
|
|
|
- * @mtd: mtd info
|
|
|
- * @ofs: offset to start unlock from
|
|
|
- * @len: length to unlock
|
|
|
- * @invert:
|
|
|
- * - when = 0, unlock the range of blocks within the lower and
|
|
|
- * upper boundary address
|
|
|
- * - when = 1, unlock the range of blocks outside the boundaries
|
|
|
- * of the lower and upper boundary address
|
|
|
- *
|
|
|
- * Returs unlock status.
|
|
|
- */
|
|
|
-static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
|
|
|
- uint64_t len, int invert)
|
|
|
-{
|
|
|
- int ret = 0;
|
|
|
- int status, page;
|
|
|
- struct nand_chip *chip = mtd_to_nand(mtd);
|
|
|
-
|
|
|
- /* Submit address of first page to unlock */
|
|
|
- page = ofs >> chip->page_shift;
|
|
|
- chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask);
|
|
|
-
|
|
|
- /* Submit address of last page to unlock */
|
|
|
- page = (ofs + len) >> chip->page_shift;
|
|
|
- chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1,
|
|
|
- (page | invert) & chip->pagemask);
|
|
|
-
|
|
|
- /* Call wait ready function */
|
|
|
- status = chip->waitfunc(mtd, chip);
|
|
|
- /* See if device thinks it succeeded */
|
|
|
- if (status & NAND_STATUS_FAIL) {
|
|
|
- pr_debug("%s: error status = 0x%08x\n",
|
|
|
- __func__, status);
|
|
|
- ret = -EIO;
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * nand_unlock - [REPLACEABLE] unlocks specified locked blocks
|
|
|
- * @mtd: mtd info
|
|
|
- * @ofs: offset to start unlock from
|
|
|
- * @len: length to unlock
|
|
|
- *
|
|
|
- * Returns unlock status.
|
|
|
- */
|
|
|
-int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|
|
-{
|
|
|
- int ret = 0;
|
|
|
- int chipnr;
|
|
|
- struct nand_chip *chip = mtd_to_nand(mtd);
|
|
|
-
|
|
|
- pr_debug("%s: start = 0x%012llx, len = %llu\n",
|
|
|
- __func__, (unsigned long long)ofs, len);
|
|
|
-
|
|
|
- if (check_offs_len(mtd, ofs, len))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- /* Align to last block address if size addresses end of the device */
|
|
|
- if (ofs + len == mtd->size)
|
|
|
- len -= mtd->erasesize;
|
|
|
-
|
|
|
- nand_get_device(mtd, FL_UNLOCKING);
|
|
|
-
|
|
|
- /* Shift to get chip number */
|
|
|
- chipnr = ofs >> chip->chip_shift;
|
|
|
-
|
|
|
- /*
|
|
|
- * Reset the chip.
|
|
|
- * If we want to check the WP through READ STATUS and check the bit 7
|
|
|
- * we must reset the chip
|
|
|
- * some operation can also clear the bit 7 of status register
|
|
|
- * eg. erase/program a locked block
|
|
|
- */
|
|
|
- nand_reset(chip, chipnr);
|
|
|
-
|
|
|
- chip->select_chip(mtd, chipnr);
|
|
|
-
|
|
|
- /* Check, if it is write protected */
|
|
|
- if (nand_check_wp(mtd)) {
|
|
|
- pr_debug("%s: device is write protected!\n",
|
|
|
- __func__);
|
|
|
- ret = -EIO;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- ret = __nand_unlock(mtd, ofs, len, 0);
|
|
|
-
|
|
|
-out:
|
|
|
- chip->select_chip(mtd, -1);
|
|
|
- nand_release_device(mtd);
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(nand_unlock);
|
|
|
-
|
|
|
-/**
|
|
|
- * nand_lock - [REPLACEABLE] locks all blocks present in the device
|
|
|
- * @mtd: mtd info
|
|
|
- * @ofs: offset to start unlock from
|
|
|
- * @len: length to unlock
|
|
|
- *
|
|
|
- * This feature is not supported in many NAND parts. 'Micron' NAND parts do
|
|
|
- * have this feature, but it allows only to lock all blocks, not for specified
|
|
|
- * range for block. Implementing 'lock' feature by making use of 'unlock', for
|
|
|
- * now.
|
|
|
- *
|
|
|
- * Returns lock status.
|
|
|
- */
|
|
|
-int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|
|
-{
|
|
|
- int ret = 0;
|
|
|
- int chipnr, status, page;
|
|
|
- struct nand_chip *chip = mtd_to_nand(mtd);
|
|
|
-
|
|
|
- pr_debug("%s: start = 0x%012llx, len = %llu\n",
|
|
|
- __func__, (unsigned long long)ofs, len);
|
|
|
-
|
|
|
- if (check_offs_len(mtd, ofs, len))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- nand_get_device(mtd, FL_LOCKING);
|
|
|
-
|
|
|
- /* Shift to get chip number */
|
|
|
- chipnr = ofs >> chip->chip_shift;
|
|
|
-
|
|
|
- /*
|
|
|
- * Reset the chip.
|
|
|
- * If we want to check the WP through READ STATUS and check the bit 7
|
|
|
- * we must reset the chip
|
|
|
- * some operation can also clear the bit 7 of status register
|
|
|
- * eg. erase/program a locked block
|
|
|
- */
|
|
|
- nand_reset(chip, chipnr);
|
|
|
-
|
|
|
- chip->select_chip(mtd, chipnr);
|
|
|
-
|
|
|
- /* Check, if it is write protected */
|
|
|
- if (nand_check_wp(mtd)) {
|
|
|
- pr_debug("%s: device is write protected!\n",
|
|
|
- __func__);
|
|
|
- status = MTD_ERASE_FAILED;
|
|
|
- ret = -EIO;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- /* Submit address of first page to lock */
|
|
|
- page = ofs >> chip->page_shift;
|
|
|
- chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask);
|
|
|
-
|
|
|
- /* Call wait ready function */
|
|
|
- status = chip->waitfunc(mtd, chip);
|
|
|
- /* See if device thinks it succeeded */
|
|
|
- if (status & NAND_STATUS_FAIL) {
|
|
|
- pr_debug("%s: error status = 0x%08x\n",
|
|
|
- __func__, status);
|
|
|
- ret = -EIO;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- ret = __nand_unlock(mtd, ofs, len, 0x1);
|
|
|
-
|
|
|
-out:
|
|
|
- chip->select_chip(mtd, -1);
|
|
|
- nand_release_device(mtd);
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(nand_lock);
|
|
|
-
|
|
|
/**
|
|
|
* nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
|
|
|
* @buf: buffer to test
|