diff options
author | Rodolfo Giometti <giometti@enneenne.com> | 2007-03-27 01:45:43 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-04-02 14:12:23 -0400 |
commit | 0ecbc81adfcb9f15f86b05ff576b342ce81bbef8 (patch) | |
tree | 037741dc830ffff7e21b4f1ed343a613e0752414 | |
parent | 8dc64fca75b631142f282047d7f6ae9e8af82543 (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>
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 93 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 1 |
2 files changed, 91 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 | */ | ||
229 | static 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 | |||
223 | static struct cfi_fixup cfi_fixup_table[] = { | 235 | static 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 | 1842 | static int __xipram do_getlockstatus_oneblock(struct map_info *map, |
1829 | static 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 | ||
1860 | static 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 | ||
2241 | static 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 | |||
2219 | static int cfi_intelext_suspend(struct mtd_info *mtd) | 2267 | static 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 | ||
2341 | static 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 | |||
2288 | static void cfi_intelext_resume(struct mtd_info *mtd) | 2363 | static 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 | ||
2312 | static int cfi_intelext_reset(struct mtd_info *mtd) | 2392 | static 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 | ||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 3d956c3abb31..45d482ce8397 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -53,6 +53,7 @@ struct mtd_erase_region_info { | |||
53 | u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ | 53 | u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ |
54 | u_int32_t erasesize; /* For this region */ | 54 | u_int32_t erasesize; /* For this region */ |
55 | u_int32_t numblocks; /* Number of blocks of erasesize in this region */ | 55 | u_int32_t numblocks; /* Number of blocks of erasesize in this region */ |
56 | unsigned long *lockmap; /* If keeping bitmap of locks */ | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | /* | 59 | /* |