aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2005-02-08 12:11:19 -0500
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-05-23 06:25:23 -0400
commitf77814dd5728edaf1239d19755d2aa0d8c33d861 (patch)
tree5cf7f73aa367bf152e5fbd16b5173e18bb787dd5
parent67d9e95c393d23c229836e28b262dc73d71da784 (diff)
[MTD] Support for protection register support on Intel FLASH chips
This enables support for reading, writing and locking so called "Protection Registers" present on some flash chips. A subset of them are pre-programmed at the factory with a unique set of values. The rest is user-programmable. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/mtd/chips/Kconfig27
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c401
-rw-r--r--drivers/mtd/mtdpart.c28
-rw-r--r--include/linux/mtd/cfi.h4
-rw-r--r--include/linux/mtd/flashchip.h3
-rw-r--r--include/linux/mtd/map.h15
-rw-r--r--include/linux/mtd/mtd.h10
-rw-r--r--include/mtd/mtd-abi.h8
8 files changed, 369 insertions, 127 deletions
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index d682dbc8157e..f4eda1e40d51 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -1,5 +1,5 @@
1# drivers/mtd/chips/Kconfig 1# drivers/mtd/chips/Kconfig
2# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $ 2# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $
3 3
4menu "RAM/ROM/Flash chip drivers" 4menu "RAM/ROM/Flash chip drivers"
5 depends on MTD!=n 5 depends on MTD!=n
@@ -155,6 +155,31 @@ config MTD_CFI_I8
155 If your flash chips are interleaved in eights - i.e. you have eight 155 If your flash chips are interleaved in eights - i.e. you have eight
156 flash chips addressed by each bus cycle, then say 'Y'. 156 flash chips addressed by each bus cycle, then say 'Y'.
157 157
158config MTD_OTP
159 bool "Protection Registers aka one-time programmable (OTP) bits"
160 depends on MTD_CFI_ADV_OPTIONS
161 default n
162 help
163 This enables support for reading, writing and locking so called
164 "Protection Registers" present on some flash chips.
165 A subset of them are pre-programmed at the factory with a
166 unique set of values. The rest is user-programmable.
167
168 The user-programmable Protection Registers contain one-time
169 programmable (OTP) bits; when programmed, register bits cannot be
170 erased. Each Protection Register can be accessed multiple times to
171 program individual bits, as long as the register remains unlocked.
172
173 Each Protection Register has an associated Lock Register bit. When a
174 Lock Register bit is programmed, the associated Protection Register
175 can only be read; it can no longer be programmed. Additionally,
176 because the Lock Register bits themselves are OTP, when programmed,
177 Lock Register bits cannot be erased. Therefore, when a Protection
178 Register is locked, it cannot be unlocked.
179
180 This feature should therefore be used with extreme care. Any mistake
181 in the programming of OTP bits will waste them.
182
158config MTD_CFI_INTELEXT 183config MTD_CFI_INTELEXT
159 tristate "Support for Intel/Sharp flash chips" 184 tristate "Support for Intel/Sharp flash chips"
160 depends on MTD_GEN_PROBE 185 depends on MTD_GEN_PROBE
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index c630d7532f7a..b3f5acf0760c 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -4,7 +4,7 @@
4 * 4 *
5 * (C) 2000 Red Hat. GPL'd 5 * (C) 2000 Red Hat. GPL'd
6 * 6 *
7 * $Id: cfi_cmdset_0001.c,v 1.165 2005/02/05 02:06:15 nico Exp $ 7 * $Id: cfi_cmdset_0001.c,v 1.167 2005/02/08 17:11:15 nico Exp $
8 * 8 *
9 * 9 *
10 * 10/10/2000 Nicolas Pitre <nico@cam.org> 10 * 10/10/2000 Nicolas Pitre <nico@cam.org>
@@ -48,14 +48,20 @@
48#define M50LPW080 0x002F 48#define M50LPW080 0x002F
49 49
50static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 50static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
51//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
52//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
53static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 51static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
54static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 52static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
55static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); 53static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
56static void cfi_intelext_sync (struct mtd_info *); 54static void cfi_intelext_sync (struct mtd_info *);
57static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); 55static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
58static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); 56static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
57static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
58static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
59static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
60static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
61static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
62 struct otp_info *, size_t);
63static int cfi_intelext_get_user_prot_info (struct mtd_info *,
64 struct otp_info *, size_t);
59static int cfi_intelext_suspend (struct mtd_info *); 65static int cfi_intelext_suspend (struct mtd_info *);
60static void cfi_intelext_resume (struct mtd_info *); 66static void cfi_intelext_resume (struct mtd_info *);
61 67
@@ -423,9 +429,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
423 mtd->eraseregions[i].numblocks); 429 mtd->eraseregions[i].numblocks);
424 } 430 }
425 431
426#if 0 432#ifdef CONFIG_MTD_OTP
427 mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
428 mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; 433 mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
434 mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
435 mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
436 mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
437 mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
438 mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
429#endif 439#endif
430 440
431 /* This function has the potential to distort the reality 441 /* This function has the potential to distort the reality
@@ -565,7 +575,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
565 resettime: 575 resettime:
566 timeo = jiffies + HZ; 576 timeo = jiffies + HZ;
567 retry: 577 retry:
568 if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) { 578 if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
569 /* 579 /*
570 * OK. We have possibility for contension on the write/erase 580 * OK. We have possibility for contension on the write/erase
571 * operations which are global to the real chip and not per 581 * operations which are global to the real chip and not per
@@ -1178,111 +1188,11 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
1178 return ret; 1188 return ret;
1179} 1189}
1180 1190
1181#if 0
1182static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
1183 loff_t from, size_t len,
1184 size_t *retlen,
1185 u_char *buf,
1186 int base_offst, int reg_sz)
1187{
1188 struct map_info *map = mtd->priv;
1189 struct cfi_private *cfi = map->fldrv_priv;
1190 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
1191 struct flchip *chip;
1192 int ofs_factor = cfi->interleave * cfi->device_type;
1193 int count = len;
1194 int chip_num, offst;
1195 int ret;
1196
1197 chip_num = ((unsigned int)from/reg_sz);
1198 offst = from - (reg_sz*chip_num)+base_offst;
1199
1200 while (count) {
1201 /* Calculate which chip & protection register offset we need */
1202
1203 if (chip_num >= cfi->numchips)
1204 goto out;
1205
1206 chip = &cfi->chips[chip_num];
1207
1208 spin_lock(chip->mutex);
1209 ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
1210 if (ret) {
1211 spin_unlock(chip->mutex);
1212 return (len-count)?:ret;
1213 }
1214
1215 xip_disable(map, chip, chip->start);
1216
1217 if (chip->state != FL_JEDEC_QUERY) {
1218 map_write(map, CMD(0x90), chip->start);
1219 chip->state = FL_JEDEC_QUERY;
1220 }
1221
1222 while (count && ((offst-base_offst) < reg_sz)) {
1223 *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
1224 buf++;
1225 offst++;
1226 count--;
1227 }
1228
1229 xip_enable(map, chip, chip->start);
1230 put_chip(map, chip, chip->start);
1231 spin_unlock(chip->mutex);
1232
1233 /* Move on to the next chip */
1234 chip_num++;
1235 offst = base_offst;
1236 }
1237
1238 out:
1239 return len-count;
1240}
1241
1242static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
1243{
1244 struct map_info *map = mtd->priv;
1245 struct cfi_private *cfi = map->fldrv_priv;
1246 struct cfi_pri_intelext *extp=cfi->cmdset_priv;
1247 int base_offst,reg_sz;
1248
1249 /* Check that we actually have some protection registers */
1250 if(!extp || !(extp->FeatureSupport&64)){
1251 printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
1252 return 0;
1253 }
1254
1255 base_offst=(1<<extp->FactProtRegSize);
1256 reg_sz=(1<<extp->UserProtRegSize);
1257
1258 return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
1259}
1260
1261static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
1262{
1263 struct map_info *map = mtd->priv;
1264 struct cfi_private *cfi = map->fldrv_priv;
1265 struct cfi_pri_intelext *extp=cfi->cmdset_priv;
1266 int base_offst,reg_sz;
1267
1268 /* Check that we actually have some protection registers */
1269 if(!extp || !(extp->FeatureSupport&64)){
1270 printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
1271 return 0;
1272 }
1273
1274 base_offst=0;
1275 reg_sz=(1<<extp->FactProtRegSize);
1276
1277 return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
1278}
1279#endif
1280
1281static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, 1191static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1282 unsigned long adr, map_word datum) 1192 unsigned long adr, map_word datum, int mode)
1283{ 1193{
1284 struct cfi_private *cfi = map->fldrv_priv; 1194 struct cfi_private *cfi = map->fldrv_priv;
1285 map_word status, status_OK; 1195 map_word status, status_OK, write_cmd;
1286 unsigned long timeo; 1196 unsigned long timeo;
1287 int z, ret=0; 1197 int z, ret=0;
1288 1198
@@ -1290,9 +1200,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1290 1200
1291 /* Let's determine this according to the interleave only once */ 1201 /* Let's determine this according to the interleave only once */
1292 status_OK = CMD(0x80); 1202 status_OK = CMD(0x80);
1203 switch (mode) {
1204 case FL_WRITING: write_cmd = CMD(0x40); break;
1205 case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
1206 default: return -EINVAL;
1207 }
1293 1208
1294 spin_lock(chip->mutex); 1209 spin_lock(chip->mutex);
1295 ret = get_chip(map, chip, adr, FL_WRITING); 1210 ret = get_chip(map, chip, adr, mode);
1296 if (ret) { 1211 if (ret) {
1297 spin_unlock(chip->mutex); 1212 spin_unlock(chip->mutex);
1298 return ret; 1213 return ret;
@@ -1301,9 +1216,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1301 XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); 1216 XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
1302 ENABLE_VPP(map); 1217 ENABLE_VPP(map);
1303 xip_disable(map, chip, adr); 1218 xip_disable(map, chip, adr);
1304 map_write(map, CMD(0x40), adr); 1219 map_write(map, write_cmd, adr);
1305 map_write(map, datum, adr); 1220 map_write(map, datum, adr);
1306 chip->state = FL_WRITING; 1221 chip->state = mode;
1307 1222
1308 spin_unlock(chip->mutex); 1223 spin_unlock(chip->mutex);
1309 INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map)); 1224 INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
@@ -1313,7 +1228,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1313 timeo = jiffies + (HZ/2); 1228 timeo = jiffies + (HZ/2);
1314 z = 0; 1229 z = 0;
1315 for (;;) { 1230 for (;;) {
1316 if (chip->state != FL_WRITING) { 1231 if (chip->state != mode) {
1317 /* Someone's suspended the write. Sleep */ 1232 /* Someone's suspended the write. Sleep */
1318 DECLARE_WAITQUEUE(wait, current); 1233 DECLARE_WAITQUEUE(wait, current);
1319 1234
@@ -1401,7 +1316,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
1401 datum = map_word_load_partial(map, datum, buf, gap, n); 1316 datum = map_word_load_partial(map, datum, buf, gap, n);
1402 1317
1403 ret = do_write_oneword(map, &cfi->chips[chipnum], 1318 ret = do_write_oneword(map, &cfi->chips[chipnum],
1404 bus_ofs, datum); 1319 bus_ofs, datum, FL_WRITING);
1405 if (ret) 1320 if (ret)
1406 return ret; 1321 return ret;
1407 1322
@@ -1422,7 +1337,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
1422 map_word datum = map_word_load(map, buf); 1337 map_word datum = map_word_load(map, buf);
1423 1338
1424 ret = do_write_oneword(map, &cfi->chips[chipnum], 1339 ret = do_write_oneword(map, &cfi->chips[chipnum],
1425 ofs, datum); 1340 ofs, datum, FL_WRITING);
1426 if (ret) 1341 if (ret)
1427 return ret; 1342 return ret;
1428 1343
@@ -1446,7 +1361,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
1446 datum = map_word_load_partial(map, datum, buf, 0, len); 1361 datum = map_word_load_partial(map, datum, buf, 0, len);
1447 1362
1448 ret = do_write_oneword(map, &cfi->chips[chipnum], 1363 ret = do_write_oneword(map, &cfi->chips[chipnum],
1449 ofs, datum); 1364 ofs, datum, FL_WRITING);
1450 if (ret) 1365 if (ret)
1451 return ret; 1366 return ret;
1452 1367
@@ -2036,6 +1951,262 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
2036 return ret; 1951 return ret;
2037} 1952}
2038 1953
1954#ifdef CONFIG_MTD_OTP
1955
1956typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
1957 u_long data_offset, u_char *buf, u_int size,
1958 u_long prot_offset, u_int groupno, u_int groupsize);
1959
1960static int __xipram
1961do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
1962 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
1963{
1964 struct cfi_private *cfi = map->fldrv_priv;
1965 int ret;
1966
1967 spin_lock(chip->mutex);
1968 ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
1969 if (ret) {
1970 spin_unlock(chip->mutex);
1971 return ret;
1972 }
1973
1974 /* let's ensure we're not reading back cached data from array mode */
1975 if (map->inval_cache)
1976 map->inval_cache(map, chip->start + offset, size);
1977
1978 xip_disable(map, chip, chip->start);
1979 if (chip->state != FL_JEDEC_QUERY) {
1980 map_write(map, CMD(0x90), chip->start);
1981 chip->state = FL_JEDEC_QUERY;
1982 }
1983 map_copy_from(map, buf, chip->start + offset, size);
1984 xip_enable(map, chip, chip->start);
1985
1986 /* then ensure we don't keep OTP data in the cache */
1987 if (map->inval_cache)
1988 map->inval_cache(map, chip->start + offset, size);
1989
1990 put_chip(map, chip, chip->start);
1991 spin_unlock(chip->mutex);
1992 return 0;
1993}
1994
1995static int
1996do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
1997 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
1998{
1999 int ret;
2000
2001 while (size) {
2002 unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
2003 int gap = offset - bus_ofs;
2004 int n = min_t(int, size, map_bankwidth(map)-gap);
2005 map_word datum = map_word_ff(map);
2006
2007 datum = map_word_load_partial(map, datum, buf, gap, n);
2008 ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
2009 if (ret)
2010 return ret;
2011
2012 offset += n;
2013 buf += n;
2014 size -= n;
2015 }
2016
2017 return 0;
2018}
2019
2020static int
2021do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
2022 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
2023{
2024 struct cfi_private *cfi = map->fldrv_priv;
2025 map_word datum;
2026
2027 /* make sure area matches group boundaries */
2028 if (offset != 0 || size != grpsz)
2029 return -EXDEV;
2030
2031 datum = map_word_ff(map);
2032 datum = map_word_clr(map, datum, CMD(1 << grpno));
2033 return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
2034}
2035
2036static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
2037 size_t *retlen, u_char *buf,
2038 otp_op_t action, int user_regs)
2039{
2040 struct map_info *map = mtd->priv;
2041 struct cfi_private *cfi = map->fldrv_priv;
2042 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
2043 struct flchip *chip;
2044 struct cfi_intelext_otpinfo *otp;
2045 u_long devsize, reg_prot_offset, data_offset;
2046 u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
2047 u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
2048 int ret;
2049
2050 *retlen = 0;
2051
2052 /* Check that we actually have some OTP registers */
2053 if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
2054 return -ENODATA;
2055
2056 /* we need real chips here not virtual ones */
2057 devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
2058 chip_step = devsize >> cfi->chipshift;
2059
2060 for (chip_num = 0; chip_num < cfi->numchips; chip_num += chip_step) {
2061 chip = &cfi->chips[chip_num];
2062 otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
2063
2064 /* first OTP region */
2065 field = 0;
2066 reg_prot_offset = extp->ProtRegAddr;
2067 reg_fact_groups = 1;
2068 reg_fact_size = 1 << extp->FactProtRegSize;
2069 reg_user_groups = 1;
2070 reg_user_size = 1 << extp->UserProtRegSize;
2071
2072 while (len > 0) {
2073 /* flash geometry fixup */
2074 data_offset = reg_prot_offset + 1;
2075 data_offset *= cfi->interleave * cfi->device_type;
2076 reg_prot_offset *= cfi->interleave * cfi->device_type;
2077 reg_fact_size *= cfi->interleave;
2078 reg_user_size *= cfi->interleave;
2079
2080 if (user_regs) {
2081 groups = reg_user_groups;
2082 groupsize = reg_user_size;
2083 /* skip over factory reg area */
2084 groupno = reg_fact_groups;
2085 data_offset += reg_fact_groups * reg_fact_size;
2086 } else {
2087 groups = reg_fact_groups;
2088 groupsize = reg_fact_size;
2089 groupno = 0;
2090 }
2091
2092 while (groups > 0) {
2093 if (!action) {
2094 /*
2095 * Special case: if action is NULL
2096 * we fill buf with otp_info records.
2097 */
2098 struct otp_info *otpinfo;
2099 map_word lockword;
2100 len -= sizeof(struct otp_info);
2101 if (len <= 0)
2102 return -ENOSPC;
2103 ret = do_otp_read(map, chip,
2104 reg_prot_offset,
2105 (u_char *)&lockword,
2106 map_bankwidth(map),
2107 0, 0, 0);
2108 if (ret)
2109 return ret;
2110 otpinfo = (struct otp_info *)buf;
2111 otpinfo->start = from;
2112 otpinfo->length = groupsize;
2113 otpinfo->locked =
2114 !map_word_bitsset(map, lockword,
2115 CMD(1 << groupno));
2116 from += groupsize;
2117 buf += sizeof(*otpinfo);
2118 *retlen += sizeof(*otpinfo);
2119 } else if (from >= groupsize) {
2120 from -= groupsize;
2121 } else {
2122 int size = groupsize;
2123 data_offset += from;
2124 size -= from;
2125 from = 0;
2126 if (size > len)
2127 size = len;
2128 ret = action(map, chip, data_offset,
2129 buf, size, reg_prot_offset,
2130 groupno, groupsize);
2131 if (ret < 0)
2132 return ret;
2133 buf += size;
2134 len -= size;
2135 *retlen += size;
2136 }
2137 groupno++;
2138 groups--;
2139 }
2140
2141 /* next OTP region */
2142 if (++field == extp->NumProtectionFields)
2143 break;
2144 reg_prot_offset = otp->ProtRegAddr;
2145 reg_fact_groups = otp->FactGroups;
2146 reg_fact_size = 1 << otp->FactProtRegSize;
2147 reg_user_groups = otp->UserGroups;
2148 reg_user_size = 1 << otp->UserProtRegSize;
2149 otp++;
2150 }
2151 }
2152
2153 return 0;
2154}
2155
2156static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
2157 size_t len, size_t *retlen,
2158 u_char *buf)
2159{
2160 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2161 buf, do_otp_read, 0);
2162}
2163
2164static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
2165 size_t len, size_t *retlen,
2166 u_char *buf)
2167{
2168 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2169 buf, do_otp_read, 1);
2170}
2171
2172static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
2173 size_t len, size_t *retlen,
2174 u_char *buf)
2175{
2176 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2177 buf, do_otp_write, 1);
2178}
2179
2180static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
2181 loff_t from, size_t len)
2182{
2183 size_t retlen;
2184 return cfi_intelext_otp_walk(mtd, from, len, &retlen,
2185 NULL, do_otp_lock, 1);
2186}
2187
2188static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
2189 struct otp_info *buf, size_t len)
2190{
2191 size_t retlen;
2192 int ret;
2193
2194 ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
2195 return ret ? : retlen;
2196}
2197
2198static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
2199 struct otp_info *buf, size_t len)
2200{
2201 size_t retlen;
2202 int ret;
2203
2204 ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
2205 return ret ? : retlen;
2206}
2207
2208#endif
2209
2039static int cfi_intelext_suspend(struct mtd_info *mtd) 2210static int cfi_intelext_suspend(struct mtd_info *mtd)
2040{ 2211{
2041 struct map_info *map = mtd->priv; 2212 struct map_info *map = mtd->priv;
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 96ebb52f24b1..b92e6bfffaf2 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -5,7 +5,7 @@
5 * 5 *
6 * This code is GPL 6 * This code is GPL
7 * 7 *
8 * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $ 8 * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
9 * 9 *
10 * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> 10 * 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
11 * added support for read_oob, write_oob 11 * added support for read_oob, write_oob
@@ -116,6 +116,13 @@ static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
116 len, retlen, buf); 116 len, retlen, buf);
117} 117}
118 118
119static int part_get_user_prot_info (struct mtd_info *mtd,
120 struct otp_info *buf, size_t len)
121{
122 struct mtd_part *part = PART(mtd);
123 return part->master->get_user_prot_info (part->master, buf, len);
124}
125
119static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 126static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
120 size_t *retlen, u_char *buf) 127 size_t *retlen, u_char *buf)
121{ 128{
@@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
124 len, retlen, buf); 131 len, retlen, buf);
125} 132}
126 133
134static int part_get_fact_prot_info (struct mtd_info *mtd,
135 struct otp_info *buf, size_t len)
136{
137 struct mtd_part *part = PART(mtd);
138 return part->master->get_fact_prot_info (part->master, buf, len);
139}
140
127static int part_write (struct mtd_info *mtd, loff_t to, size_t len, 141static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
128 size_t *retlen, const u_char *buf) 142 size_t *retlen, const u_char *buf)
129{ 143{
@@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l
182 len, retlen, buf); 196 len, retlen, buf);
183} 197}
184 198
199static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
200{
201 struct mtd_part *part = PART(mtd);
202 return part->master->lock_user_prot_reg (part->master, from, len);
203}
204
185static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, 205static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
186 unsigned long count, loff_t to, size_t *retlen) 206 unsigned long count, loff_t to, size_t *retlen)
187{ 207{
@@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master,
409 slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; 429 slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
410 if(master->write_user_prot_reg) 430 if(master->write_user_prot_reg)
411 slave->mtd.write_user_prot_reg = part_write_user_prot_reg; 431 slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
432 if(master->lock_user_prot_reg)
433 slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
434 if(master->get_user_prot_info)
435 slave->mtd.get_user_prot_info = part_get_user_prot_info;
436 if(master->get_fact_prot_info)
437 slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
412 if (master->sync) 438 if (master->sync)
413 slave->mtd.sync = part_sync; 439 slave->mtd.sync = part_sync;
414 if (!i && master->suspend && master->resume) { 440 if (!i && master->suspend && master->resume) {
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index d87dc3fbd4ba..76255474a27c 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -1,7 +1,7 @@
1 1
2/* Common Flash Interface structures 2/* Common Flash Interface structures
3 * See http://support.intel.com/design/flash/technote/index.htm 3 * See http://support.intel.com/design/flash/technote/index.htm
4 * $Id: cfi.h,v 1.51 2005/02/05 02:06:16 nico Exp $ 4 * $Id: cfi.h,v 1.52 2005/02/08 17:11:15 nico Exp $
5 */ 5 */
6 6
7#ifndef __MTD_CFI_H__ 7#ifndef __MTD_CFI_H__
@@ -252,7 +252,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int
252 * It looks too long to be inline, but in the common case it should almost all 252 * It looks too long to be inline, but in the common case it should almost all
253 * get optimised away. 253 * get optimised away.
254 */ 254 */
255static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi) 255static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
256{ 256{
257 map_word val = { {0} }; 257 map_word val = { {0} };
258 int wordwidth, words_per_bus, chip_mode, chips_per_word; 258 int wordwidth, words_per_bus, chip_mode, chips_per_word;
diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h
index c66ba812bf90..e778a1ab23c4 100644
--- a/include/linux/mtd/flashchip.h
+++ b/include/linux/mtd/flashchip.h
@@ -6,7 +6,7 @@
6 * 6 *
7 * (C) 2000 Red Hat. GPLd. 7 * (C) 2000 Red Hat. GPLd.
8 * 8 *
9 * $Id: flashchip.h,v 1.15 2004/11/05 22:41:06 nico Exp $ 9 * $Id: flashchip.h,v 1.16 2005/02/08 17:11:15 nico Exp $
10 * 10 *
11 */ 11 */
12 12
@@ -29,6 +29,7 @@ typedef enum {
29 FL_ERASE_SUSPENDED, 29 FL_ERASE_SUSPENDED,
30 FL_WRITING, 30 FL_WRITING,
31 FL_WRITING_TO_BUFFER, 31 FL_WRITING_TO_BUFFER,
32 FL_OTP_WRITE,
32 FL_WRITE_SUSPENDING, 33 FL_WRITE_SUSPENDING,
33 FL_WRITE_SUSPENDED, 34 FL_WRITE_SUSPENDED,
34 FL_PM_SUSPENDED, 35 FL_PM_SUSPENDED,
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index f0268b99c900..8fc6679aa9b1 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -1,6 +1,6 @@
1 1
2/* Overhauled routines for dealing with different mmap regions of flash */ 2/* Overhauled routines for dealing with different mmap regions of flash */
3/* $Id: map.h,v 1.46 2005/01/05 17:09:44 dwmw2 Exp $ */ 3/* $Id: map.h,v 1.47 2005/02/08 17:11:15 nico Exp $ */
4 4
5#ifndef __LINUX_MTD_MAP_H__ 5#ifndef __LINUX_MTD_MAP_H__
6#define __LINUX_MTD_MAP_H__ 6#define __LINUX_MTD_MAP_H__
@@ -263,6 +263,17 @@ static inline map_word map_word_and(struct map_info *map, map_word val1, map_wor
263 return r; 263 return r;
264} 264}
265 265
266static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
267{
268 map_word r;
269 int i;
270
271 for (i=0; i<map_words(map); i++) {
272 r.x[i] = val1.x[i] & ~val2.x[i];
273 }
274 return r;
275}
276
266static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2) 277static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
267{ 278{
268 map_word r; 279 map_word r;
@@ -273,6 +284,7 @@ static inline map_word map_word_or(struct map_info *map, map_word val1, map_word
273 } 284 }
274 return r; 285 return r;
275} 286}
287
276#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b)) 288#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
277 289
278static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) 290static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
@@ -338,6 +350,7 @@ static inline map_word map_word_ff(struct map_info *map)
338 } 350 }
339 return r; 351 return r;
340} 352}
353
341static inline map_word inline_map_read(struct map_info *map, unsigned long ofs) 354static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
342{ 355{
343 map_word r; 356 map_word r;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index b3d134392b31..3aab1b8729e0 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $ 2 * $Id: mtd.h,v 1.57 2005/02/08 17:11:15 nico Exp $
3 * 3 *
4 * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al. 4 * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
5 * 5 *
@@ -113,12 +113,12 @@ struct mtd_info {
113 * flash devices. The user data is one time programmable but the 113 * flash devices. The user data is one time programmable but the
114 * factory data is read only. 114 * factory data is read only.
115 */ 115 */
116 int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); 116 int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
117
118 int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); 117 int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
119 118 int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
120 /* This function is not yet implemented */ 119 int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
121 int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); 120 int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
121 int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
122 122
123 /* kvec-based read/write methods. We need these especially for NAND flash, 123 /* kvec-based read/write methods. We need these especially for NAND flash,
124 with its limited number of write cycles per erase. 124 with its limited number of write cycles per erase.
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index a76ab898f445..091eb571e993 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $ 2 * $Id: mtd-abi.h,v 1.8 2005/02/08 17:11:16 nico Exp $
3 * 3 *
4 * Portions of MTD ABI definition which are shared by kernel and user space 4 * Portions of MTD ABI definition which are shared by kernel and user space
5 */ 5 */
@@ -80,6 +80,12 @@ struct region_info_user {
80 uint32_t regionindex; 80 uint32_t regionindex;
81}; 81};
82 82
83struct otp_info {
84 uint32_t start;
85 uint32_t length;
86 uint32_t locked;
87};
88
83#define MEMGETINFO _IOR('M', 1, struct mtd_info_user) 89#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
84#define MEMERASE _IOW('M', 2, struct erase_info_user) 90#define MEMERASE _IOW('M', 2, struct erase_info_user)
85#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) 91#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)