soc/amd: rework SPI flash MMIO region handling

Only 16 MByte of the SPI flash can be mapped right below the 4 GB
boundary.

In case of a larger SPI flash size, still only the 16 MByte region
starting at 0xff000000 can be configured as WRPROT and be reserved for
the MMIO mapped SPI flash region. The next 16 MByte MMIO region starting
at address 0xfe000000 contain for example the LAPIC MMIO region, the
ACPIMMIO region and the UART/I2C controller MMIO regions which shouldn't
be configured as WRPROT. Reserving this region for the MMIO mapped SPI
flash would also result in an overlap with the MMIO resources mentioned
above.

In the case of a smaller SPI flash, reserving the full 16 MByte flash
MMIO region makes sure that the resource allocator won't try to put
anything else in the lower parts of the 16 MByte SPI mapping region.

To avoid the issues described above, always reserve/cache the maximum
amount of 16 MBytes of flash that can be mapped below 4 GB.

TEST=On boards with 16 MByte SPI flash chips, the resulting image of a
timeless build doesn't change with this patch. Verified this on Chausie
(Mendocino), Majolica (Cezanne), Cereme (Picasso) and Google/Careena
(Stoneyridge). On Mandolin (Picasso) with an 8 MByte flash, the
resulting image of a timeless build is different, but neither the
coreboot console output nor the Linux dmesg output shows any errors that
might be related to this change.

Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Change-Id: Ie12bd48e48e267a84dc494f67e8e0c7a4a01a320
Reviewed-on: https://review.coreboot.org/c/coreboot/+/66700
Reviewed-by: Martin Roth <martin.roth@amd.corp-partner.google.com>
Reviewed-by: Raul Rangel <rrangel@chromium.org>
Reviewed-by: Fred Reitberger <reitbergerfred@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/soc/amd/cezanne/cpu.c b/src/soc/amd/cezanne/cpu.c
index a22b369..8b4e347 100644
--- a/src/soc/amd/cezanne/cpu.c
+++ b/src/soc/amd/cezanne/cpu.c
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <amdblocks/cpu.h>
+#include <amdblocks/iomap.h>
 #include <amdblocks/mca.h>
 #include <amdblocks/reset.h>
 #include <amdblocks/smm.h>
@@ -55,7 +56,8 @@
 				"mp_init_with_smm failed. Halting.\n");
 
 	/* pre_mp_init made the flash not cacheable. Reset to WP for performance. */
-	mtrr_use_temp_range(FLASH_BASE_ADDR, CONFIG_ROM_SIZE, MTRR_TYPE_WRPROT);
+	mtrr_use_temp_range(FLASH_BELOW_4GB_MAPPING_REGION_BASE,
+			    FLASH_BELOW_4GB_MAPPING_REGION_SIZE, MTRR_TYPE_WRPROT);
 
 	/* SMMINFO only needs to be set up when booting from S5 */
 	if (!acpi_is_wakeup_s3())
diff --git a/src/soc/amd/common/block/cpu/noncar/early_cache.c b/src/soc/amd/common/block/cpu/noncar/early_cache.c
index d8684ee..4bba172 100644
--- a/src/soc/amd/common/block/cpu/noncar/early_cache.c
+++ b/src/soc/amd/common/block/cpu/noncar/early_cache.c
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <amdblocks/cpu.h>
+#include <amdblocks/iomap.h>
 #include <assert.h>
 #include <cpu/amd/mtrr.h>
 #include <cpu/x86/cache.h>
@@ -61,8 +62,9 @@
 	wrmsr(SYSCFG_MSR, sys_cfg);
 
 	var_mtrr_set(&mtrr_ctx.ctx, 0, ALIGN_DOWN(top_mem.lo, 8 * MiB), MTRR_TYPE_WRBACK);
-	/* TODO: check if we should always mark 16 MByte below 4 GByte as WRPROT */
-	var_mtrr_set(&mtrr_ctx.ctx, FLASH_BASE_ADDR, CONFIG_ROM_SIZE, MTRR_TYPE_WRPROT);
+	/* Always mark the 16 MByte right below the 4 GB boundary as WRPROT */
+	var_mtrr_set(&mtrr_ctx.ctx, FLASH_BELOW_4GB_MAPPING_REGION_BASE,
+		     FLASH_BELOW_4GB_MAPPING_REGION_SIZE, MTRR_TYPE_WRPROT);
 
 	commit_mtrr_setup(&mtrr_ctx.ctx);
 
