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

Ronald Hoogenboom ronald at zonnet.nl
Thu Jan 17 00:13:48 CET 2008


I mounted a SST25VF016B 2MByte flash chip on the second SPI bios
landpattern on the m57sli mobo (as per the m57sli tutorial).
There as some problems with that, on the one side from the point of the
LPC memory mapping options of the IT8716F (max. 512KB contiguous) and on
the other side with the programming method(s) supported by the SST flash
chip (only the byte-mode programming is compatible with the IT8716).
Lets call them problem1 and problem2.

The reason why I want the 2MB is that I would like to try direct Linux
kernel as the payload.

Problem1 and Problem2 have impact on the useability of flashrom, which I
have sort-of solved (patch below). Problem1 also has impact on the
elfboot.c and rom-stream.c in coreboot (linuxbios), which I'm still
investigating (suggestions welcome!).

Problem1 (for reading) is solved by NOT using the mmap method for
reading the flash contents, but using outb() for sending the flash read
commands (using a specific 25vf016 read function). Also the normal read
command is only supported up to 25MHz by this chip, so I cannot use the
33MHz speed as used normally by spi.c. There is also a 'high speed' read
command (0x0b), which inserts an extra dummy byte between address and
data, but as the 8716 only allows max. 3 bytes read per io transfer, the
gain (3 bytes per io transfer @ 16MHz versus 2 bytes per io transfer @
33MHz) is negligible.

Problem2 (for writing) is solved similarly: The mmap write method cannot
be used effectively, because the flash chip needs a Write-enable command
for each Byte-program (no block program concept in byte-program mode).
The chip has a so-called AAI (auto address increment) programming mode
instead, but that cannot be used with the 8716 chip, because it needs 6
byte and 3 byte io transfers, which it doesn't support (bah!). Not using
the mmap writes also solves the limited LPC memory address window. So,
there is also a 25vf016 specific write function.

NOTE: there may be some offset because of other changes...

Index: flash.h
===================================================================
--- flash.h	(revision 3051)
+++ flash.h	(working copy)
@@ -297,6 +303,8 @@
 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 sst25vf016_spi_chip_write(struct flashchip *flash, uint8_t *buf);
+int sst25vf016_spi_chip_read(struct flashchip *flash, uint8_t *buf);
 
 /* 82802ab.c */
 int probe_82802ab(struct flashchip *flash);
Index: flashchips.c
===================================================================
--- flashchips.c	(revision 3051)
+++ flashchips.c	(working copy)
@@ -57,7 +57,7 @@
 	{"SST25VF040B",	SST_ID,		SST_25VF040B,	512,	256,
 	probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
 	{"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,	sst25vf016_spi_chip_write,
sst25vf016_spi_chip_read},
 	{"SST29EE020A", SST_ID,		SST_29EE020A,	256, 128,
 	 probe_jedec,	erase_chip_jedec, write_jedec},
 	{"SST28SF040A", SST_ID,		SST_28SF040,	512, 256,
Index: spi.c
===================================================================
--- spi.c	(revision 3051)
+++ spi.c	(working copy)
@@ -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,6 +449,94 @@
 		it8716f_spi_page_program(block, buf, bios);
 }
 
+/*
+ * This is according the SST25VF016 datasheet, who knows it is more
+ * generic that this...
+ */
+void sst25vf016_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 sst25vf016_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 sst25vf016_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();
+		sst25vf016_spi_write_status_register(status&~0x3c);
+	}
+	for (i=0; i<total_size; i++) {
+		generic_spi_write_enable();
+		sst25vf016_spi_byte_program(i,buf[i]);
+		//while (generic_spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+			usleep(10);
+		if (i%1024==0) fputc('b',stderr);
+	}
+	/* resume normal ops... */
+	outb(0x20, it8716f_flashport);
+	return 0;
+}
+
+void sst25vf016_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 sst25vf016_spi_chip_read(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	int i;
+	fast_spi=0;
+
+	for (i = 0; i < total_size; i+=3) {
+		int toread=3;
+		if (total_size-i < toread) toread=total_size-i;
+		sst25vf016_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;





More information about the coreboot mailing list