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

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Fri Jan 18 03:00:49 CET 2008


On 17.01.2008 22:25, Ronald Hoogenboom wrote:
> On Thu, 2008-01-17 at 00:56 +0100, Carl-Daniel Hailfinger wrote:
>
>   
>> Please see
>> http://www.coreboot.org/Development_Guidelines#Sign-off_Procedure for
>> details on patch submission. There are two things that block acceptance
>> of your patch:
>> - A "Signed-off-by:" line is missing. Please add one.
>>     
>
> I'll try again now... Sorry for my ignorance (or failure to read the
> procedure).
>   

No problem, thanks for fixing this up.

>> The function is probably more specific to IT8716F and chips bigger than
>> 512 kByte. Maybe rename the function and have the IT8716F writing code
>> switch to you method if the chip is bigger than 512 kB?
>>     
>
> I've made it a little more generic, but otoh, the spi.c is sort of less
> generic than the filename would suggest, quite IT8716F specific.
>   

Yes, but I always try to keep infrastructure generic enough to be able
to support other SPI hosts later.

> I've made all spi flash chips over 512k point to the new functions and
> hope that they will all work for them too (I cannot test this). With the
> generic functions, it will definately not work because of the 8716's
> 512k limit, so it won't break anything that is not already broken...
> But the lack of block-write seems to me is quite sst chip specific
> (remember they have an AAI mode instead, which doesn't play well with
> the limited io transfer length options of the IT8716). It might be more
> appropriate to have an 'over512k_page_write' for more speed with chips
> that do support that. Also the byte program wait time is hard wired to
> 10 us (following the 25vf016b datasheet). And the block protect
> enablement might also NOT be so generic.
>   

By the way, the lack of block-write in the data sheet does not mean it
will not work with the real chip.


>> Please try to address the comments above and repost.
>> Note: I suggest that the "maximum frequency" stuff could be handled in
>> another patch because it requires redesign of some structures (needs
>> discussion) and is also is logically another change.
>>
>>     
>
> For now, the frequency is set to 33/2 for the new large flash functions,
> pending a better approach.
>
> The reworked attached patch also includes the added winbond (previously
> known as Nexcom) chips.
>
> Signed-off-by: Ronald Hoogenboom <hoogenboom30 at zonnet.nl>
>   

Nice. I have restructured your patch a bit, but I'd like to improve even
further. Could you take a look at all those places where you added
"const unsigned char cmd[] = XXX" and use #defines for commands like
those at the top of spi.c? That would improve readability of the code.
Please verify the code still works for you.

Explicit mentioning of flash functions for chips >512 kByte has been
converted to implicit decisions. Some cosmetic changes were done as well.

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


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)
@@ -77,6 +77,8 @@
 #define JEDEC_RDSR_BIT_WIP	(0x01 << 0)
 
 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);
 
@@ -203,10 +205,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);
@@ -314,6 +316,39 @@
 		"%sset\n", (status & (1 << 0)) ? "" : "not ");
 }
 
+/* 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 ");
+	printf_debug("Chip status register: Bit 5 (BP3) is "
+		"%sset\n", (status & (1 << 5)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 4 (BP2) is "
+		"%sset\n", (status & (1 << 4)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 3 (BP1) is "
+		"%sset\n", (status & (1 << 3)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 2 (BP0) is "
+		"%sset\n", (status & (1 << 2)) ? "" : "not ");
+	printf_debug("Resulting block protection : %s\n", bpt[(status&0x1c)>>2]);
+	printf_debug("Chip status register: Write Enable Latch (WEL) is "
+		"%sset\n", (status & (1 << 1)) ? "" : "not ");
+	printf_debug("Chip status register: Write In Progress (BUSY) is "
+		"%sset\n", (status & (1 << 0)) ? "" : "not ");
+}
+
 void generic_spi_prettyprint_status_register(struct flashchip *flash)
 {
 	uint8_t status;
@@ -326,6 +361,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;
 	}
 }
 	
@@ -392,7 +431,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 +449,107 @@
 		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[] = {0x01,(unsigned char)status};
+
+	/* Send WRSR (Write Status Register) */
+	generic_spi_command(2, 0, cmd, NULL);
+
+}
+
+void spi_byte_program(int address, uint8_t byte)
+{
+	const unsigned char cmd[5] = {0x02,
+		(address>>16)&0xff,
+		(address>>8)&0xff,
+		(address>>0)&0xff,
+		byte
+	};
+
+	/* Send Byte-Program */
+	generic_spi_command(5, 0, cmd, NULL);
+
+}
+
+/*
+ * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles
+ * Program chip using firmware cycle byte programming. (SLOW!)
+ */
+int over512k_spi_chip_write(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	uint8_t status;
+	int i;
+	fast_spi=0;
+
+	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);
+	}
+	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[5] = {0x03,
+		(address>>16)&0xff,
+		(address>>8)&0xff,
+		(address>>0)&0xff,
+	};
+
+	/* Send Read */
+	generic_spi_command(4, 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) {
+		memcpy(buf, (const char *)flash->virtual_memory, total_size);
+	} else {
+		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);
+		}
+	}
+	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) {
+		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