dummyflasher: Add emulation for S25FL128L

Used to test WRSR_EXT2/3 support.

Signed-off-by: Nico Huber <nico.h@gmx.de>
Change-Id: Ic3cbea87218c973331b9b83e809e7d438407bc13
Original-Reviewed-on: https://review.coreboot.org/c/flashrom/+/64748
Original-Reviewed-by: Thomas Heijligen <src@posteo.de>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/71464
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/dummyflasher.c b/dummyflasher.c
index 27b212e..c352601 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -35,6 +35,7 @@
 	EMULATE_SST_SST25VF032B,
 	EMULATE_MACRONIX_MX25L6436,
 	EMULATE_WINBOND_W25Q128FV,
+	EMULATE_SPANSION_S25FL128L,
 };
 
 struct emu_data {
@@ -362,6 +363,21 @@
 		data->emu_jedec_ce_c7_size = data->emu_chip_size;
 		msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID)\n");
 	}
+	if (!strcmp(tmp, "S25FL128L")) {
+		data->emu_chip = EMULATE_SPANSION_S25FL128L;
+		data->emu_wrsr_ext2 = true;
+		data->emu_wrsr_ext3 = true;
+		data->emu_chip_size = 16 * 1024 * 1024;
+		data->emu_max_byteprogram_size = 256;
+		data->emu_max_aai_size = 0;
+		data->emu_status_len = 3;
+		data->emu_jedec_se_size = 4 * 1024;
+		data->emu_jedec_be_52_size = 32 * 1024;
+		data->emu_jedec_be_d8_size = 64 * 1024;
+		data->emu_jedec_ce_60_size = data->emu_chip_size;
+		data->emu_jedec_ce_c7_size = data->emu_chip_size;
+		msg_pdbg("Emulating Spansion S25FL128L SPI flash chip (RES, RDID, WP)\n");
+	}
 	if (data->emu_chip == EMULATE_NONE) {
 		msg_perr("Invalid chip specified for emulation: %s\n", tmp);
 		free(tmp);
@@ -580,12 +596,36 @@
 		}
 	}
 
+	if (data->emu_chip == EMULATE_SPANSION_S25FL128L) {
+		const bool srp0 = (data->emu_status[0] >> 7);
+		const bool srp1 = (data->emu_status[1] & 1);
+
+		const bool wp_active = (srp1 || (srp0 && data->hwwp));
+
+		if (wp_active) {
+			ro_bits = 0xff;
+		} else if (reg == STATUS2) {
+			/* SUS (bit_7) */
+			ro_bits = 0x80;
+			/* Once any of the lock bits (LB[0..3]) are set, they
+			   can't be unset. */
+			ro_bits |= data->emu_status[1] & (1 << 2);
+			ro_bits |= data->emu_status[1] & (1 << 3);
+			ro_bits |= data->emu_status[1] & (1 << 4);
+			ro_bits |= data->emu_status[1] & (1 << 5);
+		} else if (reg == STATUS3) {
+			/* Two reserved bits. */
+			ro_bits = 0x11;
+		}
+	}
+
 	return ro_bits;
 }
 
 static void update_write_protection(struct emu_data *data)
 {
-	if (data->emu_chip != EMULATE_WINBOND_W25Q128FV)
+	if (data->emu_chip != EMULATE_WINBOND_W25Q128FV &&
+	    data->emu_chip != EMULATE_SPANSION_S25FL128L)
 		return;
 
 	const struct wp_bits bits = {
@@ -731,6 +771,12 @@
 			if (readcnt > 0)
 				memset(readarr, 0x17, readcnt);
 			break;
+		case EMULATE_SPANSION_S25FL128L:
+			if (readcnt > 0)
+				readarr[0] = 0x60;
+			if (readcnt > 1)
+				readarr[1] = 0x18;
+			break;
 		default: /* ignore */
 			break;
 		}
@@ -788,6 +834,14 @@
 			if (readcnt > 2)
 				readarr[2] = 0x18;
 			break;
+		case EMULATE_SPANSION_S25FL128L:
+			if (readcnt > 0)
+				readarr[0] = 0x01;
+			if (readcnt > 1)
+				readarr[1] = 0x60;
+			if (readcnt > 2)
+				readarr[2] = 0x18;
+			break;
 		default: /* ignore */
 			break;
 		}
@@ -1108,6 +1162,7 @@
 	case EMULATE_SST_SST25VF032B:
 	case EMULATE_MACRONIX_MX25L6436:
 	case EMULATE_WINBOND_W25Q128FV:
+	case EMULATE_SPANSION_S25FL128L:
 		if (emulate_spi_chip_response(writecnt, readcnt, writearr,
 					      readarr, emu_data)) {
 			msg_pdbg("Invalid command sent to flash chip!\n");
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index 2ab5c75..62c6ce7 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -640,6 +640,8 @@
 .sp
 .RB "* Macronix " MX25L6436 " SPI flash chip (8192 kB, RDID, SFDP)"
 .sp
+.RB "* Spansion " S25FL128L " SPI flash chip (16384 kB, RDID)"
+.sp
 Example:
 .B "flashrom -p dummy:emulate=SST25VF040.REMS"
 .TP
@@ -722,7 +724,7 @@
 .TP
 .B Write protection
 .sp
-Chips with emulated WP: W25Q128FV.
+Chips with emulated WP: W25Q128FV, S25FL128L.
 .sp
 You can simulate state of hardware protection pin (WP) with the
 .sp