[MTD] Support for protection register support on Intel FLASH chips
authorNicolas Pitre <nico@cam.org>
Tue, 8 Feb 2005 17:11:19 +0000 (17:11 +0000)
committerThomas Gleixner <tglx@mtd.linutronix.de>
Mon, 23 May 2005 10:25:23 +0000 (12:25 +0200)
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>
drivers/mtd/chips/Kconfig
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/mtdpart.c
include/linux/mtd/cfi.h
include/linux/mtd/flashchip.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/mtd/mtd-abi.h

index d682dbc..f4eda1e 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $
+# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $
 
 menu "RAM/ROM/Flash chip drivers"
        depends on MTD!=n
@@ -155,6 +155,31 @@ config MTD_CFI_I8
          If your flash chips are interleaved in eights - i.e. you have eight
          flash chips addressed by each bus cycle, then say 'Y'.
 
+config MTD_OTP
+       bool "Protection Registers aka one-time programmable (OTP) bits"
+       depends on MTD_CFI_ADV_OPTIONS
+       default n
+       help
+         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.
+
+         The user-programmable Protection Registers contain one-time
+         programmable (OTP) bits; when programmed, register bits cannot be
+         erased. Each Protection Register can be accessed multiple times to
+         program individual bits, as long as the register remains unlocked.
+
+         Each Protection Register has an associated Lock Register bit. When a
+         Lock Register bit is programmed, the associated Protection Register
+         can only be read; it can no longer be programmed. Additionally,
+         because the Lock Register bits themselves are OTP, when programmed,
+         Lock Register bits cannot be erased. Therefore, when a Protection
+         Register is locked, it cannot be unlocked.
+
+         This feature should therefore be used with extreme care. Any mistake
+         in the programming of OTP bits will waste them.
+
 config MTD_CFI_INTELEXT
        tristate "Support for Intel/Sharp flash chips"
        depends on MTD_GEN_PROBE
index c630d75..b3f5acf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.165 2005/02/05 02:06:15 nico Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.167 2005/02/08 17:11:15 nico Exp $
  *
  * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
 #define M50LPW080       0x002F
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
 static void cfi_intelext_sync (struct mtd_info *);
 static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
 static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
+static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
+                                           struct otp_info *, size_t);
+static int cfi_intelext_get_user_prot_info (struct mtd_info *,
+                                           struct otp_info *, size_t);
 static int cfi_intelext_suspend (struct mtd_info *);
 static void cfi_intelext_resume (struct mtd_info *);
 
@@ -423,9 +429,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
                       mtd->eraseregions[i].numblocks);
        }
 
-#if 0
-       mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+#ifdef CONFIG_MTD_OTP
        mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+       mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+       mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
+       mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
+       mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
+       mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
 #endif
 
        /* 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
  resettime:
        timeo = jiffies + HZ;
  retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) {
+       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
                /*
                 * OK. We have possibility for contension on the write/erase
                 * 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
        return ret;
 }
 
-#if 0
-static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
-                                               loff_t from, size_t len,
-                                               size_t *retlen,
-                                               u_char *buf,
-                                               int base_offst, int reg_sz)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-       struct flchip *chip;
-       int ofs_factor = cfi->interleave * cfi->device_type;
-       int count = len;
-       int chip_num, offst;
-       int ret;
-
-       chip_num = ((unsigned int)from/reg_sz);
-       offst = from - (reg_sz*chip_num)+base_offst;
-
-       while (count) {
-       /* Calculate which chip & protection register offset we need */
-
-               if (chip_num >= cfi->numchips)
-                       goto out;
-
-               chip = &cfi->chips[chip_num];
-               
-               spin_lock(chip->mutex);
-               ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
-               if (ret) {
-                       spin_unlock(chip->mutex);
-                       return (len-count)?:ret;
-               }
-
-               xip_disable(map, chip, chip->start);
-
-               if (chip->state != FL_JEDEC_QUERY) {
-                       map_write(map, CMD(0x90), chip->start);
-                       chip->state = FL_JEDEC_QUERY;
-               }
-
-               while (count && ((offst-base_offst) < reg_sz)) {
-                       *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
-                       buf++;
-                       offst++;
-                       count--;
-               }
-
-               xip_enable(map, chip, chip->start);
-               put_chip(map, chip, chip->start);
-               spin_unlock(chip->mutex);
-
-               /* Move on to the next chip */
-               chip_num++;
-               offst = base_offst;
-       }
-       
- out:  
-       return len-count;
-}
-       
-static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-       int base_offst,reg_sz;
-       
-       /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
-               printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-               return 0;
-       }
-
-       base_offst=(1<<extp->FactProtRegSize);
-       reg_sz=(1<<extp->UserProtRegSize);
-
-       return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-
-static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-       int base_offst,reg_sz;
-       
-       /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
-               printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-               return 0;
-       }
-
-       base_offst=0;
-       reg_sz=(1<<extp->FactProtRegSize);
-
-       return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-#endif
-
 static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
-                                    unsigned long adr, map_word datum)
+                                    unsigned long adr, map_word datum, int mode)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       map_word status, status_OK;
+       map_word status, status_OK, write_cmd;
        unsigned long timeo;
        int z, ret=0;
 
@@ -1290,9 +1200,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 
        /* Let's determine this according to the interleave only once */
        status_OK = CMD(0x80);
+       switch (mode) {
+       case FL_WRITING:   write_cmd = CMD(0x40); break;
+       case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
+       default: return -EINVAL;
+       }
 
        spin_lock(chip->mutex);
-       ret = get_chip(map, chip, adr, FL_WRITING);
+       ret = get_chip(map, chip, adr, mode);
        if (ret) {
                spin_unlock(chip->mutex);
                return ret;
@@ -1301,9 +1216,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
        XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
        ENABLE_VPP(map);
        xip_disable(map, chip, adr);
-       map_write(map, CMD(0x40), adr);
+       map_write(map, write_cmd, adr);
        map_write(map, datum, adr);
-       chip->state = FL_WRITING;
+       chip->state = mode;
 
        spin_unlock(chip->mutex);
        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,
        timeo = jiffies + (HZ/2);
        z = 0;
        for (;;) {
-               if (chip->state != FL_WRITING) {
+               if (chip->state != mode) {
                        /* Someone's suspended the write. Sleep */
                        DECLARE_WAITQUEUE(wait, current);
 
@@ -1401,7 +1316,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                datum = map_word_load_partial(map, datum, buf, gap, n);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                                              bus_ofs, datum);
+                                              bus_ofs, datum, FL_WRITING);
                if (ret) 
                        return ret;
 
@@ -1422,7 +1337,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                map_word datum = map_word_load(map, buf);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                               ofs, datum);
+                                      ofs, datum, FL_WRITING);
                if (ret)
                        return ret;
 
@@ -1446,7 +1361,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                datum = map_word_load_partial(map, datum, buf, 0, len);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                                              ofs, datum);
+                                      ofs, datum, FL_WRITING);
                if (ret) 
                        return ret;
                
@@ -2036,6 +1951,262 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
        return ret;
 }
 
