Add SPI flash emulation capability to dummyflasher. You have to choose at compile time between - no emulation - ST M25P10.RES SPI flash chip (RES, page write) - SST SST25VF040.REMS SPI flash chip (REMS, byte write) - SST SST25VF032B SPI flash chip (RDID, AAI write)
This code helped me find and fix various bugs in the SPI write code (patches forthcoming).
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-emulate_spi_flashchip/dummyflasher.c =================================================================== --- flashrom-emulate_spi_flashchip/dummyflasher.c (Revision 1216) +++ flashrom-emulate_spi_flashchip/dummyflasher.c (Arbeitskopie) @@ -25,6 +25,45 @@ #include "chipdrivers.h" #include "programmer.h"
+//#define EMULATE_ST_M25P10_RES 1 +//#define EMULATE_SST_SST25VF040_REMS 1 +//#define EMULATE_SST_SST25VF032B 1 + +#if EMULATE_ST_M25P10_RES + EMULATE_SST_SST25VF040_REMS + EMULATE_SST_SST25VF032B > 1 +#error Only one chip can be emulated. Please decide which one you want. +#endif + +#if EMULATE_ST_M25P10_RES || EMULATE_SST_SST25VF040_REMS || EMULATE_SST_SST25VF032B +#define EMULATE_SPI_CHIP 1 +#endif + +#if EMULATE_SPI_CHIP +#define EMULATE_CHIP 1 +#include "spi.h" +#endif + +#if EMULATE_ST_M25P10_RES +#define EMU_FLASHCHIP_SIZE 128 * 1024 +#define MAX_BYTEPROGRAM_SIZE 128 +#define MAX_AAI_SIZE 0 +#endif + +#if EMULATE_SST_SST25VF040_REMS +#define EMU_FLASHCHIP_SIZE 512 * 1024 +#define MAX_BYTEPROGRAM_SIZE 1 +#define MAX_AAI_SIZE 0 +#endif + +#if EMULATE_SST_SST25VF032B +#define EMU_FLASHCHIP_SIZE 4 * 1024 * 1024 +#define MAX_BYTEPROGRAM_SIZE 1 +#define MAX_AAI_SIZE 2 +#endif + +#if EMULATE_CHIP +static uint8_t flashchip_contents[EMU_FLASHCHIP_SIZE]; +#endif + static void tolower_string(char *str) { for (; *str != '\0'; str++) @@ -65,6 +104,25 @@ if (buses_supported == CHIP_BUSTYPE_NONE) msg_pdbg("Support for all flash bus types disabled.\n"); free(bustext); + +#if EMULATE_ST_M25P10_RES + msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page write)\n"); +#endif +#if EMULATE_SST_SST25VF040_REMS + msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, byte " + "write)\n"); +#endif +#if EMULATE_SST_SST25VF032B + msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI " + "write)\n"); +#endif +#if EMULATE_CHIP + msg_pdbg("Filling fake flash chip with 0xff, size %i\n", + sizeof(flashchip_contents)); + memset(flashchip_contents, 0xff, sizeof(flashchip_contents)); +#else + msg_pdbg("Not emulating any flash chip.\n"); +#endif return 0; }
@@ -140,6 +198,123 @@ return; }
+#if EMULATE_SPI_CHIP +static int emulate_spi_chip_response(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + int offs; +#if EMULATE_SST_SST25VF032B + static int aai_offs; + static int aai_active = 0; +#endif + if (writecnt == 0) { + msg_cerr("No command sent to the chip!\n"); + return 1; + } + switch (writearr[0]) { +#if EMULATE_ST_M25P10_RES + case JEDEC_RES: + /* Respond with ST_M25P10_RES. */ + if (readcnt > 0) + readarr[0] = 0x10; + break; +#endif +#if EMULATE_SST_SST25VF040_REMS + case JEDEC_REMS: + /* Respond with SST_SST25VF040_REMS. */ + if (readcnt > 0) + readarr[0] = 0xbf; + if (readcnt > 1) + readarr[1] = 0x44; + break; +#endif +#if EMULATE_SST_SST25VF032B + case JEDEC_RDID: + /* Respond with SST_SST25VF032B. */ + if (readcnt > 0) + readarr[0] = 0xbf; + if (readcnt > 1) + readarr[1] = 0x25; + if (readcnt > 2) + readarr[2] = 0x4a; + break; +#endif + case JEDEC_RDSR: + memset(readarr, 0, readcnt); +#if EMULATE_SST_SST25VF032B + if (aai_active) + memset(readarr, 1 << 6, readcnt); +#endif + break; + case JEDEC_READ: + offs = writearr[1] << 16 | writearr[2] << 8 | + writearr[3]; + /* Truncate to EMU_FLASHCHIP_SIZE. */ + offs %= EMU_FLASHCHIP_SIZE; + if (readcnt > 0) + memcpy(readarr, flashchip_contents + offs, readcnt); + break; + case JEDEC_BYTE_PROGRAM: + offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; + /* Truncate to EMU_FLASHCHIP_SIZE. */ + offs %= EMU_FLASHCHIP_SIZE; + if (writecnt < 5) { + msg_cerr("BYTE PROGRAM size too short!\n"); + return 1; + } + if (writecnt - 4 > MAX_BYTEPROGRAM_SIZE) { + msg_cerr("Max BYTE PROGRAM size exceeded!\n"); + return 1; + } + memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4); + break; +#if EMULATE_SST_SST25VF032B + case JEDEC_AAI_WORD_PROGRAM: + if (!aai_active) { + if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) { + msg_cerr("Initial AAI WORD PROGRAM size too " + "short!\n"); + return 1; + } + if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) { + msg_cerr("Initial AAI WORD PROGRAM size too " + "long!\n"); + return 1; + } + aai_active = 1; + aai_offs = writearr[1] << 16 | writearr[2] << 8 | + writearr[3]; + /* Truncate to EMU_FLASHCHIP_SIZE. */ + aai_offs %= EMU_FLASHCHIP_SIZE; + memcpy(flashchip_contents + aai_offs, writearr + 4, 2); + aai_offs += 2; + } else { + if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) { + msg_cerr("Continuation AAI WORD PROGRAM size " + "too short!\n"); + return 1; + } + if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) { + msg_cerr("Continuation AAI WORD PROGRAM size " + "too long!\n"); + return 1; + } + memcpy(flashchip_contents + aai_offs, writearr + 1, 2); + aai_offs += 2; + } + break; + case JEDEC_WRDI: + aai_active = 0; + break; +#endif + default: + /* No special response. */ + break; + } + return 0; +} +#endif + int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { @@ -157,6 +332,9 @@ readarr[i] = 0xff; }
+#if EMULATE_SPI_CHIP + emulate_spi_chip_response(writecnt, readcnt, writearr, readarr); +#endif msg_pspew("\n"); return 0; }