[coreboot] SST25VF016B (2MB) flash on m57sli (IT8716F).

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Fri Jan 18 23:31:10 CET 2008


On 18.01.2008 21:48, Ronald Hoogenboom wrote:
> I think this is a matter of taste... But if the style is like this, I
> will comply. So I changed my patch again to do exactly the same, but
> with a few JEDEC_... defines.
>
>   
> Signed-off-by: Ronald Hoogenboom <hoogenboom30 at zonnet.nl>
>   

Thanks for reworking the code! I have factored out some common status
registers to duplicate less code and hope the code still works. Could
you please review it and tell me what you think?

Ron (Minnich), can you test with your GA-2761GXDK?

Regards,
Carl-Daniel
-------------------
Support SPI flash chips bigger than 512 kByte sitting behind IT8716F
Super I/O performing LPC-to-SPI flash translation.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>
Signed-off-by: Ronald Hoogenboom <hoogenboom30 at zonnet.nl>


Index: flashrom-big/flash.h
===================================================================
--- flashrom-big/flash.h	(Revision 3051)
+++ flashrom-big/flash.h	(Arbeitskopie)
@@ -234,7 +234,16 @@
 
 #define TI_ID			0x97	/* Texas Instruments */
 
+/*
+ * W25X chips are SPI, first byte of device ID is memory type, second
+ * byte of device ID is related to log(bitsize).
+ */
 #define WINBOND_ID		0xDA	/* Winbond */
+#define WINBOND_NEX_ID		0xEF	/* Winbond (ex Nexcom) serial flash devices */
+#define W_25X10			0x3011
+#define W_25X20			0x3012
+#define W_25X40			0x3013
+#define W_25X80			0x3014
 #define W_29C011		0xC1
 #define W_29C020C		0x45
 #define W_29C040P		0x46
@@ -297,6 +306,7 @@
 void generic_spi_write_disable();
 int generic_spi_chip_erase_c7(struct flashchip *flash);
 int generic_spi_chip_write(struct flashchip *flash, uint8_t *buf);
+int generic_spi_chip_read(struct flashchip *flash, uint8_t *buf);
 
 /* 82802ab.c */
 int probe_82802ab(struct flashchip *flash);
Index: flashrom-big/flashchips.c
===================================================================
--- flashrom-big/flashchips.c	(Revision 3051)
+++ flashrom-big/flashchips.c	(Arbeitskopie)
@@ -51,13 +51,13 @@
 	{"MX29F002",	MX_ID,		MX_29F002,	256, 64 * 1024,
 	 probe_29f002,	erase_29f002, 	write_29f002},
 	{"MX25L4005",	MX_ID,		MX_25L4005,	512, 256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"MX25L8005",	MX_ID,		MX_25L8005,	1024, 256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"SST25VF040B",	SST_ID,		SST_25VF040B,	512,	256,
-	probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"SST25VF016B",	SST_ID,		SST_25VF016B,	2048,	256,
-	probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"SST29EE020A", SST_ID,		SST_29EE020A,	256, 128,
 	 probe_jedec,	erase_chip_jedec, write_jedec},
 	{"SST28SF040A", SST_ID,		SST_28SF040,	512, 256,
@@ -122,6 +122,14 @@
 	 probe_jedec,   erase_chip_jedec, write_39sf020},
 	{"W39V080A", 	WINBOND_ID, 	W_39V080A,	1024, 64*1024,
 	 probe_jedec,	erase_chip_jedec, write_39sf020},
