Author: hailfinger Date: 2008-01-19 01:04:46 +0100 (Sat, 19 Jan 2008) New Revision: 3061
Modified: trunk/util/flashrom/flash.h trunk/util/flashrom/flashchips.c trunk/util/flashrom/spi.c Log: Support SPI flash chips bigger than 512 kByte sitting behind IT8716F Super I/O performing LPC-to-SPI flash translation.
Signed-off-by: Ronald Hoogenboom hoogenboom30@zonnet.nl Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net Acked-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Modified: trunk/util/flashrom/flash.h =================================================================== --- trunk/util/flashrom/flash.h 2008-01-18 18:04:28 UTC (rev 3060) +++ trunk/util/flashrom/flash.h 2008-01-19 00:04:46 UTC (rev 3061) @@ -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);
Modified: trunk/util/flashrom/flashchips.c =================================================================== --- trunk/util/flashrom/flashchips.c 2008-01-18 18:04:28 UTC (rev 3060) +++ trunk/util/flashrom/flashchips.c 2008-01-19 00:04:46 UTC (rev 3061) @@ -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,
Modified: trunk/util/flashrom/spi.c =================================================================== --- trunk/util/flashrom/spi.c 2008-01-18 18:04:28 UTC (rev 3060) +++ trunk/util/flashrom/spi.c 2008-01-19 00:04:46 UTC (rev 3061) @@ -1,7 +1,8 @@ /* * This file is part of the flashrom project. * - * Copyright (C) 2007 Carl-Daniel Hailfinger + * Copyright (C) 2007, 2008 Carl-Daniel Hailfinger + * Copyright (C) 2008 Ronald Hoogenboom ronald@zonnet.nl * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,9 +77,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_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 +222,11 @@ __FUNCTION__, writecnt); return 1; } - /* Start IO, 33MHz, readcnt input bytes, writecnt output bytes. Note: + /* Start IO, 33 or 16 MHz, 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); @@ -242,7 +262,6 @@
/* Send WREN (Write Enable) */ generic_spi_command(JEDEC_WREN_OUTSIZE, JEDEC_WREN_INSIZE, cmd, NULL); - }
void generic_spi_write_disable() @@ -267,7 +286,7 @@ /* Print the status register to tell the * user about possible write protection. */ - generic_spi_prettyprint_status_register(flash); + spi_prettyprint_status_register(flash);
return 1; } @@ -290,32 +309,62 @@ return readarr[0]; }
-/* Prettyprint the status register. Works for - * ST M25P series - * MX MX25L series +/* Prettyprint the status register. Common definitions. */ -void generic_spi_prettyprint_status_register_st_m25p(uint8_t status) +void spi_prettyprint_status_register_common(uint8_t status) { - printf_debug("Chip status register: Status Register Write Disable " - "(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 " + printf_debug("Chip status register: Bit 5 / Block Protect 3 (BP3) is " "%sset\n", (status & (1 << 5)) ? "" : "not "); - printf_debug("Chip status register: Block Protect 2 (BP2) is " + printf_debug("Chip status register: Bit 4 / Block Protect 2 (BP2) is " "%sset\n", (status & (1 << 4)) ? "" : "not "); - printf_debug("Chip status register: Block Protect 1 (BP1) is " + printf_debug("Chip status register: Bit 3 / Block Protect 1 (BP1) is " "%sset\n", (status & (1 << 3)) ? "" : "not "); - printf_debug("Chip status register: Block Protect 0 (BP0) is " + 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) is " + printf_debug("Chip status register: Write In Progress (WIP/BUSY) is " "%sset\n", (status & (1 << 0)) ? "" : "not "); }
-void generic_spi_prettyprint_status_register(struct flashchip *flash) +/* Prettyprint the status register. Works for + * ST M25P series + * MX MX25L series + */ +void spi_prettyprint_status_register_st_m25p(uint8_t status) { + printf_debug("Chip status register: Status Register Write Disable " + "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not "); + printf_debug("Chip status register: Bit 6 is " + "%sset\n", (status & (1 << 6)) ? "" : "not "); + spi_prettyprint_status_register_common(status); +} + +/* Prettyprint the status register. Works for + * SST 25VF016 + */ +void 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 "); + spi_prettyprint_status_register_common(status); + printf_debug("Resulting block protection : %s\n", + bpt[(status & 0x1c) >> 2]); +} + +void spi_prettyprint_status_register(struct flashchip *flash) +{ uint8_t status;
status = generic_spi_read_status_register(); @@ -324,8 +373,12 @@ case ST_ID: case MX_ID: if ((flash->model_id & 0xff00) == 0x2000) - generic_spi_prettyprint_status_register_st_m25p(status); + spi_prettyprint_status_register_st_m25p(status); break; + case SST_ID: + if (flash->model_id == SST_25VF016B) + spi_prettyprint_status_register_sst25vf016(status); + break; } } @@ -333,6 +386,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 +446,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 +464,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]); + /* FIXME: We really should read the status register and delay + * accordingly. + */ + //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; }