[flashrom] [commit] r1679 - trunk

repository service svn at flashrom.org
Fri Jun 21 00:55:42 CEST 2013


Author: stefanct
Date: Fri Jun 21 00:55:41 2013
New Revision: 1679
URL: http://flashrom.org/trac/flashrom/changeset/1679

Log:
Fix unlocking function for most Atmel AT2[56]D* chips.

I broke unlocking them correctly in r1635 while refactoring (NB: the
commit log including the overly selfconfident statement about the
"bug in spi_disable_blockprotect_at25df()").

Affected chips have per sector protection bits and the write protection bits
in the status register do indicate if none, some or all sectors are protected.
It is possible to globally (un)lock all sectors at once but in a way that was
not anticipated when refactoring the spi25 unlocking functions into
spi_disable_blockprotect_generic(). To globally unprotect not only the
protection bits (2 and 3) have 0 to be written to them but also bits 4 and 5
which normally would not be touched by spi_disable_blockprotect_generic().
Some of the chips also support a permanent lockdown with fuses which we
do not handle yet.

To fix this without copying the whole method I introduce another mask
parameter to spi_disable_blockprotect_generic() namely unprotect_mask.
See verbose comments inline for details.

Also, prettyprint the status register after trying to disable the block
protection fails.

Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
Tested-by: Chi Zhang <zhangchi866 at gmail.com>
Acked-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>

Modified:
   trunk/chipdrivers.h
   trunk/flashchips.c
   trunk/flashchips.h
   trunk/spi25_statusreg.c

Modified: trunk/chipdrivers.h
==============================================================================
--- trunk/chipdrivers.h	Sun Jun 16 12:30:08 2013	(r1678)
+++ trunk/chipdrivers.h	Fri Jun 21 00:55:41 2013	(r1679)
@@ -77,8 +77,8 @@
 int spi_prettyprint_status_register_at25fs010(struct flashctx *flash);
 int spi_prettyprint_status_register_at25fs040(struct flashctx *flash);
 int spi_prettyprint_status_register_at26df081a(struct flashctx *flash);
-int spi_disable_blockprotect_at25df(struct flashctx *flash);
-int spi_disable_blockprotect_at25df_sec(struct flashctx *flash);
+int spi_disable_blockprotect_at2x_global_unprotect(struct flashctx *flash);
+int spi_disable_blockprotect_at2x_global_unprotect_sec(struct flashctx *flash);
 int spi_disable_blockprotect_at25f(struct flashctx *flash);
 int spi_disable_blockprotect_at25f512a(struct flashctx *flash);
 int spi_disable_blockprotect_at25f512b(struct flashctx *flash);

Modified: trunk/flashchips.c
==============================================================================
--- trunk/flashchips.c	Sun Jun 16 12:30:08 2013	(r1678)
+++ trunk/flashchips.c	Fri Jun 21 00:55:41 2013	(r1679)
@@ -1353,7 +1353,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df,
-		.unlock		= spi_disable_blockprotect_at25df,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */
@@ -1391,7 +1391,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df,
-		.unlock		= spi_disable_blockprotect_at25df,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */
@@ -1429,7 +1429,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df,
-		.unlock		= spi_disable_blockprotect_at25df,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {1600, 2000}, /* Datasheet says range is 1.65-1.95 V */
@@ -1467,7 +1467,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df_sec,
-		.unlock		= spi_disable_blockprotect_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -1505,7 +1505,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df_sec,
-		.unlock		= spi_disable_blockprotect_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -1543,7 +1543,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df,
-		.unlock		= spi_disable_blockprotect_at25df,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -1582,7 +1582,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df_sec,
-		.unlock		= spi_disable_blockprotect_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -1620,7 +1620,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df_sec,
-		.unlock		= spi_disable_blockprotect_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -1659,7 +1659,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df_sec,
-		.unlock		= spi_disable_blockprotect_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -1959,7 +1959,7 @@
 				.block_erase = spi_block_erase_20,
 			}
 		},
-		.printlock	= spi_prettyprint_status_register_plain, /* TODO: improve */
+		.printlock	= spi_prettyprint_status_register_plain,
 		/* Supports also an incompatible page write (of exactly 256 B) and an auto-erasing write. */
 		.write		= spi_chip_write_1,
 		.read		= spi_chip_read, /* Fast read (0x0B) supported */
