[LinuxBIOS] [PATCH] flashrom: SPI serial flash: The sector/block erase pitfalls

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Thu Oct 18 22:32:01 CEST 2007


This is more a rant than a tutorial how to solve the remaining problems.
Almost all SPI flash falls into at least one of three categories:
* Does not respect the JEDEC standards
* Totally different chips with exactly the same ID and no means to tell
them apart unless you physically look at their part number
* Completely weird configuration, unique per chip

SST SST25* chips claim not to support standard JEDEC RDID. Maybe someone
just forgot to write something about RDID support in the data sheet, but
even then we don't know what values they would return.
Macronix MX25* chips sometimes have two variants of the same chip
(exactly same electronic ID) with different sector sizes. The slow
variant with useless big sectors and less reflash cycles calls itself
"eliteflash".
EON EN25* chips have variable sized blocks between 4-32k, call these
blocks sectors and have no sector erase support. To make matters worse,
different chips with different block configurations return exactly the
same values from RDID. At least they can somewhat be told apart when
using REMS.

This patch introduces block and sector erase routines, but does not use
them yet.

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

---

Index: util/flashrom/spi.c
===================================================================
--- util/flashrom/spi.c	(Revision 2876)
+++ util/flashrom/spi.c	(Arbeitskopie)
@@ -45,17 +45,31 @@
 #define JEDEC_WRDI_OUTSIZE	0x01
 #define JEDEC_WRDI_INSIZE	0x00
 
-/* Both Chip Erase commands below should work */
-/* Chip Erase 0x60 */
+/* Chip Erase 0x60 is supported by Macronix/SST chips */
 #define JEDEC_CE_1	{0x60};
 #define JEDEC_CE_1_OUTSIZE	0x01
 #define JEDEC_CE_1_INSIZE	0x00
 
-/* Chip Erase 0xc7 */
+/* Chip Erase 0xc7 is supported by EON/Macronix chips */
 #define JEDEC_CE_2	{0xc7};
 #define JEDEC_CE_2_OUTSIZE	0x01
 #define JEDEC_CE_2_INSIZE	0x00
 
+/* Block Erase 0x52 is supported by SST chips */
+#define JEDEC_BE_1	{0x52};
+#define JEDEC_BE_1_OUTSIZE	0x04
+#define JEDEC_BE_1_INSIZE	0x00
+
+/* Block Erase 0xd8 is supported by EON/Macronix chips */
+#define JEDEC_BE_2	{0xd8};
+#define JEDEC_BE_2_OUTSIZE	0x04
+#define JEDEC_BE_2_INSIZE	0x00
+
+/* Sector Erase 0x20 is supported by Macronix/SST chips*/
+#define JEDEC_SE	{0x20};
+#define JEDEC_SE_OUTSIZE	0x04
+#define JEDEC_SE_INSIZE	0x00
+
 /* Read Status Register */
 #define JEDEC_RDSR	{0x05};
 #define JEDEC_RDSR_OUTSIZE	0x01
@@ -269,13 +283,52 @@
 
 	generic_spi_write_enable();
 	/* Send CE (Chip Erase) */
-	generic_spi_command(1, 0, cmd, NULL);
+	generic_spi_command(JEDEC_CE_2_OUTSIZE, JEDEC_CE_2_INSIZE, cmd, NULL);
 	/* Wait until the Write-In-Progress bit is cleared */
 	while (generic_spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
 		sleep(1);
 	return 0;
 }
 
+/* Block size is usually
+ * 64k for Macronix
+ * 32k for SST
+ * 4-32k non-uniform for EON
+ */
+int generic_spi_block_erase(struct flashchip *flash, unsigned long addr)
+{
+	unsigned char cmd[JEDEC_BE_2_OUTSIZE] = JEDEC_BE_2;
+
+	cmd[1] = (addr & 0x00ff0000) >> 16;
+	cmd[2] = (addr & 0x0000ff00) >> 8;
+	cmd[3] = (addr & 0x000000ff);
+	generic_spi_write_enable();
+	/* Send BE (Block Erase) */
+	generic_spi_command(JEDEC_BE_2_OUTSIZE, JEDEC_BE_2_INSIZE, cmd, NULL);
+	/* Wait until the Write-In-Progress bit is cleared */
+	while (generic_spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		usleep(100 * 1000);
+	return 0;
+}
+
+/* Sector size is usually 4k, though Macronix eliteflash has 64k */
+int generic_spi_sector_erase(struct flashchip *flash, unsigned long addr)
+{
+	unsigned char cmd[JEDEC_SE_OUTSIZE] = JEDEC_SE;
+	cmd[1] = (addr & 0x00ff0000) >> 16;
+	cmd[2] = (addr & 0x0000ff00) >> 8;
+	cmd[3] = (addr & 0x000000ff);
+
+	generic_spi_write_enable();
+	/* Send SE (Sector Erase) */
+	generic_spi_command(JEDEC_SE_OUTSIZE, JEDEC_SE_INSIZE, cmd, NULL);
+	/* Wait until the Write-In-Progress bit is cleared */
+	while (generic_spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		usleep(10 * 1000);
+	return 0;
+}
+
+/* Page size is usually 256 bytes */
 void it8716f_spi_page_program(int block, uint8_t *buf, uint8_t *bios) {
 	int i;
 






More information about the coreboot mailing list