diff mbox

mtd: cfi_cmdset_0002: Micron M29EW bugfixes as per TN-13-07

Message ID 1341299387-6303-1-git-send-email-gerlando.falauto@keymile.com
State New, archived
Headers show

Commit Message

Gerlando Falauto July 3, 2012, 7:09 a.m. UTC
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>
Cc: Stefan Bigler <stefan.bigler@keymile.com>
Cc: Holger Brunck <holger.brunck@keymile.com>
Cc: Artem Bityutskiy <dedekind1@gmail.com>
---
 drivers/mtd/chips/cfi_cmdset_0002.c |   69 +++++++++++++++++++++++++++++++++++
 1 files changed, 69 insertions(+), 0 deletions(-)

Comments

Artem Bityutskiy July 16, 2012, 2:29 p.m. UTC | #1
On Tue, 2012-07-03 at 09:09 +0200, Gerlando Falauto wrote:
> 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)

Pushed to l2-mtd.git, thanks!
David Woodhouse Feb. 12, 2013, 2:50 p.m. UTC | #2
On Tue, 2012-07-03 at 09:09 +0200, Gerlando Falauto wrote:
> +/*
> + * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22:
> + *
> + * Some revisions of the M29EW (for example, A1 and A2 step revisions)
> + * are affected by a problem that could cause a hang up when an ERASE SUSPEND
> + * command is issued after an ERASE RESUME operation without waiting for a
> + * minimum delay.  The result is that once the ERASE seems to be completed
> + * (no bits are toggling), the contents of the Flash memory block on which
> + * the erase was ongoing could be inconsistent with the expected values
> + * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84
> + * values), causing a consequent failure of the ERASE operation.
> + * The occurrence of this issue could be high, especially when file system
> + * operations on the Flash are intensive.  As a result, it is recommended
> + * that a patch be applied.  Intensive file system operations can cause many
> + * calls to the garbage routine to free Flash space (also by erasing physical
> + * Flash blocks) and as a result, many consecutive SUSPEND and RESUME
> + * commands can occur.  The problem disappears when a delay is inserted after
> + * the RESUME command by using the udelay() function available in Linux.
> + * The DELAY value must be tuned based on the customer's platform.
> + * The maximum value that fixes the problem in all cases is 500us.
> + * But, in our experience, a delay of 30 us to 50 us is sufficient
> + * in most cases.
> + * We have chosen 500us because this latency is acceptable.
> + */
> +static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi)
> +{
> +       /*
> +        * Resolving the Delay After Resume Issue see Micron TN-13-07
> +        * Worstcase delay must be 500us but 30-50us should be ok as well
> +        */
> +       if (is_m29ew(cfi))
> +               cfi_udelay(500);
> +}

Hm, this would be better off done without a hard delay right there, but
instead just note the timestamp. Then use your existing hook in erase
suspend to check that it's been long enough since the last resume, and
have a *conditional* delay if not.

This assumes you have a timer with enough precision, of course.
diff mbox

Patch

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 23175ed..7f23248 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -417,6 +417,70 @@  static void cfi_fixup_major_minor(struct cfi_private *cfi,
 	}
 }
 
+static int is_m29ew(struct cfi_private *cfi)
+{
+	if (cfi->mfr == CFI_MFR_INTEL)
+		if ((cfi->device_type == CFI_DEVICETYPE_X8  &&
+			(cfi->id & 0xff)	== 0x7e) ||
+		    (cfi->device_type == CFI_DEVICETYPE_X16 &&
+			cfi->id			== 0x227e))
+			return 1;
+	return 0;
+}
+
+/*
+ * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20:
+ * Some revisions of the M29EW suffer from erase suspend hang ups. In
+ * particular, it can occur when the sequence
+ * Erase Confirm -> Suspend -> Program -> Resume
+ * causes a lockup due to internal timing issues. The consequence is that the
+ * erase cannot be resumed without inserting a dummy command after programming
+ * and prior to resuming. [...] The work-around is to issue a dummy write cycle
+ * that writes an F0 command code before the RESUME command.
+ */
+static void cfi_fixup_m29ew_erase_suspend(struct map_info *map,
+					  unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	/* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */
+	if (is_m29ew(cfi))
+		map_write(map, CMD(0xF0), adr);
+}
+
+/*
+ * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22:
+ *
+ * Some revisions of the M29EW (for example, A1 and A2 step revisions)
+ * are affected by a problem that could cause a hang up when an ERASE SUSPEND
+ * command is issued after an ERASE RESUME operation without waiting for a
+ * minimum delay.  The result is that once the ERASE seems to be completed
+ * (no bits are toggling), the contents of the Flash memory block on which
+ * the erase was ongoing could be inconsistent with the expected values
+ * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84
+ * values), causing a consequent failure of the ERASE operation.
+ * The occurrence of this issue could be high, especially when file system
+ * operations on the Flash are intensive.  As a result, it is recommended
+ * that a patch be applied.  Intensive file system operations can cause many
+ * calls to the garbage routine to free Flash space (also by erasing physical
+ * Flash blocks) and as a result, many consecutive SUSPEND and RESUME
+ * commands can occur.  The problem disappears when a delay is inserted after
+ * the RESUME command by using the udelay() function available in Linux.
+ * The DELAY value must be tuned based on the customer's platform.
+ * The maximum value that fixes the problem in all cases is 500us.
+ * But, in our experience, a delay of 30 us to 50 us is sufficient
+ * in most cases.
+ * We have chosen 500us because this latency is acceptable.
+ */
+static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi)
+{
+	/*
+	 * Resolving the Delay After Resume Issue see Micron TN-13-07
+	 * Worstcase delay must be 500us but 30-50us should be ok as well
+	 */
+	if (is_m29ew(cfi))
+		cfi_udelay(500);
+}
+
 struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
@@ -761,7 +825,10 @@  static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
 
 	switch(chip->oldstate) {
 	case FL_ERASING:
+		cfi_fixup_m29ew_erase_suspend(map,
+			chip->in_progress_block_addr);
 		map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
+		cfi_fixup_m29ew_delay_after_resume(cfi);
 		chip->oldstate = FL_READY;
 		chip->state = FL_ERASING;
 		break;
@@ -903,6 +970,8 @@  static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
 			/* Disallow XIP again */
 			local_irq_disable();
 
+			/* Correct Erase Suspend Hangups for M29EW */
+			cfi_fixup_m29ew_erase_suspend(map, adr);
 			/* Resume the write or erase operation */
 			map_write(map, cfi->sector_erase_cmd, adr);
 			chip->state = oldstate;