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

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Fri Oct 19 23:39:03 CEST 2007


On 19.10.2007 23:01, Uwe Hermann wrote:
> On Thu, Oct 18, 2007 at 10:32:01PM +0200, Carl-Daniel Hailfinger wrote:
>   
> [...]
>
> Looks good IMO. With the above fixes:
>
> Acked-by: Uwe Hermann <uwe at hermann-uwe.de>
>   

Thanks for the review! I fixed most of the points you raised, but
especially constification was not possible everywhere without changing
all erase and write prototypes in all files. Something to be left for
future commits.

Can you re-review?

Carl-Daniel

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/flash.h
===================================================================
--- util/flashrom/flash.h	(Revision 2876)
+++ util/flashrom/flash.h	(Arbeitskopie)
@@ -72,7 +72,7 @@
 
 #define EON_ID			0x1C
 /* EN25 chips are SPI, first byte of device id is memory type,
-   second byte of device id is log(bitsize)-9 */
+ * second byte of device id is log(bitsize)-9. */
 #define EN_25B05		0x2010	/* 2^19 kbit or 2^16 kByte */
 #define EN_25B10		0x2011
 #define EN_25B20		0x2012
@@ -82,9 +82,8 @@
 #define EN_25B32		0x2016
 
 #define MX_ID			0xC2	/* Macronix (MX) */
-#define MX_29F002		0xB0
-/* MX25L chips are SPI, first byte of device id is memory type,
-   second byte of device id is log(bitsize)-9 */
+/* MX25 chips are SPI, first byte of device id is memory type,
+ * second byte of device id is log(bitsize)-9. */
 #define MX_25L512		0x2010	/* 2^19 kbit or 2^16 kByte */
 #define MX_25L1005		0x2011
 #define MX_25L2005		0x2012
@@ -95,11 +94,22 @@
 #define MX_25L6405		0x2017	/* MX25L3205{,D} */
 #define MX_25L1635D		0x2415
 #define MX_25L3235D		0x2416
+#define MX_29F002		0xB0
 
 #define SHARP_ID		0xB0	/* Sharp */
 #define SHARP_LHF00L04		0xCF
 
 #define SST_ID			0xBF	/* SST */
+/* SST25 chips are SPI, first byte of device id is memory type, second
+ * byte of device id is related to log(bitsize) at least for some chips. */
+#define SST_25WF512		0x2501
+#define SST_25WF010		0x2502
+#define SST_25WF020		0x2503
+#define SST_25WF040		0x2504
+#define SST_25VF016B		0x2541
+#define SST_25VF032B		0x254A
+#define SST_25VF040B		0x258D
+#define SST_25VF080B		0x258E
 #define SST_29EE020A		0x10
 #define SST_28SF040		0x04
 #define SST_39SF010		0xB5
@@ -210,7 +220,7 @@
 /* spi.c */
 int probe_spi(struct flashchip *flash);
 int it87xx_probe_spi_flash(const char *name);
-int generic_spi_command(unsigned char writecnt, unsigned char readcnt, const unsigned char *writearr, unsigned char *readarr);
+int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
 void generic_spi_write_enable();
 void generic_spi_write_disable();
 int generic_spi_chip_erase(struct flashchip *flash);
Index: util/flashrom/flashchips.c
===================================================================
--- util/flashrom/flashchips.c	(Revision 2876)
+++ util/flashrom/flashchips.c	(Arbeitskopie)
@@ -36,7 +36,7 @@
 	 probe_jedec,	erase_chip_jedec, write_jedec},
 	{"At29C020",	ATMEL_ID,	AT_29C020,	256, 256,
 	 probe_jedec,	erase_chip_jedec, write_jedec},
-	{"Mx29f002",	MX_ID,		MX_29F002,	256, 64 * 1024,
+	{"MX29F002",	MX_ID,		MX_29F002,	256, 64 * 1024,
 	 probe_29f002,	erase_29f002, 	write_29f002},
 	{"MX25L4005",	MX_ID,		MX_25L4005,	512, 4 * 1024,
 	 probe_spi,	generic_spi_chip_erase,	generic_spi_chip_write},
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
@@ -144,7 +158,7 @@
    whereas the IT8716F splits commands internally into address and non-address
    commands with the address in inverse wire order. That's why the register
    ordering in case 4 and 5 may seem strange. */
-static int it8716f_spi_command(uint16_t port, unsigned char writecnt, unsigned char readcnt, const unsigned char *writearr, unsigned char *readarr)
+static int it8716f_spi_command(uint16_t port, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
 {
 	uint8_t busy, writeenc;
 	int i;
@@ -188,7 +202,7 @@
 		return 1;
 	}
 	/* Start IO, 33MHz, readcnt input bytes, writecnt output bytes. Note:
-	 * We can't use writecnt directly, but have to use a strange encoding 
+	 * We can't use writecnt directly, but have to use a strange encoding.
 	 */ 
 	outb((0x5 << 4) | ((readcnt & 0x3) << 2) | (writeenc), port);
 	do {
@@ -202,7 +216,7 @@
 	return 0;
 }
 
-int generic_spi_command(unsigned char writecnt, unsigned char readcnt, const unsigned char *writearr, unsigned char *readarr)
+int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
 {
 	if (it8716f_flashport)
 		return it8716f_spi_command(it8716f_flashport, writecnt, readcnt, writearr, readarr);
@@ -269,13 +283,58 @@
 
 	generic_spi_write_enable();
 	/* Send CE (Chip Erase) */
-	generic_spi_command(1, 0, cmd, NULL);
-	/* Wait until the Write-In-Progress bit is cleared */
+	generic_spi_command(JEDEC_CE_2_OUTSIZE, JEDEC_CE_2_INSIZE, cmd, NULL);
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 1-85 s, so wait in 1 s steps.
+	 */
 	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(const 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.
+	 * This usually takes 100-4000 ms, so wait in 100 ms steps.
+	 */
+	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(const 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.
+	 * This usually takes 15-800 ms, so wait in 10 ms steps.
+	 */
+	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;
 
@@ -286,7 +345,9 @@
 		bios[256 * block + i] = buf[256 * block + i];
 	}
 	outb(0, it8716f_flashport);
-	/* Wait until the Write-In-Progress bit is cleared */
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 1-10 ms, so wait in 1 ms steps.
+	 */
 	while (generic_spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
 		usleep(1000);
 }






More information about the coreboot mailing list