[flashrom] [PATCH] Write protection handling for Atmel AT25*

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Tue Jul 27 00:47:47 CEST 2010


Next try, with one status register printing corner case fixed and with
a better changelog.

Add detailed status register printing and unlocking for all ATMEL AT25*
chips.

Add support for Atmel AT25DF081A and AT25DQ161.

Some chips require EWSR before WRSR, others require WREN before WRSR,
and some support both variants. Add feature_bits to select the correct
SPI command, and default to EWSR.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>

 Index: flashrom-writeprotect_atmel_at25/flash.h
===================================================================
--- flashrom-writeprotect_atmel_at25/flash.h	(Revision 1109)
+++ flashrom-writeprotect_atmel_at25/flash.h	(Arbeitskopie)
@@ -167,8 +167,9 @@
 
 /*
  * How many different erase functions do we have per chip?
+ * Atmel AT25FS010 has 6 different functions.
  */
-#define NUM_ERASEFUNCTIONS 5
+#define NUM_ERASEFUNCTIONS 6
 
 #define FEATURE_REGISTERMAP	(1 << 0)
 #define FEATURE_BYTEWRITES	(1 << 1)
@@ -180,6 +181,9 @@
 #define FEATURE_ADDR_2AA	(1 << 2)
 #define FEATURE_ADDR_AAA	(2 << 2)
 #define FEATURE_ADDR_SHIFTED	(1 << 5)
+#define FEATURE_WRSR_EWSR	(1 << 6)
+#define FEATURE_WRSR_WREN	(1 << 7)
+#define FEATURE_WRSR_EITHER	(FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
 
 struct flashchip {
 	const char *vendor;
Index: flashrom-writeprotect_atmel_at25/spi25.c
===================================================================
--- flashrom-writeprotect_atmel_at25/spi25.c	(Revision 1109)
+++ flashrom-writeprotect_atmel_at25/spi25.c	(Arbeitskopie)
@@ -311,8 +311,17 @@
 }
 
 /* Prettyprint the status register. Common definitions. */
-void spi_prettyprint_status_register_common(uint8_t status)
+static void spi_prettyprint_status_register_welwip(uint8_t status)
 {
+	msg_cdbg("Chip status register: Write Enable Latch (WEL) is "
+		     "%sset\n", (status & (1 << 1)) ? "" : "not ");
+	msg_cdbg("Chip status register: Write In Progress (WIP/BUSY) is "
+		     "%sset\n", (status & (1 << 0)) ? "" : "not ");
+}
+
+/* Prettyprint the status register. Common definitions. */
+static void spi_prettyprint_status_register_common(uint8_t status)
+{
 	msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
 		     "%sset\n", (status & (1 << 5)) ? "" : "not ");
 	msg_cdbg("Chip status register: Bit 4 / Block Protect 2 (BP2) is "
@@ -321,10 +330,7 @@
 		     "%sset\n", (status & (1 << 3)) ? "" : "not ");
 	msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
 		     "%sset\n", (status & (1 << 2)) ? "" : "not ");
