amd_spi100: Implement memory-mapped reads

Query the RomRange2 register for the memory range (usually top below 4G)
and try to map that. Reads outside this range will still be served via
the command engine.

Change-Id: I21aa67d550ccda0f55a9cf3ff14545a881624d11
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/72583
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/amd_spi100.c b/amd_spi100.c
index 39b293f..d0d2f28 100644
--- a/amd_spi100.c
+++ b/amd_spi100.c
@@ -25,6 +25,9 @@
 
 struct spi100 {
 	uint8_t *spibar;
+	uint8_t *memory;
+	size_t mapped_len;
+
 	unsigned int altspeed;
 };
 
@@ -123,6 +126,27 @@
 	return 0;
 }
 
+static int spi100_read(struct flashctx *const flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+	const struct spi100 *const spi100 = flash->mst->spi.data;
+
+	/* Use SPI100 engine for data outside the memory-mapped range */
+	const chipoff_t from_top = flashrom_flash_getsize(flash) - start;
+	if (from_top > spi100->mapped_len) {
+		const chipsize_t unmapped_len = MIN(len, from_top - spi100->mapped_len);
+		const int ret = default_spi_read(flash, buf, start, unmapped_len);
+		if (ret)
+			return ret;
+		start += unmapped_len;
+		buf += unmapped_len;
+		len -= unmapped_len;
+	}
+
+	mmio_readn_aligned(spi100->memory + start, buf, len, 8);
+
+	return 0;
+}
+
 static int spi100_shutdown(void *data)
 {
 	struct spi100 *const spi100 = data;
@@ -139,7 +163,7 @@
 	.max_data_write	= SPI100_FIFO_SIZE - 4,
 	.command	= spi100_send_command,
 	.multicommand	= default_spi_send_multicommand,
-	.read		= default_spi_read,
+	.read		= spi100_read,
 	.write_256	= default_spi_write_256,
 	.probe_opcode	= default_spi_probe_opcode,
 	.shutdown	= spi100_shutdown,
@@ -215,7 +239,7 @@
 	}
 }
 
-int amd_spi100_probe(void *const spibar)
+int amd_spi100_probe(void *const spibar, void *const memory_mapping, const size_t mapped_len)
 {
 	struct spi100 *const spi100 = malloc(sizeof(*spi100));
 	if (!spi100) {
@@ -223,6 +247,8 @@
 		return ERROR_FATAL;
 	}
 	spi100->spibar = spibar;
+	spi100->memory = memory_mapping;
+	spi100->mapped_len = mapped_len;
 
 	spi100_print(spi100);
 
diff --git a/chipset_enable.c b/chipset_enable.c
index 7728cb9..8210a9c 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -1435,6 +1435,13 @@
 		return ERROR_FATAL;
 	}
 
+	/* RomRange2 is supposed to be used for the mapping directly below 4G. */
+	const uint32_t rom_range2 = pci_read_long(lpc, 0x6c);
+	const uint32_t rom_range_end = rom_range2 | 0xffff;
+	const uint32_t rom_range_start = (rom_range2 & 0xffff) << 16;
+	const size_t mapped_len = rom_range_end > rom_range_start ? rom_range_end - rom_range_start + 1 : 0;
+	msg_pdbg("ROM Range 2: 0x%08x..0x%08x (%zu kB)\n", rom_range_start, rom_range_end, mapped_len / KiB);
+
 	const uint32_t spibar = pci_read_long(lpc, 0xa0);
 	msg_pdbg("AltSpiCSEnable=%u, SpiRomEnable=%u", spibar >> 0 & 1, spibar >> 1 & 1);
 	msg_pdbg(", AbortEnable=%u, RouteTpm2Spi=%u", spibar >> 2 & 1, spibar >> 3 & 1);
@@ -1460,7 +1467,14 @@
 	if (virt_spibar == ERROR_PTR)
 		return ERROR_FATAL;
 
-	return amd_spi100_probe(virt_spibar);
+	void *memory_mapping = NULL;
+	if (spirom_enable && mapped_len) {
+		memory_mapping = rphysmap("SPI100 memory mapping", rom_range_start, mapped_len);
+		if (memory_mapping == ERROR_PTR)
+			memory_mapping = NULL;
+	}
+
+	return amd_spi100_probe(virt_spibar, memory_mapping, memory_mapping ? mapped_len : 0);
 }
 
 /* sets bit 0 in 0x6d */
diff --git a/include/programmer.h b/include/programmer.h
index 9f33e23..64e01f8 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -364,7 +364,7 @@
 int amd_imc_shutdown(struct pci_dev *dev);
 
 /* amd_spi100.c */
-int amd_spi100_probe(void *const spibar);
+int amd_spi100_probe(void *const spibar, void *const memory_mapping, const size_t mapped_len);
 
 /* it87spi.c */
 void enter_conf_mode_ite(uint16_t port);