aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRodolfo Giometti <giometti@enneenne.com>2007-03-27 01:45:43 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-04-02 14:12:23 -0400
commit0ecbc81adfcb9f15f86b05ff576b342ce81bbef8 (patch)
tree037741dc830ffff7e21b4f1ed343a613e0752414 /drivers
parent8dc64fca75b631142f282047d7f6ae9e8af82543 (diff)
[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: Rodolfo Giometti <giometti@enneenne.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c93
1 files changed, 90 insertions, 3 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index f334959a335b..2f19fa78d24a 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -15,6 +15,8 @@
15 * - optimized write buffer method 15 * - optimized write buffer method
16 * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com> 16 * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
17 * - reworked lock/unlock/erase support for var size flash 17 * - reworked lock/unlock/erase support for var size flash
18 * 21/03/2007 Rodolfo Giometti <giometti@linux.it>
19 * - auto unlock sectors on resume for auto locking flash on power up
18 */ 20 */
19 21
20#include <linux/module.h> 22#include <linux/module.h>
@@ -30,6 +32,7 @@
30#include <linux/delay.h> 32#include <linux/delay.h>
31#include <linux/interrupt.h> 33#include <linux/interrupt.h>
32#include <linux/reboot.h> 34#include <linux/reboot.h>
35#include <linux/bitmap.h>
33#include <linux/mtd/xip.h> 36#include <linux/mtd/xip.h>
34#include <linux/mtd/map.h> 37#include <linux/mtd/map.h>
35#include <linux/mtd/mtd.h> 38#include <linux/mtd/mtd.h>
@@ -220,6 +223,15 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
220 } 223 }
221} 224}
222 225
226/*
227 * Some chips power-up with all sectors locked by default.
228 */
229static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
230{
231 printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
232 mtd->flags |= MTD_STUPID_LOCK;
233}
234
223static struct cfi_fixup cfi_fixup_table[] = { 235static struct cfi_fixup cfi_fixup_table[] = {
224#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE 236#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
225 { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, 237 { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
@@ -232,6 +244,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
232#endif 244#endif
233 { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, 245 { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
234 { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, 246 { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
247 { MANUFACTURER_INTEL, 0x891c, fixup_use_powerup_lock, NULL, },
235 { 0, 0, NULL, NULL } 248 { 0, 0, NULL, NULL }
236}; 249};
237 250
@@ -460,6 +473,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
460 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; 473 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
461 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; 474 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
462 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; 475 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
476 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL);
463 } 477 }
464 offset += (ersize * ernum); 478 offset += (ersize * ernum);
465 } 479 }
@@ -1825,8 +1839,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
1825 } 1839 }
1826} 1840}
1827 1841
1828#ifdef DEBUG_LOCK_BITS 1842static int __xipram do_getlockstatus_oneblock(struct map_info *map,
1829static int __xipram do_printlockstatus_oneblock(struct map_info *map,
1830 struct flchip *chip, 1843 struct flchip *chip,
1831 unsigned long adr, 1844 unsigned long adr,
1832 int len, void *thunk) 1845 int len, void *thunk)
@@ -1840,8 +1853,17 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
1840 chip->state = FL_JEDEC_QUERY; 1853 chip->state = FL_JEDEC_QUERY;
1841 status = cfi_read_query(map, adr+(2*ofs_factor)); 1854 status = cfi_read_query(map, adr+(2*ofs_factor));
1842 xip_enable(map, chip, 0); 1855 xip_enable(map, chip, 0);
1856 return status;
1857}
1858
1859#ifdef DEBUG_LOCK_BITS
1860static int __xipram do_printlockstatus_oneblock(struct map_info *map,
1861 struct flchip *chip,
1862 unsigned long adr,
1863 int len, void *thunk)
1864{
1843 printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", 1865 printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
1844 adr, status); 1866 adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));
1845 return 0; 1867 return 0;
1846} 1868}
1847#endif 1869#endif
@@ -2216,14 +2238,45 @@ static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
2216 2238
2217#endif 2239#endif
2218 2240
2241static void cfi_intelext_save_locks(struct mtd_info *mtd)
2242{
2243 struct mtd_erase_region_info *region;
2244 int block, status, i;
2245 unsigned long adr;
2246 size_t len;
2247
2248 for (i = 0; i < mtd->numeraseregions; i++) {
2249 region = &mtd->eraseregions[i];
2250 if (!region->lockmap)
2251 continue;
2252
2253 for (block = 0; block < region->numblocks; block++){
2254 len = region->erasesize;
2255 adr = region->offset + block * len;
2256
2257 status = cfi_varsize_frob(mtd,
2258 do_getlockstatus_oneblock, adr, len, 0);
2259 if (status)
2260 set_bit(block, region->lockmap);
2261 else
2262 clear_bit(block, region->lockmap);
2263 }
2264 }
2265}
2266
2219static int cfi_intelext_suspend(struct mtd_info *mtd) 2267static int cfi_intelext_suspend(struct mtd_info *mtd)
2220{ 2268{
2221 struct map_info *map = mtd->priv; 2269 struct map_info *map = mtd->priv;
2222 struct cfi_private *cfi = map->fldrv_priv; 2270 struct cfi_private *cfi = map->fldrv_priv;
2271 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
2223 int i; 2272 int i;
2224 struct flchip *chip; 2273 struct flchip *chip;
2225 int ret = 0; 2274 int ret = 0;
2226 2275
2276 if ((mtd->flags & MTD_STUPID_LOCK)
2277 && extp && (extp->FeatureSupport & (1 << 5)))
2278 cfi_intelext_save_locks(mtd);
2279
2227 for (i=0; !ret && i<cfi->numchips; i++) { 2280 for (i=0; !ret && i<cfi->numchips; i++) {
2228 chip = &cfi->chips[i]; 2281 chip = &cfi->chips[i];
2229 2282
@@ -2285,10 +2338,33 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
2285 return ret; 2338 return ret;
2286} 2339}
2287 2340
2341static void cfi_intelext_restore_locks(struct mtd_info *mtd)
2342{
2343 struct mtd_erase_region_info *region;
2344 int block, i;
2345 unsigned long adr;
2346 size_t len;
2347
2348 for (i = 0; i < mtd->numeraseregions; i++) {
2349 region = &mtd->eraseregions[i];
2350 if (!region->lockmap)
2351 continue;
2352
2353 for (block = 0; block < region->numblocks; block++) {
2354 len = region->erasesize;
2355 adr = region->offset + block * len;
2356
2357 if (!test_bit(block, region->lockmap))
2358 cfi_intelext_unlock(mtd, adr, len);
2359 }
2360 }
2361}
2362
2288static void cfi_intelext_resume(struct mtd_info *mtd) 2363static void cfi_intelext_resume(struct mtd_info *mtd)
2289{ 2364{
2290 struct map_info *map = mtd->priv; 2365 struct map_info *map = mtd->priv;
2291 struct cfi_private *cfi = map->fldrv_priv; 2366 struct cfi_private *cfi = map->fldrv_priv;
2367 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
2292 int i; 2368 int i;
2293 struct flchip *chip; 2369 struct flchip *chip;
2294 2370
@@ -2307,6 +2383,10 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
2307 2383
2308 spin_unlock(chip->mutex); 2384 spin_unlock(chip->mutex);
2309 } 2385 }
2386
2387 if ((mtd->flags & MTD_STUPID_LOCK)
2388 && extp && (extp->FeatureSupport & (1 << 5)))
2389 cfi_intelext_restore_locks(mtd);
2310} 2390}
2311 2391
2312static int cfi_intelext_reset(struct mtd_info *mtd) 2392static int cfi_intelext_reset(struct mtd_info *mtd)
@@ -2347,12 +2427,19 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
2347{ 2427{
2348 struct map_info *map = mtd->priv; 2428 struct map_info *map = mtd->priv;
2349 struct cfi_private *cfi = map->fldrv_priv; 2429 struct cfi_private *cfi = map->fldrv_priv;
2430 struct mtd_erase_region_info *region;
2431 int i;
2350 cfi_intelext_reset(mtd); 2432 cfi_intelext_reset(mtd);
2351 unregister_reboot_notifier(&mtd->reboot_notifier); 2433 unregister_reboot_notifier(&mtd->reboot_notifier);
2352 kfree(cfi->cmdset_priv); 2434 kfree(cfi->cmdset_priv);
2353 kfree(cfi->cfiq); 2435 kfree(cfi->cfiq);
2354 kfree(cfi->chips[0].priv); 2436 kfree(cfi->chips[0].priv);
2355 kfree(cfi); 2437 kfree(cfi);
2438 for (i = 0; i < mtd->numeraseregions; i++) {
2439 region = &mtd->eraseregions[i];
2440 if (region->lockmap)
2441 kfree(region->lockmap);
2442 }
2356 kfree(mtd->eraseregions); 2443 kfree(mtd->eraseregions);
2357} 2444}
2358 2445