+#ifdef CONFIG_MTD_OTP
+
+typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, 
+                       u_long data_offset, u_char *buf, u_int size,
+                       u_long prot_offset, u_int groupno, u_int groupsize);
+
+static int __xipram
+do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
+           u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       int ret;
+
+       spin_lock(chip->mutex);
+       ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
+       if (ret) {
+               spin_unlock(chip->mutex);
+               return ret;
+       }
+
+       /* let's ensure we're not reading back cached data from array mode */
+       if (map->inval_cache)
+               map->inval_cache(map, chip->start + offset, size);
+
+       xip_disable(map, chip, chip->start);
+       if (chip->state != FL_JEDEC_QUERY) {
+               map_write(map, CMD(0x90), chip->start);
+               chip->state = FL_JEDEC_QUERY;
+       }
+       map_copy_from(map, buf, chip->start + offset, size);
+       xip_enable(map, chip, chip->start);
+
+       /* then ensure we don't keep OTP data in the cache */
+       if (map->inval_cache)
+               map->inval_cache(map, chip->start + offset, size);
+
+       put_chip(map, chip, chip->start);
+       spin_unlock(chip->mutex);
+       return 0;
+}
+
+static int
+do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
+            u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       int ret;
+
+       while (size) {
+               unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
+               int gap = offset - bus_ofs;
+               int n = min_t(int, size, map_bankwidth(map)-gap);
+               map_word datum = map_word_ff(map);
+
+               datum = map_word_load_partial(map, datum, buf, gap, n);
+               ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
+               if (ret) 
+                       return ret;
+
+               offset += n;
+               buf += n;
+               size -= n;
+       }
+
+       return 0;
+}
+
+static int
+do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
+           u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       map_word datum;
+
+       /* make sure area matches group boundaries */
+       if (offset != 0 || size != grpsz)
+               return -EXDEV;
+
+       datum = map_word_ff(map);
+       datum = map_word_clr(map, datum, CMD(1 << grpno));
+       return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
+}
+
+static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
+                                size_t *retlen, u_char *buf,
+                                otp_op_t action, int user_regs)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+       struct flchip *chip;
+       struct cfi_intelext_otpinfo *otp;
+       u_long devsize, reg_prot_offset, data_offset;
+       u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
+       u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
+       int ret;
+
+       *retlen = 0;
+
+       /* Check that we actually have some OTP registers */
+       if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
+               return -ENODATA;
+
+       /* we need real chips here not virtual ones */
+       devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
+       chip_step = devsize >> cfi->chipshift;
+
+       for (chip_num = 0; chip_num < cfi->numchips; chip_num += chip_step) {
+               chip = &cfi->chips[chip_num];
+               otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
+
+               /* first OTP region */
+               field = 0;
+               reg_prot_offset = extp->ProtRegAddr;
+               reg_fact_groups = 1;
+               reg_fact_size = 1 << extp->FactProtRegSize;
+               reg_user_groups = 1;
+               reg_user_size = 1 << extp->UserProtRegSize;
+
+               while (len > 0) {
+                       /* flash geometry fixup */
+                       data_offset = reg_prot_offset + 1;
+                       data_offset *= cfi->interleave * cfi->device_type;
+                       reg_prot_offset *= cfi->interleave * cfi->device_type;
+                       reg_fact_size *= cfi->interleave;
+                       reg_user_size *= cfi->interleave;
+
+                       if (user_regs) {
+                               groups = reg_user_groups;
+                               groupsize = reg_user_size;
+                               /* skip over factory reg area */
+                               groupno = reg_fact_groups;
+                               data_offset += reg_fact_groups * reg_fact_size;
+                       } else {
+                               groups = reg_fact_groups;
+                               groupsize = reg_fact_size;
+                               groupno = 0;
+                       }
+
+                       while (groups > 0) {
+                               if (!action) {
+                                       /*
+                                        * Special case: if action is NULL
+                                        * we fill buf with otp_info records.
+                                        */
+                                       struct otp_info *otpinfo;
+                                       map_word lockword;
+                                       len -= sizeof(struct otp_info);
+                                       if (len <= 0)
+                                               return -ENOSPC;
+                                       ret = do_otp_read(map, chip,
+                                                         reg_prot_offset,
+                                                         (u_char *)&lockword,
+                                                         map_bankwidth(map),
+                                                         0, 0,  0);
+                                       if (ret)
+                                               return ret;
+                                       otpinfo = (struct otp_info *)buf;
+                                       otpinfo->start = from;
+                                       otpinfo->length = groupsize;
+                                       otpinfo->locked =
+                                          !map_word_bitsset(map, lockword,
+                                                            CMD(1 << groupno));
+                                       from += groupsize;
+                                       buf += sizeof(*otpinfo);
+                                       *retlen += sizeof(*otpinfo);
+                               } else if (from >= groupsize) {
+                                       from -= groupsize;
+                               } else {
+                                       int size = groupsize;
+                                       data_offset += from;
+                                       size -= from;
+                                       from = 0;
+                                       if (size > len)
+                                               size = len;
+                                       ret = action(map, chip, data_offset,
+                                                    buf, size, reg_prot_offset,
+                                                    groupno, groupsize);
+                                       if (ret < 0)
+                                               return ret;
+                                       buf += size;
+                                       len -= size;
+                                       *retlen += size;
+                               }
+                               groupno++;
+                               groups--;
+                       }
+
+                       /* next OTP region */
+                       if (++field == extp->NumProtectionFields)
+                               break;
+                       reg_prot_offset = otp->ProtRegAddr;
+                       reg_fact_groups = otp->FactGroups;
+                       reg_fact_size = 1 << otp->FactProtRegSize;
+                       reg_user_groups = otp->UserGroups;
+                       reg_user_size = 1 << otp->UserProtRegSize;
+                       otp++;
+               }
+       }
+
+       return 0;
+}
+
+static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+                                          size_t len, size_t *retlen,
+                                           u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_read, 0);
+}
+
+static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+                                          size_t len, size_t *retlen,
+                                           u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_read, 1);
+}
+
+static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+                                           size_t len, size_t *retlen,
+                                            u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_write, 1);
+}
+
+static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
+                                          loff_t from, size_t len)
+{
+       size_t retlen;
+       return cfi_intelext_otp_walk(mtd, from, len, &retlen,
+                                    NULL, do_otp_lock, 1);
+}
+
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, 
+                                          struct otp_info *buf, size_t len)
+{
+       size_t retlen;
+       int ret;
+
+       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
+       return ret ? : retlen;
+}
+
+static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
+                                          struct otp_info *buf, size_t len)
+{
+       size_t retlen;
+       int ret;
+
+       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
+       return ret ? : retlen;
+}
+
+#endif
+
 static int cfi_intelext_suspend(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
index 96ebb52..b92e6bf 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
  *
  *     02-21-2002      Thomas Gleixner <gleixner@autronix.de>
  *                     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
                                        len, retlen, buf);
 }
 
