dummyflasher.c: add support for SFDP by adding a new emulator chip: MX25L6436
The chip features a complete 1.0 SFDP JEDEC flash parameter table and also a
vendor-specific extension table (defining voltages, lock bits etc).
NB: the MX25L6436 uses the same RDID as the MX25L6405.
Corresponding to flashrom svn r1534.
Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
diff --git a/dummyflasher.c b/dummyflasher.c
index 50e8bf3..29256c2 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -46,6 +46,7 @@
EMULATE_ST_M25P10_RES,
EMULATE_SST_SST25VF040_REMS,
EMULATE_SST_SST25VF032B,
+ EMULATE_MACRONIX_MX25L6436,
};
static enum emu_chip emu_chip = EMULATE_NONE;
static char *emu_persistent_image = NULL;
@@ -63,6 +64,33 @@
int spi_blacklist_size = 0;
int spi_ignorelist_size = 0;
static uint8_t emu_status = 0;
+
+/* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
+static const uint8_t const sfdp_table[] = {
+ 0x53, 0x46, 0x44, 0x50, // @0x00: SFDP signature
+ 0x00, 0x01, 0x01, 0xFF, // @0x04: revision 1.0, 2 headers
+ 0x00, 0x00, 0x01, 0x09, // @0x08: JEDEC SFDP header rev. 1.0, 9 DW long
+ 0x1C, 0x00, 0x00, 0xFF, // @0x0C: PTP0 = 0x1C (instead of 0x30)
+ 0xC2, 0x00, 0x01, 0x04, // @0x10: Macronix header rev. 1.0, 4 DW long
+ 0x48, 0x00, 0x00, 0xFF, // @0x14: PTP1 = 0x48 (instead of 0x60)
+ 0xFF, 0xFF, 0xFF, 0xFF, // @0x18: hole.
+ 0xE5, 0x20, 0xC9, 0xFF, // @0x1C: SFDP parameter table start
+ 0xFF, 0xFF, 0xFF, 0x03, // @0x20
+ 0x00, 0xFF, 0x08, 0x6B, // @0x24
+ 0x08, 0x3B, 0x00, 0xFF, // @0x28
+ 0xEE, 0xFF, 0xFF, 0xFF, // @0x2C
+ 0xFF, 0xFF, 0x00, 0x00, // @0x30
+ 0xFF, 0xFF, 0x00, 0xFF, // @0x34
+ 0x0C, 0x20, 0x0F, 0x52, // @0x38
+ 0x10, 0xD8, 0x00, 0xFF, // @0x3C: SFDP parameter table end
+ 0xFF, 0xFF, 0xFF, 0xFF, // @0x40: hole.
+ 0xFF, 0xFF, 0xFF, 0xFF, // @0x44: hole.
+ 0x00, 0x36, 0x00, 0x27, // @0x48: Macronix parameter table start
+ 0xF4, 0x4F, 0xFF, 0xFF, // @0x4C
+ 0xD9, 0xC8, 0xFF, 0xFF, // @0x50
+ 0xFF, 0xFF, 0xFF, 0xFF, // @0x54: Macronix parameter table end
+};
+
#endif
#endif
@@ -301,6 +329,19 @@
msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
"write)\n");
}
+ if (!strcmp(tmp, "MX25L6436")) {
+ emu_chip = EMULATE_MACRONIX_MX25L6436;
+ emu_chip_size = 8 * 1024 * 1024;
+ emu_max_byteprogram_size = 256;
+ emu_max_aai_size = 0;
+ emu_jedec_se_size = 4 * 1024;
+ emu_jedec_be_52_size = 32 * 1024;
+ emu_jedec_be_d8_size = 64 * 1024;
+ emu_jedec_ce_60_size = emu_chip_size;
+ emu_jedec_ce_c7_size = emu_chip_size;
+ msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
+ "SFDP)\n");
+ }
#endif
if (emu_chip == EMULATE_NONE) {
msg_perr("Invalid chip specified for emulation: %s\n", tmp);
@@ -449,7 +490,7 @@
const unsigned char *writearr,
unsigned char *readarr)
{
- unsigned int offs, i;
+ unsigned int offs, i, toread;
static int unsigned aai_offs;
if (writecnt == 0) {
@@ -503,20 +544,30 @@
readarr[1] = 0x44;
break;
case JEDEC_RDID:
- if (emu_chip != EMULATE_SST_SST25VF032B)
+ switch (emu_chip) {
+ case EMULATE_SST_SST25VF032B:
+ if (readcnt > 0)
+ readarr[0] = 0xbf;
+ if (readcnt > 1)
+ readarr[1] = 0x25;
+ if (readcnt > 2)
+ readarr[2] = 0x4a;
break;
- /* Respond with SST_SST25VF032B. */
- if (readcnt > 0)
- readarr[0] = 0xbf;
- if (readcnt > 1)
- readarr[1] = 0x25;
- if (readcnt > 2)
- readarr[2] = 0x4a;
+ case EMULATE_MACRONIX_MX25L6436:
+ if (readcnt > 0)
+ readarr[0] = 0xc2;
+ if (readcnt > 1)
+ readarr[1] = 0x20;
+ if (readcnt > 2)
+ readarr[2] = 0x17;
+ break;
+ default: /* ignore */
+ break;
+ }
break;
- case JEDEC_RDSR: {
+ case JEDEC_RDSR:
memset(readarr, emu_status, readcnt);
break;
- }
/* FIXME: this should be chip-specific. */
case JEDEC_EWSR:
case JEDEC_WREN:
@@ -673,6 +724,41 @@
/* emu_jedec_ce_c7_size is emu_chip_size. */
memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size);
break;
+ case JEDEC_SFDP:
+ if (emu_chip != EMULATE_MACRONIX_MX25L6436)
+ break;
+ if (writecnt < 4)
+ break;
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+
+ /* SFDP expects one dummy byte after the address. */
+ if (writecnt == 4) {
+ /* The dummy byte was not written, make sure it is read instead.
+ * Shifting and shortening the read array does achieve this goal.
+ */
+ readarr++;
+ readcnt--;
+ } else {
+ /* The response is shifted if more than 5 bytes are written, because SFDP data is
+ * already shifted out by the chip while those superfluous bytes are written. */
+ offs += writecnt - 5;
+ }
+
+ /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
+ * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
+ * This is a reasonable implementation choice in hardware because it saves a few gates. */
+ if (offs >= sizeof(sfdp_table)) {
+ msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
+ "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
+ offs %= sizeof(sfdp_table);
+ }
+ toread = min(sizeof(sfdp_table) - offs, readcnt);
+ memcpy(readarr, sfdp_table + offs, toread);
+ if (toread < readcnt)
+ msg_pdbg("Crossing the SFDP table boundary in a single "
+ "continuous chunk produces undefined results "
+ "after that point.\n");
+ break;
default:
/* No special response. */
break;
@@ -703,6 +789,7 @@
case EMULATE_ST_M25P10_RES:
case EMULATE_SST_SST25VF040_REMS:
case EMULATE_SST_SST25VF032B:
+ case EMULATE_MACRONIX_MX25L6436:
if (emulate_spi_chip_response(writecnt, readcnt, writearr,
readarr)) {
msg_pdbg("Invalid command sent to flash chip!\n");