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;