@@ -1998,7 +1998,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at26df081a,
-		.unlock		= spi_disable_blockprotect_at25df,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -2036,7 +2036,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at25df,
-		.unlock		= spi_disable_blockprotect,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
@@ -2051,7 +2051,7 @@
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
-		.tested		= TEST_UNTESTED,
+		.tested		= TEST_OK_PREW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
@@ -2074,7 +2074,7 @@
 			}
 		},
 		.printlock	= spi_prettyprint_status_register_at26df081a,
-		.unlock		= spi_disable_blockprotect,
+		.unlock		= spi_disable_blockprotect_at2x_global_unprotect,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},

Modified: trunk/flashchips.h
==============================================================================
--- trunk/flashchips.h	Sun Jun 16 12:30:08 2013	(r1678)
+++ trunk/flashchips.h	Fri Jun 21 00:55:41 2013	(r1679)
@@ -130,13 +130,15 @@
 #define ATMEL_ID		0x1F	/* Atmel */
 #define ATMEL_AT25DF021		0x4300
 #define ATMEL_AT25DF041A	0x4401
-#define ATMEL_AT25DF081		0x4502
+#define ATMEL_AT25DF081		0x4502	/* EDI 0x00. AT25DL081 has same ID + EDI 0x0100 */
 #define ATMEL_AT25DF081A	0x4501	/* Yes, 81A has a lower number than 81 */
 #define ATMEL_AT25DF161		0x4602
 #define ATMEL_AT25DF321		0x4700	/* Same as 26DF321 */
 #define ATMEL_AT25DF321A	0x4701
 #define ATMEL_AT25DF641		0x4800
-#define ATMEL_AT25DQ161		0x8600
+#define ATMEL_AT25DL161		0x4603	/* EDI 0x0100 */
+#define ATMEL_AT25DQ161		0x8600	/* EDI 0x0100 */
+#define ATMEL_AT25DQ321		0x8700	/* EDI 0x0100 */
 #define ATMEL_AT25F512		0x65	/* guessed, no device ID in datasheet. Needs AT25F_RDID */
 #define ATMEL_AT25F512A		0x65	/* Needs AT25F_RDID */
 #define ATMEL_AT25F512B		0x6500

Modified: trunk/spi25_statusreg.c
==============================================================================
--- trunk/spi25_statusreg.c	Sun Jun 16 12:30:08 2013	(r1678)
+++ trunk/spi25_statusreg.c	Fri Jun 21 00:55:41 2013	(r1679)
@@ -126,11 +126,24 @@
 /* A generic block protection disable.
  * Tests if a protection is enabled with the block protection mask (bp_mask) and returns success otherwise.
  * Tests if the register bits are locked with the lock_mask (lock_mask).
- * Tests if a hardware protection is active (i.e. low) with the write protection mask (wp_mask) and bails out
- * in that case.
- * Finally tries to disable engaged protections and checks if any locks are still set.
+ * Tests if a hardware protection is active (i.e. low pin/high bit value) with the write protection mask
+ * (wp_mask) and bails out in that case.
+ * If there are register lock bits set we try to disable them by unsetting those bits of the previous register
+ * contents that are set in the lock_mask. We then check if removing the lock bits has worked and continue as if
+ * they never had been engaged:
+ * If the lock bits are out of the way try to disable engaged protections.
+ * To support uncommon global unprotects (e.g. on most AT2[56]xx1(A)) unprotect_mask can be used to force
+ * bits to 0 additionally to those set in bp_mask and lock_mask. Only bits set in unprotect_mask are potentially
+ * preserved when doing the final unprotect.
+ *
+ * To sum up:
+ * bp_mask: set those bits that correspond to the bits in the status register that indicate an active protection
+ *          (which should be unset after this function returns).
+ * lock_mask: set the bits that correspond to the bits that lock changing the bits above.
+ * wp_mask: set the bits that correspond to bits indicating non-software revocable protections.
+ * unprotect_mask: set the bits that should be preserved if possible when unprotecting.
  */