+static int part_get_user_prot_info (struct mtd_info *mtd,
+                                   struct otp_info *buf, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->get_user_prot_info (part->master, buf, len);
+}
+
 static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
                        size_t *retlen, u_char *buf)
 {
@@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
                                        len, retlen, buf);
 }
 
+static int part_get_fact_prot_info (struct mtd_info *mtd,
+                                   struct otp_info *buf, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->get_fact_prot_info (part->master, buf, len);
+}
+
 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
                        size_t *retlen, const u_char *buf)
 {
@@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l
                                        len, retlen, buf);
 }
 
+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) 
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->lock_user_prot_reg (part->master, from, len);
+}
+
 static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
                         unsigned long count, loff_t to, size_t *retlen)
 {
@@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
                if(master->write_user_prot_reg)
                        slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
+               if(master->lock_user_prot_reg)
+                       slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
+               if(master->get_user_prot_info)
+                       slave->mtd.get_user_prot_info = part_get_user_prot_info;
+               if(master->get_fact_prot_info)
+                       slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
                if (master->sync)
                        slave->mtd.sync = part_sync;
                if (!i && master->suspend && master->resume) {
index d87dc3f..7625547 100644 (file)
@@ -1,7 +1,7 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.51 2005/02/05 02:06:16 nico Exp $
+ * $Id: cfi.h,v 1.52 2005/02/08 17:11:15 nico Exp $
  */
 
 #ifndef __MTD_CFI_H__
@@ -252,7 +252,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int
  * It looks too long to be inline, but in the common case it should almost all
  * get optimised away. 
  */
-static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
 {
        map_word val = { {0} };
        int wordwidth, words_per_bus, chip_mode, chips_per_word;
index c66ba81..e778a1a 100644 (file)
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.15 2004/11/05 22:41:06 nico Exp $
+ * $Id: flashchip.h,v 1.16 2005/02/08 17:11:15 nico Exp $
  *
  */
 
@@ -29,6 +29,7 @@ typedef enum {
        FL_ERASE_SUSPENDED,
        FL_WRITING,
        FL_WRITING_TO_BUFFER,
+       FL_OTP_WRITE,
        FL_WRITE_SUSPENDING,
        FL_WRITE_SUSPENDED,
        FL_PM_SUSPENDED,
index f0268b9..8fc6679 100644 (file)
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.46 2005/01/05 17:09:44 dwmw2 Exp $ */
+/* $Id: map.h,v 1.47 2005/02/08 17:11:15 nico Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #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
        return r;
 }
 
+static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
+{
+       map_word r;
+       int i;
+
+       for (i=0; i<map_words(map); i++) {
+               r.x[i] = val1.x[i] & ~val2.x[i];
+       }
+       return r;
+}
+
 static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
 {
        map_word r;
@@ -273,6 +284,7 @@ static inline map_word map_word_or(struct map_info *map, map_word val1, map_word
        }
        return r;
 }
+
 #define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
 
 static 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)
        }
        return r;
 }
+
 static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
 {
        map_word r;
index b3d1343..3aab1b8 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $
+ * $Id: mtd.h,v 1.57 2005/02/08 17:11:15 nico Exp $
  *
  * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
  *
@@ -113,12 +113,12 @@ struct mtd_info {
         * flash devices. The user data is one time programmable but the
         * factory data is read only. 
         */
-       int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
+       int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
        int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
-       /* This function is not yet implemented */
+       int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
+       int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+       int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
 
        /* kvec-based read/write methods. We need these especially for NAND flash,
           with its limited number of write cycles per erase.
index a76ab89..091eb57 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $
+ * $Id: mtd-abi.h,v 1.8 2005/02/08 17:11:16 nico Exp $
  *
  * Portions of MTD ABI definition which are shared by kernel and user space 
  */
@@ -80,6 +80,12 @@ struct region_info_user {
        uint32_t regionindex;
 };
 
+struct otp_info {
+       uint32_t start;
+       uint32_t length;
+       uint32_t locked;
+};
+
 #define MEMGETINFO              _IOR('M', 1, struct mtd_info_user)
 #define MEMERASE                _IOW('M', 2, struct erase_info_user)
 #define MEMWRITEOOB             _IOWR('M', 3, struct mtd_oob_buf)