+	{"W25x10",	WINBOND_NEX_ID, W_25X10,	128, 256, 
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
+	{"W25x20",	WINBOND_NEX_ID, W_25X20,	256, 256, 
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
+	{"W25x40",	WINBOND_NEX_ID, W_25X40,	512, 256, 
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
+	{"W25x80",	WINBOND_NEX_ID, W_25X80,	1024, 256, 
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M29F002B",	ST_ID, 		ST_M29F002B,	256, 64 * 1024,
 	 probe_jedec,	erase_chip_jedec, write_jedec},
 	{"M50FW040",	ST_ID, 		ST_M50FW040,	512, 64 * 1024,
@@ -151,23 +159,23 @@
 	{"M29F040B",	ST_ID, 		ST_M29F040B,	512, 64 * 1024,
 	 probe_29f040b, erase_29f040b,	write_29f040b},
 	{"M25P05-A",	ST_ID,		ST_M25P05A,	64,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P10-A",	ST_ID,		ST_M25P10A,	128,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P20",	ST_ID,		ST_M25P20,	256,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P40",	ST_ID,		ST_M25P40,	512,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P80",	ST_ID,		ST_M25P80,	1024,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P16",	ST_ID,		ST_M25P16,	2048,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P32",	ST_ID,		ST_M25P32,	4096,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P64",	ST_ID,		ST_M25P64,	8192,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"M25P128",	ST_ID,		ST_M25P128,	16384,	256,
-	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
+	 probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write, generic_spi_chip_read},
 	{"82802ab",	137,		173,		512, 64 * 1024,
 	 probe_82802ab, erase_82802ab,	write_82802ab},
 	{"82802ac",	137,		172,		1024, 64 * 1024,
Index: flashrom-big/spi.c
===================================================================
--- flashrom-big/spi.c	(Revision 3051)
+++ flashrom-big/spi.c	(Arbeitskopie)
@@ -76,9 +76,27 @@
 #define JEDEC_RDSR_INSIZE	0x01
 #define JEDEC_RDSR_BIT_WIP	(0x01 << 0)
 
+/* Write Status Register */
+#define JEDEC_WRSR	0x01
+#define JEDEC_WRSR_OUTSIZE	0x02
+#define JEDEC_WRSR_INSIZE	0x00
+
+/* Read the memory */
+#define JEDEC_READ	0x03
+#define JEDEC_READ_OUTSIZE	0x04
+/*      JEDEC_READ_INSIZE : any length */
+
+/* Write memory byte */
+#define JEDEC_BYTE_PROGRAM 0x02
+#define JEDEC_BYTE_PROGRAM_OUTSIZE 0x05
+#define JEDEC_BYTE_PROGRAM_INSIZE 0x00
+
 uint16_t it8716f_flashport = 0;
+/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */
+int fast_spi=1;
 
 void generic_spi_prettyprint_status_register(struct flashchip *flash);
+void spi_disable_blockprotect(void);
 
 /* Generic Super I/O helper functions */
 uint8_t regval(uint16_t port, uint8_t reg)
@@ -203,10 +221,10 @@
 			__FUNCTION__, writecnt);
 		return 1;
 	}
-	/* Start IO, 33MHz, readcnt input bytes, writecnt output bytes. Note:
+	/* Start IO, 33MHz (or 16), readcnt input bytes, writecnt output bytes. Note:
 	 * We can't use writecnt directly, but have to use a strange encoding.
 	 */ 
-	outb((0x5 << 4) | ((readcnt & 0x3) << 2) | (writeenc), port);
+	outb(((0x4+(fast_spi?1:0)) << 4) | ((readcnt & 0x3) << 2) | (writeenc), port);
 	do {
 		busy = inb(port) & 0x80;
 	} while (busy);
@@ -290,6 +308,24 @@
 	return readarr[0];
 }
 
+/* Prettyprint the status register. Common definitions.
+ */
+void generic_spi_prettyprint_status_register_common(uint8_t status)
+{
+	printf_debug("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
+		"%sset\n", (status & (1 << 5)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 4 / Block Protect 2 (BP2) is "
+		"%sset\n", (status & (1 << 4)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 3 / Block Protect 1 (BP1) is "
+		"%sset\n", (status & (1 << 3)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
+		"%sset\n", (status & (1 << 2)) ? "" : "not ");
+	printf_debug("Chip status register: Write Enable Latch (WEL) is "
+		"%sset\n", (status & (1 << 1)) ? "" : "not ");
+	printf_debug("Chip status register: Write In Progress (WIP/BUSY) is "
+		"%sset\n", (status & (1 << 0)) ? "" : "not ");
+}
+
 /* Prettyprint the status register. Works for
  * ST M25P series
  * MX MX25L series
@@ -300,20 +336,31 @@
 		"(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not ");
 	printf_debug("Chip status register: Bit 6 is "
 		"%sset\n", (status & (1 << 6)) ? "" : "not ");
-	printf_debug("Chip status register: Bit 5 is "
-		"%sset\n", (status & (1 << 5)) ? "" : "not ");
-	printf_debug("Chip status register: Block Protect 2 (BP2) is "
-		"%sset\n", (status & (1 << 4)) ? "" : "not ");
-	printf_debug("Chip status register: Block Protect 1 (BP1) is "
-		"%sset\n", (status & (1 << 3)) ? "" : "not ");
-	printf_debug("Chip status register: Block Protect 0 (BP0) is "
-		"%sset\n", (status & (1 << 2)) ? "" : "not ");
-	printf_debug("Chip status register: Write Enable Latch (WEL) is "
-		"%sset\n", (status & (1 << 1)) ? "" : "not ");
-	printf_debug("Chip status register: Write In Progress (WIP) is "
-		"%sset\n", (status & (1 << 0)) ? "" : "not ");
+	generic_spi_prettyprint_status_register_common(status);
 }
 
+/* Prettyprint the status register. Works for
+ * SST 25VF016
+ */
+void generic_spi_prettyprint_status_register_sst25vf016(uint8_t status)
+{
+	const char *bpt[]={
+		"none",
+		"1F0000H-1FFFFFH",
+		"1E0000H-1FFFFFH",
+		"1C0000H-1FFFFFH",
+		"180000H-1FFFFFH",
+		"100000H-1FFFFFH",
+		"all","all"
+	};
+	printf_debug("Chip status register: Block Protect Write Disable "
+		"(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not ");
+	printf_debug("Chip status register: Auto Address Increment Programming "
+		"(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not ");
+	generic_spi_prettyprint_status_register_common(status);
+	printf_debug("Resulting block protection : %s\n", bpt[(status&0x1c)>>2]);
+}
+
 void generic_spi_prettyprint_status_register(struct flashchip *flash)
 {
 	uint8_t status;
@@ -326,6 +373,10 @@
 		if ((flash->model_id & 0xff00) == 0x2000)
 			generic_spi_prettyprint_status_register_st_m25p(status);
 		break;
+	case SST_ID:
+		if (flash->model_id == SST_25VF016B)
+			generic_spi_prettyprint_status_register_sst25vf016(status);
+		break;
 	}
 }
 	
@@ -333,6 +384,7 @@
 {
 	const unsigned char cmd[] = JEDEC_CE_C7;
 	
+	spi_disable_blockprotect();
 	generic_spi_write_enable();
 	/* Send CE (Chip Erase) */
 	generic_spi_command(JEDEC_CE_C7_OUTSIZE, JEDEC_CE_C7_INSIZE, cmd, NULL);
@@ -392,7 +444,7 @@
 
 	generic_spi_write_enable();
 	outb(0x06 , it8716f_flashport + 1);
-	outb((3 << 4), it8716f_flashport);
+	outb(((2+(fast_spi?1:0)) << 4), it8716f_flashport);
 	for (i = 0; i < 256; i++) {
 		bios[256 * block + i] = buf[256 * block + i];
 	}
@@ -410,11 +462,113 @@
 		it8716f_spi_page_program(block, buf, bios);
 }
 
+/*
+ * This is according the SST25VF016 datasheet, who knows it is more
+ * generic that this...
+ */
+void spi_write_status_register(int status)
+{
+	const unsigned char cmd[] = {JEDEC_WRSR,(unsigned char)status};
+
+	/* Send WRSR (Write Status Register) */
+	generic_spi_command(JEDEC_WRSR_OUTSIZE, JEDEC_WRSR_INSIZE, cmd, NULL);
+
+}
+
+void spi_byte_program(int address, uint8_t byte)
+{
+	const unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE] = {JEDEC_BYTE_PROGRAM,
+		(address>>16)&0xff,
+		(address>>8)&0xff,
+		(address>>0)&0xff,
+		byte
+	};
+
+	/* Send Byte-Program */
+	generic_spi_command(JEDEC_BYTE_PROGRAM_OUTSIZE, JEDEC_BYTE_PROGRAM_INSIZE, cmd, NULL);
+
+}
+
+void spi_disable_blockprotect(void)
+{
+	uint8_t status;
+
+	status = generic_spi_read_status_register();
+	/* If there is block protection in effect, unprotect it first. */
+	if ((status & 0x3c) != 0) {
+		printf_debug("Some block protection in effect, disabling\n");
+		generic_spi_write_enable();
+		spi_write_status_register(status & ~0x3c);
+	}
+}
+
+/*
+ * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles
+ * Program chip using firmware cycle byte programming. (SLOW!)
+ */
+int it8716f_over512k_spi_chip_write(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	int i;
+	fast_spi=0;
+
+	spi_disable_blockprotect();
+	for (i=0; i<total_size; i++) {
+		generic_spi_write_enable();
+		spi_byte_program(i,buf[i]);
+		//while (generic_spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		myusec_delay(10);
+		//if (i%1024==0) fputc('b',stderr);
+	}
+	/* resume normal ops... */
+	outb(0x20, it8716f_flashport);
+	return 0;
+}
+
+void spi_3byte_read(int address, uint8_t *bytes, int len)
+{
+	const unsigned char cmd[JEDEC_READ_OUTSIZE] = {JEDEC_READ,
+		(address>>16)&0xff,
+		(address>>8)&0xff,
+		(address>>0)&0xff,
+	};
+
+	/* Send Read */
+	generic_spi_command(JEDEC_READ_OUTSIZE, len, cmd, bytes);
+
+}
+
+/*
+ * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles
+ * Need to read this big flash using firmware cycles 3 byte at a time.
+ */
+int generic_spi_chip_read(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	int i;
+	fast_spi=0;
+
+	if (total_size > 512 * 1024) {
+		for (i = 0; i < total_size; i+=3) {
+			int toread=3;
+			if (total_size-i < toread) toread=total_size-i;
+			spi_3byte_read(i, buf+i, toread);
+		}
+	} else {
+		memcpy(buf, (const char *)flash->virtual_memory, total_size);
+	}
+	return 0;
+}
+
 int generic_spi_chip_write(struct flashchip *flash, uint8_t *buf) {
 	int total_size = 1024 * flash->total_size;
 	int i;
-	for (i = 0; i < total_size / 256; i++) {
-		generic_spi_page_program(i, buf, (uint8_t *)flash->virtual_memory);
+	if (total_size > 512 * 1024) {
+		it8716f_over512k_spi_chip_write(flash, buf);
+	} else {
+		for (i = 0; i < total_size / 256; i++) {
+			generic_spi_page_program(i, buf, (uint8_t *)flash->virtual_memory);
+		}
 	}
 	return 0;
 }






More information about the coreboot mailing list