Add support for the JEDEC RES

Add support for the JEDEC RES (Read Electronic Signature and Resume from
Powerdown) SPI command to identify older SPI chips which can't handle
JEDEC RDID.

Since RES gives a one-byte identifier which is shared among many
different vendors and even different sizes, we want to match RES as a
last resort if RDID returns 0xff 0xff 0xff.

Corresponding to flashrom svn r235 and coreboot v2 svn r3320.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Peter Stuge <peter@stuge.se>

This is a heavily reworked version of a patch by Fredrik Tolf, which was
Signed-off-by: Fredrik Tolf <fredrik@dolda2000.com>
diff --git a/flash.h b/flash.h
index 4f73e0d..5d7b645 100644
--- a/flash.h
+++ b/flash.h
@@ -177,6 +177,8 @@
 /*
  * MX25 chips are SPI, first byte of device ID is memory type,
  * second byte of device ID is log(bitsize)-9.
+ * Generalplus SPI chips seem to be compatible with Macronix
+ * and use the same set of IDs.
  */
 #define MX_ID			0xC2	/* Macronix (MX) */
 #define MX_25L512		0x2010	/* 2^19 kbit or 2^16 kByte */
@@ -266,6 +268,7 @@
 #define ST_M25P10A		0x2011
 #define ST_M25P20		0x2012
 #define ST_M25P40		0x2013
+#define ST_M25P40_RES		0x12
 #define ST_M25P80		0x2014
 #define ST_M25P16		0x2015
 #define ST_M25P32		0x2016
@@ -366,7 +369,8 @@
 extern char *lb_part, *lb_vendor;
 
 /* spi.c */
-int probe_spi(struct flashchip *flash);
+int probe_spi_rdid(struct flashchip *flash);
+int probe_spi_res(struct flashchip *flash);
 int it87xx_probe_spi_flash(const char *name);
 int spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
 void spi_write_enable();
diff --git a/flashchips.c b/flashchips.c
index 123dfca..ab80bd0 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -49,26 +49,26 @@
 	{"Fujitsu",	"MBM29F400TC",		FUJITSU_ID,	MBM29F400TC_STRANGE,	512,	64 * 1024,	TEST_UNTESTED,	probe_m29f400bt,	erase_m29f400bt,		write_coreboot_m29f400bt},
 	{"Intel",	"82802AB",		INTEL_ID,	173,			512,	64 * 1024,	TEST_UNTESTED,	probe_82802ab,		erase_82802ab,			write_82802ab},
 	{"Intel",	"82802AC",		INTEL_ID,	172,			1024,	64 * 1024,	TEST_UNTESTED,	probe_82802ab,		erase_82802ab,			write_82802ab},