diff --git a/src/soc/amd/common/block/include/amdblocks/iomap.h b/src/soc/amd/common/block/include/amdblocks/iomap.h
new file mode 100644
index 0000000..759466b
--- /dev/null
+++ b/src/soc/amd/common/block/include/amdblocks/iomap.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef AMD_BLOCK_IOMAP_H
+#define AMD_BLOCK_IOMAP_H
+
+/*
+ * A maximum of 16 MBytes of the SPI flash can be mapped right below the 4 GB boundary. For
+ * region reservation and cacheability configuration purposes, we can use this maximum value
+ * and don't need to make this dependent on the flash size. This also makes sure that in case
+ * of flash sizes above 16 MByte the MMIO region right below won't get configured wrongly.
+ */
+#define FLASH_BELOW_4GB_MAPPING_REGION_BASE	((0xffffffff - 16 * MiB) + 1)
+#define FLASH_BELOW_4GB_MAPPING_REGION_SIZE	(16 * MiB)
+
+#endif /* AMD_BLOCK_IOMAP_H */
diff --git a/src/soc/amd/common/block/lpc/lpc.c b/src/soc/amd/common/block/lpc/lpc.c
index c02f297..3d1b2d4 100644
--- a/src/soc/amd/common/block/lpc/lpc.c
+++ b/src/soc/amd/common/block/lpc/lpc.c
@@ -16,6 +16,7 @@
 #include <amdblocks/acpimmio.h>
 #include <amdblocks/espi.h>
 #include <amdblocks/ioapic.h>
+#include <amdblocks/iomap.h>
 #include <amdblocks/lpc.h>
 #include <soc/iomap.h>
 #include <soc/lpc.h>
@@ -109,9 +110,10 @@
 	res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
 		     IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
 
+	/* Only up to 16 MByte of the SPI flash can be mapped right below 4 GB */
 	res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
-	res->base = FLASH_BASE_ADDR;
-	res->size = CONFIG_ROM_SIZE;
+	res->base = FLASH_BELOW_4GB_MAPPING_REGION_BASE;
+	res->size = FLASH_BELOW_4GB_MAPPING_REGION_SIZE;
 	res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
 		     IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
 
diff --git a/src/soc/amd/mendocino/cpu.c b/src/soc/amd/mendocino/cpu.c
index 0867595..a0aa05c 100644
--- a/src/soc/amd/mendocino/cpu.c
+++ b/src/soc/amd/mendocino/cpu.c
@@ -4,6 +4,7 @@
 
 #include <acpi/acpi.h>
 #include <amdblocks/cpu.h>
+#include <amdblocks/iomap.h>
 #include <amdblocks/mca.h>
 #include <amdblocks/reset.h>
 #include <amdblocks/smm.h>
@@ -58,7 +59,8 @@
 				"mp_init_with_smm failed. Halting.\n");
 
 	/* pre_mp_init made the flash not cacheable. Reset to WP for performance. */
-	mtrr_use_temp_range(FLASH_BASE_ADDR, CONFIG_ROM_SIZE, MTRR_TYPE_WRPROT);
+	mtrr_use_temp_range(FLASH_BELOW_4GB_MAPPING_REGION_BASE,
+			    FLASH_BELOW_4GB_MAPPING_REGION_SIZE, MTRR_TYPE_WRPROT);
 
 	/* SMMINFO only needs to be set up when booting from S5 */
 	if (!acpi_is_wakeup_s3())
diff --git a/src/soc/amd/picasso/cpu.c b/src/soc/amd/picasso/cpu.c
index c7931a1..08447e9 100644
--- a/src/soc/amd/picasso/cpu.c
+++ b/src/soc/amd/picasso/cpu.c
@@ -2,6 +2,7 @@
 
 #include <acpi/acpi.h>
 #include <amdblocks/cpu.h>
+#include <amdblocks/iomap.h>
 #include <amdblocks/mca.h>
 #include <amdblocks/reset.h>
 #include <amdblocks/smm.h>
