sb/intel/spi: Use different SPIOPS for most SST flashes

Many supported SST flashes use the AAI OP (0xad) to write.

TESTED on Thinkpad X60 with SST25VF016B, flashrom can use AAI_WRITE op
with locked down SPIOPS.

Change-Id: Ica72eda04a8d9f4e563987871b1640565c6e7e12
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/35537
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
diff --git a/src/southbridge/intel/common/spi.c b/src/southbridge/intel/common/spi.c
index 268030b..73181cf 100644
--- a/src/southbridge/intel/common/spi.c
+++ b/src/southbridge/intel/common/spi.c
@@ -1060,9 +1060,9 @@
 	struct ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr);
 	u16 spi_opprefix;
 	u16 optype = 0;
-	struct intel_swseq_spi_config spi_config = {
+	struct intel_swseq_spi_config spi_config_default = {
 		{0x06, 0x50},  /* OPPREFIXES: EWSR and WREN */
-		{ /* OPTYPE and OPCODE */
+		{ /* OPCODE and OPTYPE */
 			{0x01, WRITE_NO_ADDR},		/* WRSR: Write Status Register */
 			{0x02, WRITE_WITH_ADDR},	/* BYPR: Byte Program */
 			{0x03, READ_WITH_ADDR},		/* READ: Read Data */
@@ -1073,19 +1073,43 @@
 			{0x0b, READ_WITH_ADDR},		/* FAST: Fast Read */
 		}
 	};
+	struct intel_swseq_spi_config spi_config_aai_write = {
+		{0x06, 0x50}, /* OPPREFIXES: EWSR and WREN */
+		{ /* OPCODE and OPTYPE */
+			{0x01, WRITE_NO_ADDR},		/* WRSR: Write Status Register */
+			{0x02, WRITE_WITH_ADDR},	/* BYPR: Byte Program */
+			{0x03, READ_WITH_ADDR},		/* READ: Read Data */
+			{0x05, READ_NO_ADDR},		/* RDSR: Read Status Register */
+			{0x20, WRITE_WITH_ADDR},	/* SE20: Sector Erase 0x20 */
+			{0x9f, READ_NO_ADDR},		/* RDID: Read ID */
+			{0xad, WRITE_NO_ADDR},		/* Auto Address Increment Word Program */
+			{0x04, WRITE_NO_ADDR}		/* Write Disable */
+		}
+	};
+	const struct spi_flash *flash = boot_device_spi_flash();
+	struct intel_swseq_spi_config *spi_config = &spi_config_default;
 	int i;
 
+	/*
+	 * Some older SST SPI flashes support AAI write but use 0xaf opcde for
+	 * that. Flashrom uses the byte program opcode to write those flashes,
+	 * so this configuration is fine too. SST25VF064C (id = 0x4b) is an
+	 * exception.
+	 */
+	if (flash && flash->vendor == VENDOR_ID_SST && (flash->model & 0x00ff) != 0x4b)
+		spi_config = &spi_config_aai_write;
+
 	if (spi_locked())
 		return;
 
-	intel_southbridge_override_spi(&spi_config);
+	intel_southbridge_override_spi(spi_config);
 
-	spi_opprefix = spi_config.opprefixes[0]
-		| (spi_config.opprefixes[1] << 8);
+	spi_opprefix = spi_config->opprefixes[0]
+		| (spi_config->opprefixes[1] << 8);
 	writew_(spi_opprefix, cntlr->preop);
-	for (i = 0; i < ARRAY_SIZE(spi_config.ops); i++) {
-		optype |= (spi_config.ops[i].type & 3) << (i * 2);
-		writeb_(spi_config.ops[i].op, &cntlr->opmenu[i]);
+	for (i = 0; i < ARRAY_SIZE(spi_config->ops); i++) {
+		optype |= (spi_config->ops[i].type & 3) << (i * 2);
+		writeb_(spi_config->ops[i].op, &cntlr->opmenu[i]);
 	}
 	writew_(optype, cntlr->optype);
 }