aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorVimal Singh <vimal.newwork@gmail.com>2010-02-08 05:20:49 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-02-26 08:21:49 -0500
commit7d70f334ad2bf1b3aaa1f0699c0f442e14bcc9e0 (patch)
tree2d2b23d7d8145c2fb6b6414708732facdeb27fe7 /drivers/mtd
parent6fe5a6acdc126107e54a6c584536e09ab7dde949 (diff)
mtd: nand: add lock/unlock routines
Add nand lock / unlock routines. At least 'micron' parts support this. Signed-off-by: Vimal Singh <vimalsingh@ti.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/nand_base.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 2dfeb4bea83a..ed62e1ee0f81 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -864,6 +864,168 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
864} 864}
865 865
866/** 866/**
867 * __nand_unlock - [REPLACABLE] unlocks specified locked blockes
868 *
869 * @param mtd - mtd info
870 * @param ofs - offset to start unlock from
871 * @param len - length to unlock
872 * @invert - when = 0, unlock the range of blocks within the lower and
873 * upper boundary address
874 * whne = 1, unlock the range of blocks outside the boundaries
875 * of the lower and upper boundary address
876 *
877 * @return - unlock status
878 */
879static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
880 uint64_t len, int invert)
881{
882 int ret = 0;
883 int status, page;
884 struct nand_chip *chip = mtd->priv;
885
886 /* Submit address of first page to unlock */
887 page = ofs >> chip->page_shift;
888 chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask);
889
890 /* Submit address of last page to unlock */
891 page = (ofs + len) >> chip->page_shift;
892 chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1,
893 (page | invert) & chip->pagemask);
894
895 /* Call wait ready function */
896 status = chip->waitfunc(mtd, chip);
897 udelay(1000);
898 /* See if device thinks it succeeded */
899 if (status & 0x01) {
900 DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n",
901 __func__, status);
902 ret = -EIO;
903 }
904
905 return ret;
906}
907
908/**
909 * nand_unlock - [REPLACABLE] unlocks specified locked blockes
910 *
911 * @param mtd - mtd info
912 * @param ofs - offset to start unlock from
913 * @param len - length to unlock
914 *
915 * @return - unlock status
916 */
917int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
918{
919 int ret = 0;
920 int chipnr;
921 struct nand_chip *chip = mtd->priv;
922
923 DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n",
924 __func__, (unsigned long long)ofs, len);
925
926 if (check_offs_len(mtd, ofs, len))
927 ret = -EINVAL;
928
929 /* Align to last block address if size addresses end of the device */
930 if (ofs + len == mtd->size)
931 len -= mtd->erasesize;
932
933 nand_get_device(chip, mtd, FL_UNLOCKING);
934
935 /* Shift to get chip number */
936 chipnr = ofs >> chip->chip_shift;
937
938 chip->select_chip(mtd, chipnr);
939
940 /* Check, if it is write protected */
941 if (nand_check_wp(mtd)) {
942 DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n",
943 __func__);
944 ret = -EIO;
945 goto out;
946 }
947
948 ret = __nand_unlock(mtd, ofs, len, 0);
949
950out:
951 /* de-select the NAND device */
952 chip->select_chip(mtd, -1);
953
954 nand_release_device(mtd);
955
956 return ret;
957}
958
959/**
960 * nand_lock - [REPLACABLE] locks all blockes present in the device
961 *
962 * @param mtd - mtd info
963 * @param ofs - offset to start unlock from
964 * @param len - length to unlock
965 *
966 * @return - lock status
967 *
968 * This feature is not support in many NAND parts. 'Micron' NAND parts
969 * do have this feature, but it allows only to lock all blocks not for
970 * specified range for block.
971 *
972 * Implementing 'lock' feature by making use of 'unlock', for now.
973 */
974int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
975{
976 int ret = 0;
977 int chipnr, status, page;
978 struct nand_chip *chip = mtd->priv;
979
980 DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n",
981 __func__, (unsigned long long)ofs, len);
982
983 if (check_offs_len(mtd, ofs, len))
984 ret = -EINVAL;
985
986 nand_get_device(chip, mtd, FL_LOCKING);
987
988 /* Shift to get chip number */
989 chipnr = ofs >> chip->chip_shift;
990
991 chip->select_chip(mtd, chipnr);
992
993 /* Check, if it is write protected */
994 if (nand_check_wp(mtd)) {
995 DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n",
996 __func__);
997 status = MTD_ERASE_FAILED;
998 ret = -EIO;
999 goto out;
1000 }
1001
1002 /* Submit address of first page to lock */
1003 page = ofs >> chip->page_shift;
1004 chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask);
1005
1006 /* Call wait ready function */
1007 status = chip->waitfunc(mtd, chip);
1008 udelay(1000);
1009 /* See if device thinks it succeeded */
1010 if (status & 0x01) {
1011 DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n",
1012 __func__, status);
1013 ret = -EIO;
1014 goto out;
1015 }
1016
1017 ret = __nand_unlock(mtd, ofs, len, 0x1);
1018
1019out:
1020 /* de-select the NAND device */
1021 chip->select_chip(mtd, -1);
1022
1023 nand_release_device(mtd);
1024
1025 return ret;
1026}
1027
1028/**
867 * nand_read_page_raw - [Intern] read raw page data without ecc 1029 * nand_read_page_raw - [Intern] read raw page data without ecc
868 * @mtd: mtd info structure 1030 * @mtd: mtd info structure
869 * @chip: nand chip info structure 1031 * @chip: nand chip info structure
@@ -3089,6 +3251,8 @@ void nand_release(struct mtd_info *mtd)
3089 kfree(chip->buffers); 3251 kfree(chip->buffers);
3090} 3252}
3091 3253
3254EXPORT_SYMBOL_GPL(nand_lock);
3255EXPORT_SYMBOL_GPL(nand_unlock);
3092EXPORT_SYMBOL_GPL(nand_scan); 3256EXPORT_SYMBOL_GPL(nand_scan);
3093EXPORT_SYMBOL_GPL(nand_scan_ident); 3257EXPORT_SYMBOL_GPL(nand_scan_ident);
3094EXPORT_SYMBOL_GPL(nand_scan_tail); 3258EXPORT_SYMBOL_GPL(nand_scan_tail);