-	{"Macronix",	"MX25L4005",		MX_ID,		MX_25L4005,		512,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"Macronix",	"MX25L8005",		MX_ID,		MX_25L8005,		1024,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"Macronix",	"MX25L1605",		MX_ID,		MX_25L1605,		2048,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"Macronix",	"MX25L3205",		MX_ID,		MX_25L3205,		4096,	256,		TEST_OK_PREW,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"Macronix",	"MX25L4005",		MX_ID,		MX_25L4005,		512,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"Macronix",	"MX25L8005",		MX_ID,		MX_25L8005,		1024,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"Macronix",	"MX25L1605",		MX_ID,		MX_25L1605,		2048,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"Macronix",	"MX25L3205",		MX_ID,		MX_25L3205,		4096,	256,		TEST_OK_PREW,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
 	{"Macronix",	"MX29F002",		MX_ID,		MX_29F002,		256,	64 * 1024,	TEST_UNTESTED,	probe_29f002,		erase_29f002,			write_29f002},
 #ifndef DISABLE_DOC
 	{"M-Systems",	"MD-2802",		MSYSTEMS_ID,	MSYSTEMS_MD2802,	8,	8 * 1024,	TEST_UNTESTED,	probe_md2802,		erase_md2802,			write_md2802,		read_md2802},
 #endif
-	{"PMC",		"Pm25LV010",		PMC_ID,		PMC_25LV010,		128,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"PMC",		"Pm25LV016B",		PMC_ID,		PMC_25LV016B,		2048,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"PMC",		"Pm25LV020",		PMC_ID,		PMC_25LV020,		256,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"PMC",		"Pm25LV040",		PMC_ID,		PMC_25LV040,		512,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"PMC",		"Pm25LV080B",		PMC_ID,		PMC_25LV080B,		1024,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"PMC",		"Pm25LV512",		PMC_ID,		PMC_25LV512,		64,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"PMC",		"Pm25LV010",		PMC_ID,		PMC_25LV010,		128,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"PMC",		"Pm25LV016B",		PMC_ID,		PMC_25LV016B,		2048,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"PMC",		"Pm25LV020",		PMC_ID,		PMC_25LV020,		256,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"PMC",		"Pm25LV040",		PMC_ID,		PMC_25LV040,		512,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"PMC",		"Pm25LV080B",		PMC_ID,		PMC_25LV080B,		1024,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"PMC",		"Pm25LV512",		PMC_ID,		PMC_25LV512,		64,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
 	{"PMC",		"Pm49FL002",		PMC_ID_NOPREFIX,PMC_49FL002,		256,	16 * 1024,	TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_49fl004},
 	{"PMC",		"Pm49FL004",		PMC_ID_NOPREFIX,PMC_49FL004,		512,	64 * 1024,	TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_49fl004},
 	{"Sharp",	"LHF00L04",		SHARP_ID,	SHARP_LHF00L04,		1024,	64 * 1024,	TEST_UNTESTED,	probe_lhf00l04,		erase_lhf00l04,			write_lhf00l04},
-	{"Spansion",	"S25FL016A",		SPANSION_ID,	SPANSION_S25FL016A,	2048,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"SST",		"SST25VF016B",		SST_ID,		SST_25VF016B,		2048,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
-	{"SST",		"SST25VF040B",		SST_ID,		SST_25VF040B,		512,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"Spansion",	"S25FL016A",		SPANSION_ID,	SPANSION_S25FL016A,	2048,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"SST",		"SST25VF016B",		SST_ID,		SST_25VF016B,		2048,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
+	{"SST",		"SST25VF040B",		SST_ID,		SST_25VF040B,		512,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write,	spi_chip_read},
 	{"SST",		"SST28SF040A",		SST_ID,		SST_28SF040,		512,	256,		TEST_UNTESTED,	probe_28sf040,		erase_28sf040,			write_28sf040},
 	{"SST",		"SST29EE020A",		SST_ID,		SST_29EE020A,		256,	128,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_jedec},
 	{"SST",		"SST39SF010A",		SST_ID,		SST_39SF010,		128,	4096,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_39sf020},
@@ -91,15 +91,16 @@
 	{"SST",		"SST49LF040B",		SST_ID,		SST_49LF040B,		512,	64 * 1024,	TEST_UNTESTED,	probe_sst_fwhub,	erase_sst_fwhub,		write_sst_fwhub},
 	{"SST",		"SST49LF080A",		SST_ID,		SST_49LF080A,		1024,	4096,		TEST_UNTESTED,	probe_jedec,		erase_49lf040,			write_49lf040},
 	{"SST",		"SST49LF160C",		SST_ID,		SST_49LF160C,		2048,	4 * 1024,	TEST_UNTESTED,	probe_49lfxxxc,		erase_49lfxxxc,			write_49lfxxxc},
-	{"ST",		"M25P05-A",		ST_ID,		ST_M25P05A,		64,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P10-A",		ST_ID,		ST_M25P10A,		128,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P20",		ST_ID,		ST_M25P20,		256,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P40",		ST_ID,		ST_M25P40,		512,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P80",		ST_ID,		ST_M25P80,		1024,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P16",		ST_ID,		ST_M25P16,		2048,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P32",		ST_ID,		ST_M25P32,		4096,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P64",		ST_ID,		ST_M25P64,		8192,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"ST",		"M25P128",		ST_ID,		ST_M25P128,		16384,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P05-A",		ST_ID,		ST_M25P05A,		64,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P10-A",		ST_ID,		ST_M25P10A,		128,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P20",		ST_ID,		ST_M25P20,		256,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P40",		ST_ID,		ST_M25P40,		512,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P40-old",		ST_ID,		ST_M25P40_RES,		512,	256,		TEST_UNTESTED,	probe_spi_res,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P80",		ST_ID,		ST_M25P80,		1024,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P16",		ST_ID,		ST_M25P16,		2048,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P32",		ST_ID,		ST_M25P32,		4096,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P64",		ST_ID,		ST_M25P64,		8192,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"ST",		"M25P128",		ST_ID,		ST_M25P128,		16384,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
 	{"ST",		"M29F002B",		ST_ID,		ST_M29F002B,		256,	64 * 1024,	TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_jedec},
 	{"ST",		"M29F002T/NT",		ST_ID,		ST_M29F002T,		256,	64 * 1024,	TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_jedec},
 	{"ST",		"M29F040B",		ST_ID,		ST_M29F040B,		512,	64 * 1024,	TEST_UNTESTED,	probe_29f040b,		erase_29f040b,			write_29f040b},
@@ -118,10 +119,10 @@
 	{"SyncMOS",	"S29C51001T",		SYNCMOS_ID,	S29C51001T,		128,	128,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_49f002},
 	{"SyncMOS",	"S29C51002T",		SYNCMOS_ID,	S29C51002T,		256,	128,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_49f002},
 	{"SyncMOS",	"S29C51004T",		SYNCMOS_ID,	S29C51004T,		512,	128,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_49f002},
-	{"Winbond",	"W25x10",		WINBOND_NEX_ID,	W_25X10,		128,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"Winbond",	"W25x20",		WINBOND_NEX_ID,	W_25X20,		256,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"Winbond",	"W25x40",		WINBOND_NEX_ID,	W_25X40,		512,	256,		TEST_OK_PREW,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
-	{"Winbond",	"W25x80",		WINBOND_NEX_ID,	W_25X80,		1024,	256,		TEST_UNTESTED,	probe_spi,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"Winbond",	"W25x10",		WINBOND_NEX_ID,	W_25X10,		128,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"Winbond",	"W25x20",		WINBOND_NEX_ID,	W_25X20,		256,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"Winbond",	"W25x40",		WINBOND_NEX_ID,	W_25X40,		512,	256,		TEST_OK_PREW,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
+	{"Winbond",	"W25x80",		WINBOND_NEX_ID,	W_25X80,		1024,	256,		TEST_UNTESTED,	probe_spi_rdid,		spi_chip_erase_c7,	spi_chip_write, spi_chip_read},
 	{"Winbond",	"W29C011",		WINBOND_ID,	W_29C011,		128,	128,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_jedec},
 	{"Winbond",	"W29C020C",		WINBOND_ID,	W_29C020C,		256,	128,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_jedec},
 	{"Winbond",	"W29C040P",		WINBOND_ID,	W_29C040P,		512,	256,		TEST_UNTESTED,	probe_jedec,		erase_chip_jedec,		write_jedec},
@@ -136,11 +137,11 @@
 	{"Winbond",	"W39V080FA",		WINBOND_ID,	W_39V080FA,		1024,	64*1024,	TEST_UNTESTED,	probe_winbond_fwhub,	erase_winbond_fwhub,		write_winbond_fwhub},
 	{"Winbond",	"W39V080FA (dual mode)",WINBOND_ID,	W_39V080FA_DM,		512,	64*1024,	TEST_UNTESTED,	probe_winbond_fwhub,	erase_winbond_fwhub,		write_winbond_fwhub},
 
-	{"EON",		"unknown EON SPI chip",	EON_ID_NOPREFIX,GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi,		NULL,				NULL},
-	{"Macronix",	"unknown Macronix SPI chip",	MX_ID,	GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi,		NULL,				NULL},
-	{"PMC",		"unknown PMC SPI chip",	PMC_ID,		GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi,		NULL,				NULL},
-	{"SST",		"unknown SST SPI chip",	SST_ID,		GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi,		NULL,				NULL},
-	{"ST",		"unknown ST SPI chip",	ST_ID,		GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi,		NULL,				NULL},
+	{"EON",		"unknown EON SPI chip",	EON_ID_NOPREFIX,GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi_rdid,		NULL,				NULL},
+	{"Macronix",	"unknown Macronix SPI chip",	MX_ID,	GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi_rdid,		NULL,				NULL},
+	{"PMC",		"unknown PMC SPI chip",	PMC_ID,		GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi_rdid,		NULL,				NULL},
+	{"SST",		"unknown SST SPI chip",	SST_ID,		GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi_rdid,		NULL,				NULL},
+	{"ST",		"unknown ST SPI chip",	ST_ID,		GENERIC_DEVICE_ID,	0,	256,		TEST_UNTESTED,	probe_spi_rdid,		NULL,				NULL},
 
 	{NULL,}
 };
diff --git a/spi.c b/spi.c
index 786d555..ddb9ff8 100644
--- a/spi.c
+++ b/spi.c
@@ -49,6 +49,16 @@
 	return 0;
 }
 
+static int spi_res(unsigned char *readarr)
+{
+	const unsigned char cmd[JEDEC_RES_OUTSIZE] = {JEDEC_RES, 0, 0, 0};
+
+	if (spi_command(JEDEC_RES_OUTSIZE, JEDEC_RES_INSIZE, cmd, readarr))
+		return 1;
+	printf_debug("RES returned %02x.\n", readarr[0]);
+	return 0;
+}
+
 void spi_write_enable()
 {
 	const unsigned char cmd[JEDEC_WREN_OUTSIZE] = {JEDEC_WREN};
@@ -65,7 +75,7 @@
 	spi_command(JEDEC_WRDI_OUTSIZE, JEDEC_WRDI_INSIZE, cmd, NULL);
 }
 
-int probe_spi(struct flashchip *flash)
+int probe_spi_rdid(struct flashchip *flash)
 {
 	unsigned char readarr[3];
 	uint32_t manuf_id;
@@ -102,6 +112,35 @@
 	return 0;
 }
 
+int probe_spi_res(struct flashchip *flash)
+{
+	unsigned char readarr[3];
+	uint32_t model_id;
+	if (!spi_rdid(readarr)) {
+		/* Check if RDID returns 0xff 0xff 0xff, then we use RES. */
+		if ((readarr[0] != 0xff) || (readarr[1] != 0xff) ||
+		    (readarr[2] != 0xff))
+			return 0;
+	} else {
+		/* We couldn't issue RDID, it's pointless to try RES. */
+		return 0;
+	}
+	if (!spi_res(readarr)) {
+		model_id = readarr[0];
+		printf_debug("%s: id 0x%x\n", __FUNCTION__, model_id);
+		if (model_id == flash->model_id) {
+			/* Print the status register to tell the
+			 * user about possible write protection.
+			 */
+			spi_prettyprint_status_register(flash);
+
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 uint8_t spi_read_status_register()
 {
 	const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = {JEDEC_RDSR};
diff --git a/spi.h b/spi.h
index 15bac4e..f5c877c 100644
--- a/spi.h
+++ b/spi.h
@@ -29,6 +29,11 @@
 #define JEDEC_RDID_OUTSIZE	0x01
 #define JEDEC_RDID_INSIZE	0x03
 
+/* Read Electronic Signature */
+#define JEDEC_RES		0xab
+#define JEDEC_RES_OUTSIZE	0x04
+#define JEDEC_RES_INSIZE	0x01
+
 /* Write Enable */
 #define JEDEC_WREN		0x06
 #define JEDEC_WREN_OUTSIZE	0x01