@@ -59,7 +60,8 @@
 				"mp_init_with_smm failed. Halting.\n");
 
 	/* pre_mp_init made the flash not cacheable. Reset to WP for performance. */
-	mtrr_use_temp_range(FLASH_BASE_ADDR, CONFIG_ROM_SIZE, MTRR_TYPE_WRPROT);
+	mtrr_use_temp_range(FLASH_BELOW_4GB_MAPPING_REGION_BASE,
+			    FLASH_BELOW_4GB_MAPPING_REGION_SIZE, MTRR_TYPE_WRPROT);
 
 	/* SMMINFO only needs to be set up when booting from S5 */
 	if (!acpi_is_wakeup_s3())
diff --git a/src/soc/amd/stoneyridge/bootblock.c b/src/soc/amd/stoneyridge/bootblock.c
index 8ada723..0a67d9b 100644
--- a/src/soc/amd/stoneyridge/bootblock.c
+++ b/src/soc/amd/stoneyridge/bootblock.c
@@ -12,6 +12,7 @@
 #include <amdblocks/agesawrapper_call.h>
 #include <amdblocks/amd_pci_mmconf.h>
 #include <amdblocks/biosram.h>
+#include <amdblocks/iomap.h>
 #include <soc/pci_devs.h>
 #include <soc/cpu.h>
 #include <soc/southbridge.h>
@@ -42,7 +43,8 @@
 	 *       duplicate copies.
 	 */
 	mtrr = (mtrr_cap.lo & MTRR_CAP_VCNT) - SOC_EARLY_VMTRR_FLASH;
-	set_var_mtrr(mtrr, FLASH_BASE_ADDR, CONFIG_ROM_SIZE, MTRR_TYPE_WRPROT);
+	set_var_mtrr(mtrr, FLASH_BELOW_4GB_MAPPING_REGION_BASE,
+		     FLASH_BELOW_4GB_MAPPING_REGION_SIZE, MTRR_TYPE_WRPROT);
 
 	mtrr = (mtrr_cap.lo & MTRR_CAP_VCNT) - SOC_EARLY_VMTRR_CAR_HEAP;
 	set_var_mtrr(mtrr, CONFIG_PI_AGESA_CAR_HEAP_BASE,
diff --git a/src/soc/amd/stoneyridge/cpu.c b/src/soc/amd/stoneyridge/cpu.c
index 94beed8..7f71703 100644
--- a/src/soc/amd/stoneyridge/cpu.c
+++ b/src/soc/amd/stoneyridge/cpu.c
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
+#include <amdblocks/iomap.h>
 #include <amdblocks/mca.h>
 #include <amdblocks/reset.h>
 #include <amdblocks/smm.h>
@@ -61,7 +62,8 @@
 				"mp_init_with_smm failed. Halting.\n");
 
 	/* The flash is now no longer cacheable. Reset to WP for performance. */
-	mtrr_use_temp_range(FLASH_BASE_ADDR, CONFIG_ROM_SIZE, MTRR_TYPE_WRPROT);
+	mtrr_use_temp_range(FLASH_BELOW_4GB_MAPPING_REGION_BASE,
+			    FLASH_BELOW_4GB_MAPPING_REGION_SIZE, MTRR_TYPE_WRPROT);
 
 	set_warm_reset_flag();
 }
diff --git a/src/soc/amd/stoneyridge/include/soc/iomap.h b/src/soc/amd/stoneyridge/include/soc/iomap.h
index ddaea1d..31cd12b 100644
--- a/src/soc/amd/stoneyridge/include/soc/iomap.h
+++ b/src/soc/amd/stoneyridge/include/soc/iomap.h
@@ -19,8 +19,6 @@
 #define APU_UART0_BASE			0xfedc6000
 #define APU_UART1_BASE			0xfedc8000
 
-#define FLASH_BASE_ADDR			((0xffffffff - CONFIG_ROM_SIZE) + 1)
-
 /* I/O Ranges */
 #define ACPI_IO_BASE			0x400
 #define  ACPI_PM_EVT_BLK		(ACPI_IO_BASE + 0x00)		/* 4 bytes */