diff options
| -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) | |||