-	msg_cdbg("Chip status register: Write Enable Latch (WEL) is "
-		     "%sset\n", (status & (1 << 1)) ? "" : "not ");
-	msg_cdbg("Chip status register: Write In Progress (WIP/BUSY) is "
-		     "%sset\n", (status & (1 << 0)) ? "" : "not ");
+	spi_prettyprint_status_register_welwip(status);
 }
 
 /* Prettyprint the status register. Works for
@@ -337,6 +343,121 @@
 	spi_prettyprint_status_register_common(status);
 }
 
+/* Prettyprint the status register. Common definitions. */
+static void spi_prettyprint_status_register_at25_srplepewpp(uint8_t status)
+{
+	msg_cdbg("Chip status register: Sector Protection Register Lock (SRPL) "
+		 "is %sset\n", (status & (1 << 7)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 6 "
+		 "is %sset\n", (status & (1 << 6)) ? "" : "not ");
+	msg_cdbg("Chip status register: Erase/Program Error (EPE) "
+		 "is %sset\n", (status & (1 << 5)) ? "" : "not ");
+	msg_cdbg("Chip status register: WP# pin (WPP) "
+		 "is %sactive\n", (status & (1 << 4)) ? "not " : "");
+}
+
+int spi_prettyprint_status_register_at25df(struct flashchip *flash)
+{
+	uint8_t status;
+
+	status = spi_read_status_register();
+	msg_cdbg("Chip status register is %02x\n", status);
+
+	spi_prettyprint_status_register_at25_srplepewpp(status);
+	msg_cdbg("Chip status register: Software Protection Status (SWP): ");
+	switch (status & (3 << 2)) {
+	case 0x0 << 2:
+		msg_cdbg("no sectors are protected\n");
+		break;
+	case 0x1 << 2:
+		msg_cdbg("some sectors are protected\n");
+		/* FIXME: Read individual Sector Protection Registers. */
+		break;
+	case 0x3 << 2:
+		msg_cdbg("all sectors are protected\n");
+		break;
+	default:
+		msg_cdbg("reserved for future use\n");
+		break;
+	}
+	spi_prettyprint_status_register_welwip(status);
+	return 0;
+}
+
+int spi_prettyprint_status_register_at25df_sec(struct flashchip *flash)
+{
+	/* FIXME: We should check the security lockdown. */
+	msg_cdbg("Ignoring security lockdown (if present)\n");
+	msg_cdbg("Ignoring status register byte 2\n");
+	return spi_prettyprint_status_register_at25df(flash);
+}
+
+int spi_prettyprint_status_register_at25f(struct flashchip *flash)
+{
+	uint8_t status;
+
+	status = spi_read_status_register();
+	msg_cdbg("Chip status register is %02x\n", status);
+
+	spi_prettyprint_status_register_at25_srplepewpp(status);
+	msg_cdbg("Chip status register: Bit 3 "
+		 "is %sset\n", (status & (1 << 3)) ? "" : "not ");
+	msg_cdbg("Chip status register: Block Protect 0 (BP0) is "
+		 "%sset, %s sectors are protected\n",
+		 (status & (1 << 2)) ? "" : "not ",
+		 (status & (1 << 2)) ? "all" : "no");
+	spi_prettyprint_status_register_welwip(status);
+	return 0;
+}
+
+int spi_prettyprint_status_register_at25fs010(struct flashchip *flash)
+{
+	uint8_t status;
+
+	status = spi_read_status_register();
+	msg_cdbg("Chip status register is %02x\n", status);
+
+	msg_cdbg("Chip status register: Status Register Write Protect (WPEN) "
+		 "is %sset\n", (status & (1 << 7)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 6 / Block Protect 4 (BP4) is "
+		 "%sset\n", (status & (1 << 6)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
+		 "%sset\n", (status & (1 << 5)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 4 is "
+		 "%sset\n", (status & (1 << 4)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 3 / Block Protect 1 (BP1) is "
+		 "%sset\n", (status & (1 << 3)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
+		 "%sset\n", (status & (1 << 2)) ? "" : "not ");
+	/* FIXME: Pretty-print detailed sector protection status. */
+	spi_prettyprint_status_register_welwip(status);
+	return 0;
+}
+
+int spi_prettyprint_status_register_at25fs040(struct flashchip *flash)
+{
+	uint8_t status;
+
+	status = spi_read_status_register();
+	msg_cdbg("Chip status register is %02x\n", status);
+
+	msg_cdbg("Chip status register: Status Register Write Protect (WPEN) "
+		 "is %sset\n", (status & (1 << 7)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 6 / Block Protect 4 (BP4) is "
+		 "%sset\n", (status & (1 << 6)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
+		 "%sset\n", (status & (1 << 5)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 4 / Block Protect 2 (BP2) is "
+		 "%sset\n", (status & (1 << 4)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 3 / Block Protect 1 (BP1) is "
+		 "%sset\n", (status & (1 << 3)) ? "" : "not ");
+	msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
+		 "%sset\n", (status & (1 << 2)) ? "" : "not ");
+	/* FIXME: Pretty-print detailed sector protection status. */
+	spi_prettyprint_status_register_welwip(status);
+	return 0;
+}
+
 /* Prettyprint the status register. Works for
  * ST M25P series
  * MX MX25L series
@@ -731,12 +852,12 @@
  * This is according the SST25VF016 datasheet, who knows it is more
  * generic that this...
  */
-int spi_write_status_register(int status)
+static int spi_write_status_register_ewsr(struct flashchip *flash, int status)
 {
 	int result;
 	struct spi_command cmds[] = {
 	{
-	/* FIXME: WRSR requires either EWSR or WREN depending on chip type. */
+	/* WRSR requires either EWSR or WREN depending on chip type. */
 		.writecnt	= JEDEC_EWSR_OUTSIZE,
 		.writearr	= (const unsigned char[]){ JEDEC_EWSR },
 		.readcnt	= 0,
@@ -758,9 +879,59 @@
 		msg_cerr("%s failed during command execution\n",
 			__func__);
 	}
+	/* WRSR performs a self-timed erase before the changes take effect. */
+	programmer_delay(100 * 1000);
 	return result;
 }
 
+static int spi_write_status_register_wren(struct flashchip *flash, int status)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+	/* WRSR requires either EWSR or WREN depending on chip type. */
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_WRSR_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		msg_cerr("%s failed during command execution\n",
+			__func__);
+	}
+	/* WRSR performs a self-timed erase before the changes take effect. */
+	programmer_delay(100 * 1000);
+	return result;
+}
+
+static int spi_write_status_register(struct flashchip *flash, int status)
+{
+	int ret = 1;
+
+	if (!(flash->feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
+		msg_cdbg("Missing status register write definition, assuming "
+			 "EWSR is needed\n");
+		flash->feature_bits |= FEATURE_WRSR_EWSR;
+	}
+	if (flash->feature_bits & FEATURE_WRSR_WREN)
+		ret = spi_write_status_register_wren(flash, status);
+	if (ret && (flash->feature_bits & FEATURE_WRSR_EWSR))
+		ret = spi_write_status_register_ewsr(flash, status);
+	return ret;
+}
+
 int spi_byte_program(int addr, uint8_t databyte)
 {
 	int result;
@@ -843,29 +1014,156 @@
 	return result;
 }
 
+/* A generic brute-force block protection disable works like this:
+ * Write 0x00 to the status register. Check if any locks are still set (that
+ * part is chip specific). Repeat once.
+ */
 int spi_disable_blockprotect(struct flashchip *flash)
 {
 	uint8_t status;
 	int result;
 
 	status = spi_read_status_register();
-	/* If there is block protection in effect, unprotect it first. */
+	/* If block protection is disabled, stop here. */
+	if ((status & 0x3c) == 0)
+		return 0;
+
+	msg_cdbg("Some block protection in effect, disabling\n");
+	result = spi_write_status_register(flash, status & ~0x3c);
+	if (result) {
+		msg_cerr("spi_write_status_register failed\n");
+		return result;
+	}
+	status = spi_read_status_register();
 	if ((status & 0x3c) != 0) {
-		msg_cdbg("Some block protection in effect, disabling\n");
-		result = spi_write_status_register(status & ~0x3c);
+		msg_cerr("Block protection could not be disabled!\n");
+		return 1;
+	}
+	return 0;
+}
+
+int spi_disable_blockprotect_at25df(struct flashchip *flash)
+{
+	uint8_t status;
+	int result;
+
+	status = spi_read_status_register();
+	/* If block protection is disabled, stop here. */
+	if ((status & (3 << 2)) == 0)
+		return 0;
+
+	msg_cdbg("Some block protection in effect, disabling\n");
+	if (status & (1 << 7)) {
+		msg_cdbg("Need to disable Sector Protection Register Lock\n");
+		if ((status & (1 << 4)) == 0) {
+			msg_cerr("WP# pin is active, disabling "
+				 "write protection is impossible.\n");
+			return 1;
+		}
+		/* All bits except bit 7 (SPRL) are readonly. */
+		result = spi_write_status_register(flash, status & ~(1 << 7));
 		if (result) {
 			msg_cerr("spi_write_status_register failed\n");
 			return result;
 		}
-		status = spi_read_status_register();
-		if ((status & 0x3c) != 0) {
-			msg_cerr("Block protection could not be disabled!\n");
-			return 1;
+		
+	}
+	/* Global unprotect. Make sure to mask SPRL as well. */
+	result = spi_write_status_register(flash, status & ~0xbc);
+	if (result) {
+		msg_cerr("spi_write_status_register failed\n");
+		return result;
+	}
+	status = spi_read_status_register();
+	if ((status & (3 << 2)) != 0) {
+		msg_cerr("Block protection could not be disabled!\n");
+		return 1;
+	}
+	return 0;
+}
+
+int spi_disable_blockprotect_at25df_sec(struct flashchip *flash)
+{
+	/* FIXME: We should check the security lockdown. */
+	msg_cinfo("Ignoring security lockdown (if present)\n");
+	return spi_disable_blockprotect_at25df(flash);
+}
+
+int spi_disable_blockprotect_at25f(struct flashchip *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);
+}
+
+int spi_disable_blockprotect_at25fs010(struct flashchip *flash)
+{
+	uint8_t status;
+	int result;
+
+	status = spi_read_status_register();
+	/* If block protection is disabled, stop here. */
+	if ((status & 0x6c) == 0)
+		return 0;
+
+	msg_cdbg("Some block protection in effect, disabling\n");
+	if (status & (1 << 7)) {
+		msg_cdbg("Need to disable Status Register Write Protect\n");
+		/* Clear bit 7 (WPEN). */
+		result = spi_write_status_register(flash, status & ~(1 << 7));
+		if (result) {
+			msg_cerr("spi_write_status_register failed\n");
+			return result;
 		}
 	}
+	/* Global unprotect. Make sure to mask WPEN as well. */
+	result = spi_write_status_register(flash, status & ~0xec);
+	if (result) {
+		msg_cerr("spi_write_status_register failed\n");
+		return result;
+	}
+	status = spi_read_status_register();
+	if ((status & 0x6c) != 0) {
+		msg_cerr("Block protection could not be disabled!\n");
+		return 1;
+	}
 	return 0;
 }
+int spi_disable_blockprotect_at25fs040(struct flashchip *flash)
+{
+	uint8_t status;
+	int result;
 
+	status = spi_read_status_register();
+	/* If block protection is disabled, stop here. */
+	if ((status & 0x7c) == 0)
+		return 0;
+
+	msg_cdbg("Some block protection in effect, disabling\n");
+	if (status & (1 << 7)) {
+		msg_cdbg("Need to disable Status Register Write Protect\n");
+		/* Clear bit 7 (WPEN). */
+		result = spi_write_status_register(flash, status & ~(1 << 7));
+		if (result) {
+			msg_cerr("spi_write_status_register failed\n");
+			return result;
+		}
+	}
+	/* Global unprotect. Make sure to mask WPEN as well. */
+	result = spi_write_status_register(flash, status & ~0xfc);
+	if (result) {
+		msg_cerr("spi_write_status_register failed\n");
+		return result;
+	}
+	status = spi_read_status_register();
+	if ((status & 0x7c) != 0) {
+		msg_cerr("Block protection could not be disabled!\n");
+		return 1;
+	}
+	return 0;
+}
+
 int spi_nbyte_read(int address, uint8_t *bytes, int len)
 {
 	const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
Index: flashrom-writeprotect_atmel_at25/flashchips.c
===================================================================
--- flashrom-writeprotect_atmel_at25/flashchips.c	(Revision 1109)
+++ flashrom-writeprotect_atmel_at25/flashchips.c	(Arbeitskopie)
@@ -313,6 +313,7 @@
 		.model_id	= AT_25DF021,
 		.total_size	= 256,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -335,7 +336,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25df,
+		.unlock		= spi_disable_blockprotect_at25df,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
@@ -348,6 +350,7 @@
 		.model_id	= AT_25DF041A,
 		.total_size	= 512,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -370,7 +373,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25df,
+		.unlock		= spi_disable_blockprotect_at25df,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
@@ -383,6 +387,7 @@
 		.model_id	= AT_25DF081,
 		.total_size	= 1024,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -405,19 +410,58 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25df,
+		.unlock		= spi_disable_blockprotect_at25df,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
 
 	{
 		.vendor		= "Atmel",
+		.name		= "AT25DF081A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF081A,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 256} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {32 * 1024, 32} },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 16} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.printlock	= spi_prettyprint_status_register_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at25df_sec,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
 		.name		= "AT25DF161",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= ATMEL_ID,
 		.model_id	= AT_25DF161,
 		.total_size	= 2048,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -440,7 +484,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at25df_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
@@ -453,6 +498,7 @@
 		.model_id	= AT_25DF321,
 		.total_size	= 4096,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PRW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -475,7 +521,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25df,
+		.unlock		= spi_disable_blockprotect_at25df,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
@@ -488,6 +535,7 @@
 		.model_id	= AT_25DF321A,
 		.total_size	= 4096,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -510,7 +558,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at25df_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
@@ -523,6 +572,7 @@
 		.model_id	= AT_25DF641,
 		.total_size	= 8192,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -545,19 +595,58 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at25df_sec,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
 
 	{
 		.vendor		= "Atmel",
+		.name		= "AT25DQ161",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DQ161,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 512} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {32 * 1024, 64} },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 32} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {2 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {2 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.printlock	= spi_prettyprint_status_register_at25df_sec,
+		.unlock		= spi_disable_blockprotect_at25df_sec,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
 		.name		= "AT25F512B",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= ATMEL_ID,
 		.model_id	= AT_25F512B,
 		.total_size	= 64,
 		.page_size	= 256,
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -580,7 +669,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25f,
+		.unlock		= spi_disable_blockprotect_at25f,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
@@ -602,6 +692,9 @@
 				.eraseblocks = { {4 * 1024, 32} },
 				.block_erase = spi_block_erase_20,
 			}, {
+				.eraseblocks = { {4 * 1024, 32} },
+				.block_erase = spi_block_erase_d7,
+			}, {
 				.eraseblocks = { {32 * 1024, 4} },
 				.block_erase = spi_block_erase_52,
 			}, {
@@ -615,7 +708,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25fs010,
+		.unlock		= spi_disable_blockprotect_at25fs010,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
@@ -650,7 +744,8 @@
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.unlock		= spi_disable_blockprotect,
+		.printlock	= spi_prettyprint_status_register_at25fs040,
+		.unlock		= spi_disable_blockprotect_at25fs040,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 	},
Index: flashrom-writeprotect_atmel_at25/flashchips.h
===================================================================
--- flashrom-writeprotect_atmel_at25/flashchips.h	(Revision 1109)
+++ flashrom-writeprotect_atmel_at25/flashchips.h	(Arbeitskopie)
@@ -110,12 +110,19 @@
 #define AT_25DF021		0x4300
 #define AT_25DF041A		0x4401
 #define AT_25DF081		0x4502
+#define AT_25DF081A		0x4501	/* Yes, 81A has a lower number than 81 */
 #define AT_25DF161		0x4602
 #define AT_25DF321		0x4700	/* Same as 26DF321 */
 #define AT_25DF321A		0x4701
 #define AT_25DF641		0x4800
-#define AT_25F512A		0x65 /* Needs special RDID. AT25F512A_RDID 15 1d */
+#define AT_25DQ161		0x8600
+#define AT25F512		/* No device ID found in datasheet. Vendor ID
+				 * can be read with AT25F512A_RDID */
+#define AT_25F512A		0x65 /* Needs AT25F512A_RDID */
 #define AT_25F512B		0x6500
+#define AT25F1024		/* No device ID found in datasheet. Vendor ID
+				 * can be read with AT25F512A_RDID */
+#define AT_25F1024A		0x60 /* Needs AT25F512A_RDID */
 #define AT_25FS010		0x6601
 #define AT_25FS040		0x6604
 #define AT_26DF041		0x4400
Index: flashrom-writeprotect_atmel_at25/spi.c
===================================================================
--- flashrom-writeprotect_atmel_at25/spi.c	(Revision 1109)
+++ flashrom-writeprotect_atmel_at25/spi.c	(Arbeitskopie)
@@ -29,8 +29,6 @@
 
 enum spi_controller spi_controller = SPI_CONTROLLER_NONE;
 
-void spi_prettyprint_status_register(struct flashchip *flash);
-
 const struct spi_programmer spi_programmer[] = {
 	{ /* SPI_CONTROLLER_NONE */
 		.command = NULL,
Index: flashrom-writeprotect_atmel_at25/spi.h
===================================================================
--- flashrom-writeprotect_atmel_at25/spi.h	(Revision 1109)
+++ flashrom-writeprotect_atmel_at25/spi.h	(Arbeitskopie)
@@ -31,7 +31,7 @@
 #define JEDEC_RDID_INSIZE	0x03
 
 /* AT25F512A has bit 3 as don't care bit in commands */
-#define AT25F512A_RDID		0x15
+#define AT25F512A_RDID		0x15	/* 0x15 or 0x1d */
 #define AT25F512A_RDID_OUTSIZE	0x01
 #define AT25F512A_RDID_INSIZE	0x02
 
@@ -123,5 +123,6 @@
 #define SPI_INVALID_OPCODE	-2
 #define SPI_INVALID_ADDRESS	-3
 #define SPI_INVALID_LENGTH	-4
+#define SPI_FLASHROM_BUG	-5
 
 #endif		/* !__SPI_H__ */
Index: flashrom-writeprotect_atmel_at25/chipdrivers.h
===================================================================
--- flashrom-writeprotect_atmel_at25/chipdrivers.h	(Revision 1109)
+++ flashrom-writeprotect_atmel_at25/chipdrivers.h	(Arbeitskopie)
@@ -47,7 +47,17 @@
 int spi_chip_write_256_new(struct flashchip *flash, uint8_t *buf, int start, int len);
 int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
 uint8_t spi_read_status_register(void);
+int spi_prettyprint_status_register_at25df(struct flashchip *flash);
+int spi_prettyprint_status_register_at25df_sec(struct flashchip *flash);
+int spi_prettyprint_status_register_at25f(struct flashchip *flash);
+int spi_prettyprint_status_register_at25fs010(struct flashchip *flash);
+int spi_prettyprint_status_register_at25fs040(struct flashchip *flash);
 int spi_disable_blockprotect(struct flashchip *flash);
+int spi_disable_blockprotect_at25df(struct flashchip *flash);
+int spi_disable_blockprotect_at25df_sec(struct flashchip *flash);
+int spi_disable_blockprotect_at25f(struct flashchip *flash);
+int spi_disable_blockprotect_at25fs010(struct flashchip *flash);
+int spi_disable_blockprotect_at25fs040(struct flashchip *flash);
 int spi_byte_program(int addr, uint8_t databyte);
 int spi_nbyte_program(int addr, uint8_t *bytes, int len);
 int spi_nbyte_read(int addr, uint8_t *bytes, int len);


-- 
http://www.hailfinger.org/





More information about the flashrom mailing list