Patchwork Re: Does NOR chip drivers support PPB protection

login
register
mail settings
Submitter Hoyler, Gernot
Date April 13, 2011, 10:21 a.m.
Message ID <1302690114.23151.51.camel@MUC-CSE-01.spansion.com>
Download mbox | patch
Permalink /patch/90984/
State New
Headers show

Comments

Hoyler, Gernot - April 13, 2011, 10:21 a.m.
Currently, cfi_cmdset_0002.c does not support PPB locking of sectors - mainly
because it is hard to check for older devices if they support it or not (newer 
devices indicate this via CFI word 0x49, 0x08 means PPB locking is supported).

On the other hand, adding PPB support is not too complicated. The major hurdle
is the MTD lock/unlock logic which assumes that sectors can be locked and unlocked
individually. With the PPB bits, sectors can be locked individually but can be 
unlocked only together as a group.

So if you want to use the existing MTD lock infrastructure (which is normally 
unused by the AMD/Spansion chip driver) to set PPB bits then you can apply below
changes (older kernel version). Afterwards, you can lock sectors, i.e. set the 
corresponding PPB bit via the "flash_lock" mtd utility. Similarly, you could 
implement an unlock function and use flash_unlock, however, note that all sectors
will be unlocked (!) in this case whenever you use flash_unlock. Maybe it would 
be better to develop a new "flash_unlockall" utility instead to clarify this.



@@ -270,6 +267,7 @@
 	mtd->sync    = cfi_amdstd_sync;
 	mtd->suspend = cfi_amdstd_suspend;
 	mtd->resume  = cfi_amdstd_resume;
+	mtd->lock    = cfi_amdstd_lock;
 	mtd->flags   = MTD_CAP_NORFLASH;
 	mtd->name    = map->name;
 	mtd->writesize = 1;
@@ -1869,6 +1876,53 @@
 	kfree(mtd->erasereg+	ions);
 }
 
+static int __xipram do_lock_oneblock(struct map_info *map, struct flchip *chip,
+				       unsigned long adr, int len, void *thunk)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	int udelay;
+	int ret;
+
+	adr += chip->start;
+
+	spin_lock(chip->mutex);
+	ret = get_chip(map, chip, adr, FL_LOCKING);
+	if (ret) {
+		spin_unlock(chip->mutex);
+		return ret;
+	}
+
+	XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
+	ENABLE_VPP(map);
+	xip_disable(map, chip, adr);
+
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0xC0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	map_write(map, CMD(0x00), adr);
+	chip->state = FL_LOCKING;
+
+	udelay = (1 << cfi->cfiq->WordWriteTimeoutTyp) * (1 << cfi->cfiq->WordWriteTimeoutMax);
+	INVALIDATE_CACHE_UDELAY(map, chip, adr, map_bankwidth(map), udelay);
+	/* wait max word program time */
+
+	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+        
+	xip_enable(map, chip, adr);
+        
+	chip->state = FL_READY;
+	put_chip(map, chip, adr);
+	spin_unlock(chip->mutex);
+	return ret;
+}
+
+static int cfi_amdstd_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	return cfi_varsize_frob(mtd, do_lock_oneblock, ofs, len, 0);
+}
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
 MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
RAGHAVENDRA V K - April 13, 2011, 10:53 a.m.
Hi Gernot,

Thanks for the info. The datasheet mentions that if the PPB freeze bit
is set, the only way to unlock this is to issue a (hardware) reset to
the flash chip. So if we are willing to use the freeze bit that we
need some callback into the chip specific driver (mapping driver) that
can issue a reset. Comments?


RAGHAVENDRA.V.K.



