SST25VF040B using 0x90 identification and AAI write

SST AAI is Auto Address Increment writing, a streamed write to the flash chip
where the first write command sets a starting address and following commands
simply append data. Unfortunately not supported by Winbond SPI masters.

From July 2008.

Corresponding to flashrom svn r407 and coreboot v2 svn r3913.

Signed-off-by: Peter Stuge <peter@stuge.se>
Acked-by: Peter Stuge <peter@stuge.se>
diff --git a/flash.h b/flash.h
index 0099b14..c74bacb 100644
--- a/flash.h
+++ b/flash.h
@@ -523,6 +523,7 @@
 int spi_disable_blockprotect(void);
 void spi_byte_program(int address, uint8_t byte);
 int spi_nbyte_read(int address, uint8_t *bytes, int len);
+int spi_aai_write(struct flashchip *flash, uint8_t *buf);
 
 /* 82802ab.c */
 int probe_82802ab(struct flashchip *flash);
diff --git a/flashchips.c b/flashchips.c
index ecadf55..950ce63 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -1128,6 +1128,20 @@
 
 	{
 		.vendor		= "SST",
+		.name		= "SST25VF040B.REMS",
+		.manufacture_id	= 0xbf,
+		.model_id	= 0x8d,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_spi_rems,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_aai_write,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
 		.name		= "SST25VF080B",
 		.manufacture_id	= SST_ID,
 		.model_id	= SST_25VF080B,
diff --git a/spi.c b/spi.c
index 756fbe5..57f4b13 100644
--- a/spi.c
+++ b/spi.c
@@ -615,3 +615,29 @@
 
 	return 1;
 }
+
+int spi_aai_write(struct flashchip *flash, uint8_t *buf) {
+	uint32_t pos = 2, size = flash->total_size * 1024;
+	unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]};
+	switch (flashbus) {
+		case BUS_TYPE_WBSIO_SPI:
+			fprintf(stderr, "%s: impossible with Winbond SPI masters, degrading to byte program\n", __func__);
+			return spi_chip_write(flash, buf);
+		default:
+			break;
+	}
+	flash->erase(flash);
+	spi_write_enable();
+	spi_command(6, 0, w, NULL);
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		myusec_delay(5); /* SST25VF040B Tbp is max 10us */
+	while (pos < size) {
+		w[1] = buf[pos++];
+		w[2] = buf[pos++];
+		spi_command(3, 0, w, NULL);
+		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+			myusec_delay(5); /* SST25VF040B Tbp is max 10us */
+	}
+	spi_write_disable();
+	return 0;
+}