diff options
| author | Gerlando Falauto <gerlando.falauto@keymile.com> | 2012-07-03 03:09:47 -0400 |
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-07-16 16:37:15 -0400 |
| commit | 420962884379bd434a7f643d0936281b2ab4b30c (patch) | |
| tree | 2570518810ff732c4083833466b2247dd1cd1bf1 /drivers/mtd/chips | |
| parent | 4d363b5518dd6298b39653919828eb7d9061488c (diff) | |
mtd: cfi_cmdset_0002: Micron M29EW bugfixes as per TN-13-07
Fix the following issues with Micron's (formerly Numonyx)
M29EW NOR flash chips, as documented on TN-13-07:
- Correcting Erase Suspend Hang Ups (page 20)
- Resolving the Delay After Resume Issue (page 22)
Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/chips')
| -rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 22d0493a026f..5ff5c4a16943 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
| @@ -431,6 +431,68 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, | |||
| 431 | } | 431 | } |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | static int is_m29ew(struct cfi_private *cfi) | ||
| 435 | { | ||
| 436 | if (cfi->mfr == CFI_MFR_INTEL && | ||
| 437 | ((cfi->device_type == CFI_DEVICETYPE_X8 && (cfi->id & 0xff) == 0x7e) || | ||
| 438 | (cfi->device_type == CFI_DEVICETYPE_X16 && cfi->id == 0x227e))) | ||
| 439 | return 1; | ||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | /* | ||
| 444 | * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20: | ||
| 445 | * Some revisions of the M29EW suffer from erase suspend hang ups. In | ||
| 446 | * particular, it can occur when the sequence | ||
| 447 | * Erase Confirm -> Suspend -> Program -> Resume | ||
| 448 | * causes a lockup due to internal timing issues. The consequence is that the | ||
| 449 | * erase cannot be resumed without inserting a dummy command after programming | ||
| 450 | * and prior to resuming. [...] The work-around is to issue a dummy write cycle | ||
| 451 | * that writes an F0 command code before the RESUME command. | ||
| 452 | */ | ||
| 453 | static void cfi_fixup_m29ew_erase_suspend(struct map_info *map, | ||
| 454 | unsigned long adr) | ||
| 455 | { | ||
| 456 | struct cfi_private *cfi = map->fldrv_priv; | ||
| 457 | /* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */ | ||
| 458 | if (is_m29ew(cfi)) | ||
| 459 | map_write(map, CMD(0xF0), adr); | ||
| 460 | } | ||
| 461 | |||
| 462 | /* | ||
| 463 | * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22: | ||
| 464 | * | ||
| 465 | * Some revisions of the M29EW (for example, A1 and A2 step revisions) | ||
| 466 | * are affected by a problem that could cause a hang up when an ERASE SUSPEND | ||
| 467 | * command is issued after an ERASE RESUME operation without waiting for a | ||
| 468 | * minimum delay. The result is that once the ERASE seems to be completed | ||
| 469 | * (no bits are toggling), the contents of the Flash memory block on which | ||
| 470 | * the erase was ongoing could be inconsistent with the expected values | ||
| 471 | * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84 | ||
| 472 | * values), causing a consequent failure of the ERASE operation. | ||
| 473 | * The occurrence of this issue could be high, especially when file system | ||
| 474 | * operations on the Flash are intensive. As a result, it is recommended | ||
| 475 | * that a patch be applied. Intensive file system operations can cause many | ||
| 476 | * calls to the garbage routine to free Flash space (also by erasing physical | ||
| 477 | * Flash blocks) and as a result, many consecutive SUSPEND and RESUME | ||
| 478 | * commands can occur. The problem disappears when a delay is inserted after | ||
| 479 | * the RESUME command by using the udelay() function available in Linux. | ||
| 480 | * The DELAY value must be tuned based on the customer's platform. | ||
| 481 | * The maximum value that fixes the problem in all cases is 500us. | ||
| 482 | * But, in our experience, a delay of 30 µs to 50 µs is sufficient | ||
| 483 | * in most cases. | ||
| 484 | * We have chosen 500µs because this latency is acceptable. | ||
| 485 | */ | ||
| 486 | static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi) | ||
| 487 | { | ||
| 488 | /* | ||
| 489 | * Resolving the Delay After Resume Issue see Micron TN-13-07 | ||
| 490 | * Worst case delay must be 500µs but 30-50µs should be ok as well | ||
| 491 | */ | ||
| 492 | if (is_m29ew(cfi)) | ||
| 493 | cfi_udelay(500); | ||
| 494 | } | ||
| 495 | |||
| 434 | struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | 496 | struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) |
| 435 | { | 497 | { |
| 436 | struct cfi_private *cfi = map->fldrv_priv; | 498 | struct cfi_private *cfi = map->fldrv_priv; |
| @@ -776,7 +838,10 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad | |||
| 776 | 838 | ||
| 777 | switch(chip->oldstate) { | 839 | switch(chip->oldstate) { |
| 778 | case FL_ERASING: | 840 | case FL_ERASING: |
| 841 | cfi_fixup_m29ew_erase_suspend(map, | ||
| 842 | chip->in_progress_block_addr); | ||
| 779 | map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); | 843 | map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); |
| 844 | cfi_fixup_m29ew_delay_after_resume(cfi); | ||
| 780 | chip->oldstate = FL_READY; | 845 | chip->oldstate = FL_READY; |
| 781 | chip->state = FL_ERASING; | 846 | chip->state = FL_ERASING; |
| 782 | break; | 847 | break; |
| @@ -916,6 +981,8 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, | |||
| 916 | /* Disallow XIP again */ | 981 | /* Disallow XIP again */ |
| 917 | local_irq_disable(); | 982 | local_irq_disable(); |
| 918 | 983 | ||
| 984 | /* Correct Erase Suspend Hangups for M29EW */ | ||
| 985 | cfi_fixup_m29ew_erase_suspend(map, adr); | ||
| 919 | /* Resume the write or erase operation */ | 986 | /* Resume the write or erase operation */ |
| 920 | map_write(map, cfi->sector_erase_cmd, adr); | 987 | map_write(map, cfi->sector_erase_cmd, adr); |
| 921 | chip->state = oldstate; | 988 | chip->state = oldstate; |