-static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_mask, uint8_t lock_mask, uint8_t wp_mask)
+static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_mask, uint8_t lock_mask, uint8_t wp_mask, uint8_t unprotect_mask)
 {
 	uint8_t status;
 	int result;
@@ -154,10 +167,15 @@
 			msg_cerr("spi_write_status_register failed.\n");
 			return result;
 		}
+		status = spi_read_status_register(flash);
+		if ((status & lock_mask) != 0) {
+			msg_cerr("Unsetting lock bit(s) failed.\n");
+			return 1;
+		}
 		msg_cdbg("done.\n");
 	}
 	/* Global unprotect. Make sure to mask the register lock bit as well. */
-	result = spi_write_status_register(flash, status & ~(bp_mask | lock_mask));
+	result = spi_write_status_register(flash, status & ~(bp_mask | lock_mask) & unprotect_mask);
 	if (result) {
 		msg_cerr("spi_write_status_register failed.\n");
 		return result;
@@ -165,6 +183,7 @@
 	status = spi_read_status_register(flash);
 	if ((status & bp_mask) != 0) {
 		msg_cerr("Block protection could not be disabled!\n");
+		flash->chip->printlock(flash);
 		return 1;
 	}
 	msg_cdbg("disabled.\n");
@@ -174,7 +193,7 @@
 /* A common block protection disable that tries to unset the status register bits masked by 0x3C. */
 int spi_disable_blockprotect(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x3C, 0, 0);
+	return spi_disable_blockprotect_generic(flash, 0x3C, 0, 0, 0xFF);
 }
 
 
@@ -488,49 +507,51 @@
 	return 0;
 }
 
-int spi_disable_blockprotect_at25df(struct flashctx *flash)
+/* Some Atmel DataFlash chips support per sector protection bits and the write protection bits in the status
+ * register do indicate if none, some or all sectors are protected. It is possible to globally (un)lock all
+ * sectors at once by writing 0 not only the protection bits (2 and 3) but also completely unrelated bits (4 and
+ * 5) which normally are not touched.
+ * Affected are all known Atmel chips matched by AT2[56]D[FLQ]..1A? but the AT26DF041. */
+int spi_disable_blockprotect_at2x_global_unprotect(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4);
+	return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4, 0x00);
 }
 
-int spi_disable_blockprotect_at25df_sec(struct flashctx *flash)
+int spi_disable_blockprotect_at2x_global_unprotect_sec(struct flashctx *flash)
 {
 	/* FIXME: We should check the security lockdown. */
 	msg_cinfo("Ignoring security lockdown (if present)\n");
-	return spi_disable_blockprotect_at25df(flash);
+	return spi_disable_blockprotect_at2x_global_unprotect(flash);
 }
 
 int spi_disable_blockprotect_at25f(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 0);
+	return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 0, 0xFF);
 }
 
 int spi_disable_blockprotect_at25f512a(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 0);
+	return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 0, 0xFF);
 }
 
 int spi_disable_blockprotect_at25f512b(struct flashctx *flash)
 {
-	/* spi_disable_blockprotect_at25df is not really the right way to do
-	 * this, but the side effects of said function work here as well.
-	 */
-	return spi_disable_blockprotect_at25df(flash);
+	return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 1 << 4, 0xFF);
 }
 
 int spi_disable_blockprotect_at25f4096(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0);
+	return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0, 0xFF);
 }
 
 int spi_disable_blockprotect_at25fs010(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x6C, 1 << 7, 0);
+	return spi_disable_blockprotect_generic(flash, 0x6C, 1 << 7, 0, 0xFF);
  }
 
 int spi_disable_blockprotect_at25fs040(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x7C, 1 << 7, 0);
+	return spi_disable_blockprotect_generic(flash, 0x7C, 1 << 7, 0, 0xFF);
 }
 
 /* === Intel === */
@@ -538,7 +559,7 @@
 /* TODO: Clear P_FAIL and E_FAIL with Clear SR Fail Flags Command (30h) here? */
 int spi_disable_blockprotect_s33(struct flashctx *flash)
 {
-	return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0);
+	return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0, 0xFF);
 }
 
 int spi_prettyprint_status_register_s33(struct flashctx *flash)




More information about the flashrom mailing list