On Wed, Apr 13, 2011 at 3:51 PM, Gernot Hoyler
<Gernot.Hoyler@spansion.com> wrote:
> Currently, cfi_cmdset_0002.c does not support PPB locking of sectors - mainly
> because it is hard to check for older devices if they support it or not (newer
> devices indicate this via CFI word 0x49, 0x08 means PPB locking is supported).
>
> On the other hand, adding PPB support is not too complicated. The major hurdle
> is the MTD lock/unlock logic which assumes that sectors can be locked and unlocked
> individually. With the PPB bits, sectors can be locked individually but can be
> unlocked only together as a group.
>
> So if you want to use the existing MTD lock infrastructure (which is normally
> unused by the AMD/Spansion chip driver) to set PPB bits then you can apply below
> changes (older kernel version). Afterwards, you can lock sectors, i.e. set the
> corresponding PPB bit via the "flash_lock" mtd utility. Similarly, you could
> implement an unlock function and use flash_unlock, however, note that all sectors
> will be unlocked (!) in this case whenever you use flash_unlock. Maybe it would
> be better to develop a new "flash_unlockall" utility instead to clarify this.
>
>
> --- cfi_cmdset_0002.c.org       2007-12-17 13:46:08.000000000 +0100
> +++ cfi_cmdset_0002.c   2007-12-17 13:46:19.000000000 +0100
> @@ -59,7 +59,8 @@
>  static void cfi_amdstd_sync (struct mtd_info *);
>  static int cfi_amdstd_suspend (struct mtd_info *);
>  static void cfi_amdstd_resume (struct mtd_info *);mtdInfo.size;
> +static int cfi_amdstd_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
>  static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
>
>  static void cfi_amdstd_destroy(struct mtd_info *);
>
>
> @@ -270,6 +267,7 @@
>        mtd->sync    = cfi_amdstd_sync;
>        mtd->suspend = cfi_amdstd_suspend;
>        mtd->resume  = cfi_amdstd_resume;
> +       mtd->lock    = cfi_amdstd_lock;
>        mtd->flags   = MTD_CAP_NORFLASH;
>        mtd->name    = map->name;
>        mtd->writesize = 1;
> @@ -1869,6 +1876,53 @@
>        kfree(mtd->erasereg+    ions);
>  }
>
> +static int __xipram do_lock_oneblock(struct map_info *map, struct flchip *chip,
> +                                      unsigned long adr, int len, void *thunk)
> +{
> +       struct cfi_private *cfi = map->fldrv_priv;
> +       int udelay;
> +       int ret;
> +
> +       adr += chip->start;
> +
> +       spin_lock(chip->mutex);
> +       ret = get_chip(map, chip, adr, FL_LOCKING);
> +       if (ret) {
> +               spin_unlock(chip->mutex);
> +               return ret;
> +       }
> +
> +       XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
> +       ENABLE_VPP(map);
> +       xip_disable(map, chip, adr);
> +
> +       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
> +       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
> +       cfi_send_gen_cmd(0xC0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
> +       cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
> +       map_write(map, CMD(0x00), adr);
> +       chip->state = FL_LOCKING;
> +
> +       udelay = (1 << cfi->cfiq->WordWriteTimeoutTyp) * (1 << cfi->cfiq->WordWriteTimeoutMax);
> +       INVALIDATE_CACHE_UDELAY(map, chip, adr, map_bankwidth(map), udelay);
> +       /* wait max word program time */
> +
> +       cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
> +       cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
> +
> +       xip_enable(map, chip, adr);
> +
> +       chip->state = FL_READY;
> +       put_chip(map, chip, adr);
> +       spin_unlock(chip->mutex);
> +       return ret;
> +}
> +
> +static int cfi_amdstd_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
> +{
> +       return cfi_varsize_frob(mtd, do_lock_oneblock, ofs, len, 0);
> +}
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
>  MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
>
>
>
Hoyler, Gernot - April 13, 2011, 11:47 a.m.
> So if we are willing to use the freeze bit that we need some callback
> into the chip specific driver (mapping driver) that can issue a reset.
> Comments? 

Normally, the purpose of the PPB lock bit is to prevent users from
changing the PPB bits/settings after initial setup. In this case, you
program your image to flash and lock certain sectors (e.g. on a tester
or factory in-system programming). Afterwards you set the PPB lock bit
pretty early in the boot phase (e.g. boot loader or boot code) to
protect both the sectors and their PPB bits.

Patch

--- cfi_cmdset_0002.c.org	2007-12-17 13:46:08.000000000 +0100
+++ cfi_cmdset_0002.c	2007-12-17 13:46:19.000000000 +0100
@@ -59,7 +59,8 @@ 
 static void cfi_amdstd_sync (struct mtd_info *);
 static int cfi_amdstd_suspend (struct mtd_info *);
 static void cfi_amdstd_resume (struct mtd_info *);mtdInfo.size;
+static int cfi_amdstd_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
 static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 
 static void cfi_amdstd_destroy(struct mtd_info *);