Commit 0ecbc81a authored by Rodolfo Giometti's avatar Rodolfo Giometti Committed by David Woodhouse

[MTD] [NOR] Support for auto locking flash on power up

Auto unlock sectors on resume for auto locking flash on power up.
Signed-off-by: default avatarRodolfo Giometti <giometti@enneenne.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 8dc64fca
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
* - optimized write buffer method * - optimized write buffer method
* 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com> * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
* - reworked lock/unlock/erase support for var size flash * - reworked lock/unlock/erase support for var size flash
* 21/03/2007 Rodolfo Giometti <giometti@linux.it>
* - auto unlock sectors on resume for auto locking flash on power up
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -30,6 +32,7 @@ ...@@ -30,6 +32,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/bitmap.h>
#include <linux/mtd/xip.h> #include <linux/mtd/xip.h>
#include <linux/mtd/map.h> #include <linux/mtd/map.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
...@@ -220,6 +223,15 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) ...@@ -220,6 +223,15 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
} }
} }
/*
* Some chips power-up with all sectors locked by default.
*/
static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
{
printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
mtd->flags |= MTD_STUPID_LOCK;
}
static struct cfi_fixup cfi_fixup_table[] = { static struct cfi_fixup cfi_fixup_table[] = {
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
...@@ -232,6 +244,7 @@ static struct cfi_fixup cfi_fixup_table[] = { ...@@ -232,6 +244,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
#endif #endif
{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
{ MANUFACTURER_INTEL, 0x891c, fixup_use_powerup_lock, NULL, },
{ 0, 0, NULL, NULL } { 0, 0, NULL, NULL }
}; };
...@@ -460,6 +473,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) ...@@ -460,6 +473,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL);
} }
offset += (ersize * ernum); offset += (ersize * ernum);
} }
...@@ -1825,8 +1839,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) ...@@ -1825,8 +1839,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
} }
} }
#ifdef DEBUG_LOCK_BITS static int __xipram do_getlockstatus_oneblock(struct map_info *map,
static int __xipram do_printlockstatus_oneblock(struct map_info *map,
struct flchip *chip, struct flchip *chip,
unsigned long adr, unsigned long adr,
int len, void *thunk) int len, void *thunk)
...@@ -1840,8 +1853,17 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map, ...@@ -1840,8 +1853,17 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
chip->state = FL_JEDEC_QUERY; chip->state = FL_JEDEC_QUERY;
status = cfi_read_query(map, adr+(2*ofs_factor)); status = cfi_read_query(map, adr+(2*ofs_factor));
xip_enable(map, chip, 0); xip_enable(map, chip, 0);
return status;
}
#ifdef DEBUG_LOCK_BITS
static int __xipram do_printlockstatus_oneblock(struct map_info *map,
struct flchip *chip,
unsigned long adr,
int len, void *thunk)
{
printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
adr, status); adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));
return 0; return 0;
} }
#endif #endif
...@@ -2216,14 +2238,45 @@ static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, ...@@ -2216,14 +2238,45 @@ static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
#endif #endif
static void cfi_intelext_save_locks(struct mtd_info *mtd)
{
struct mtd_erase_region_info *region;
int block, status, i;
unsigned long adr;
size_t len;
for (i = 0; i < mtd->numeraseregions; i++) {
region = &mtd->eraseregions[i];
if (!region->lockmap)
continue;
for (block = 0; block < region->numblocks; block++){
len = region->erasesize;
adr = region->offset + block * len;
status = cfi_varsize_frob(mtd,
do_getlockstatus_oneblock, adr, len, 0);
if (status)
set_bit(block, region->lockmap);
else
clear_bit(block, region->lockmap);
}
}
}
static int cfi_intelext_suspend(struct mtd_info *mtd) static int cfi_intelext_suspend(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
int i; int i;
struct flchip *chip; struct flchip *chip;
int ret = 0; int ret = 0;
if ((mtd->flags & MTD_STUPID_LOCK)
&& extp && (extp->FeatureSupport & (1 << 5)))
cfi_intelext_save_locks(mtd);
for (i=0; !ret && i<cfi->numchips; i++) { for (i=0; !ret && i<cfi->numchips; i++) {
chip = &cfi->chips[i]; chip = &cfi->chips[i];
...@@ -2285,10 +2338,33 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) ...@@ -2285,10 +2338,33 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
return ret; return ret;
} }
static void cfi_intelext_restore_locks(struct mtd_info *mtd)
{
struct mtd_erase_region_info *region;
int block, i;
unsigned long adr;
size_t len;
for (i = 0; i < mtd->numeraseregions; i++) {
region = &mtd->eraseregions[i];
if (!region->lockmap)
continue;
for (block = 0; block < region->numblocks; block++) {
len = region->erasesize;
adr = region->offset + block * len;
if (!test_bit(block, region->lockmap))
cfi_intelext_unlock(mtd, adr, len);
}
}
}
static void cfi_intelext_resume(struct mtd_info *mtd) static void cfi_intelext_resume(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
int i; int i;
struct flchip *chip; struct flchip *chip;
...@@ -2307,6 +2383,10 @@ static void cfi_intelext_resume(struct mtd_info *mtd) ...@@ -2307,6 +2383,10 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
spin_unlock(chip->mutex); spin_unlock(chip->mutex);
} }
if ((mtd->flags & MTD_STUPID_LOCK)
&& extp && (extp->FeatureSupport & (1 << 5)))
cfi_intelext_restore_locks(mtd);
} }
static int cfi_intelext_reset(struct mtd_info *mtd) static int cfi_intelext_reset(struct mtd_info *mtd)
...@@ -2347,12 +2427,19 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) ...@@ -2347,12 +2427,19 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
struct mtd_erase_region_info *region;
int i;
cfi_intelext_reset(mtd); cfi_intelext_reset(mtd);
unregister_reboot_notifier(&mtd->reboot_notifier); unregister_reboot_notifier(&mtd->reboot_notifier);
kfree(cfi->cmdset_priv); kfree(cfi->cmdset_priv);
kfree(cfi->cfiq); kfree(cfi->cfiq);
kfree(cfi->chips[0].priv); kfree(cfi->chips[0].priv);
kfree(cfi); kfree(cfi);
for (i = 0; i < mtd->numeraseregions; i++) {
region = &mtd->eraseregions[i];
if (region->lockmap)
kfree(region->lockmap);
}
kfree(mtd->eraseregions); kfree(mtd->eraseregions);
} }
......
...@@ -53,6 +53,7 @@ struct mtd_erase_region_info { ...@@ -53,6 +53,7 @@ struct mtd_erase_region_info {
u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ u_int32_t offset; /* At which this region starts, from the beginning of the MTD */
u_int32_t erasesize; /* For this region */ u_int32_t erasesize; /* For this region */
u_int32_t numblocks; /* Number of blocks of erasesize in this region */ u_int32_t numblocks; /* Number of blocks of erasesize in this region */
unsigned long *lockmap; /* If keeping bitmap of locks */
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment