summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/common/block/fast_spi/Kconfig45
-rw-r--r--src/soc/intel/common/block/fast_spi/Makefile.inc32
-rw-r--r--src/soc/intel/common/block/fast_spi/mmap_boot.c162
-rw-r--r--src/soc/intel/common/block/include/intelblocks/fast_spi.h7
4 files changed, 246 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/fast_spi/Kconfig b/src/soc/intel/common/block/fast_spi/Kconfig
index 936927219d..eb2373ca8b 100644
--- a/src/soc/intel/common/block/fast_spi/Kconfig
+++ b/src/soc/intel/common/block/fast_spi/Kconfig
@@ -11,3 +11,48 @@ config FAST_SPI_DISABLE_WRITE_STATUS
default y
help
Disable the write status SPI opcode in Intel Fast SPI block.
+
+config FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW
+ bool
+ depends on SOC_INTEL_COMMON_BLOCK_FAST_SPI
+ help
+ Fast SPI controller on the platform supports additional
+ window for memory mapping BIOS region (region 1) on the SPI
+ flash beyond the standard limit of 16MiB. Depending upon the
+ size of the SPI flash part used by the mainboard, two decode
+ windows will be enabled:
+ 1. Fixed decode window up to a maximum size of 16MiB under
+ 4G boundary.
+ 2. Extended decode window up to a maximum size provided by
+ the platform to map the rest of the BIOS region.
+ SoC selecting this config is expected to provide the base and
+ maximum size of the extended window in the host address space
+ using configs EXT_BIOS_WIN_BASE and EXT_BIOS_WIN_SIZE.
+
+config EXT_BIOS_WIN_BASE
+ hex
+ help
+ If an additional window for mapping BIOS region greater than
+ 16MiB is supported, then this config is used to provide the
+ base address reserved for the mapping. Since the mapping is
+ done at the top of the window, depending upon the size of the
+ BIOS region, the actual base address configured in the fast
+ SPI controller can be higher at runtime.
+
+config EXT_BIOS_WIN_SIZE
+ hex
+ help
+ Maximum size of the extended window reserved for mapping BIOS
+ region greater than 16MiB. The actual mapped window might be
+ smaller depending upon the size of the BIOS region.
+
+if FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW
+
+# Disable X86_TOP4G_BOOTMEDIA_MAP because the fast SPI controller
+# driver provides a custom boot media device when multiple decode
+# windows are used for the BIOS region.
+
+config X86_TOP4G_BOOTMEDIA_MAP
+ default n
+
+endif
diff --git a/src/soc/intel/common/block/fast_spi/Makefile.inc b/src/soc/intel/common/block/fast_spi/Makefile.inc
index e5b50aa0bf..79a2f97563 100644
--- a/src/soc/intel/common/block/fast_spi/Makefile.inc
+++ b/src/soc/intel/common/block/fast_spi/Makefile.inc
@@ -19,3 +19,35 @@ smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_FAST_SPI) += fast_spi_flash.c
endif
CPPFLAGS_common += -I$(src)/soc/intel/common/block/fast_spi
+
+ifeq ($(CONFIG_FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW),y)
+
+# mmap_boot.c provides a custom boot media device for the platforms that support
+# additional window for BIOS regions greater than 16MiB. This is used instead of
+# the default boot media device in arch/x86/mmap_boot.c
+bootblock-y += mmap_boot.c
+verstage-y += mmap_boot.c
+romstage-y += mmap_boot.c
+postcar-y += mmap_boot.c
+ramstage-y += mmap_boot.c
+smm-y += mmap_boot.c
+
+# Check to ensure that no sections in the FMAP cross 16MiB boundary if
+# the platform supports split decode windows for BIOS region greater
+# than 16MiB.
+check-fmap-16mib-crossing: $(obj)/fmap_config.h
+ flash_offset=$$(printf "%d" $$(cat $(obj)/fmap_config.h | grep "FMAP_SECTION_FLASH_START" | awk '{print $$NF}')); \
+ for x in $$(cat $(obj)/fmap_config.h | grep "FMAP_TERMINAL_SECTIONS" | cut -d\" -f2); do \
+ start=$$(printf "%d" $$(cat $(obj)/fmap_config.h | grep "FMAP_SECTION_"$$x"_START" | awk '{print $$NF}')); \
+ size=$$(printf "%d" $$(cat $(obj)/fmap_config.h | grep "FMAP_SECTION_"$$x"_SIZE" | awk '{print $$NF}')); \
+ start=$$((start-flash_offset)); \
+ end=$$((start+size-1)); \
+ if [ $$start -lt 16777216 ] && [ $$end -ge 16777216 ]; then echo "ERROR:" $$x "crosses 16MiB boundary"; fail=1; break; fi; \
+ done; \
+ if [ $$fail -eq 1 ]; then false; fi
+
+INTERMEDIATE+=check-fmap-16mib-crossing
+
+CBFSTOOL_ADD_CMD_OPTIONS += --ext-win-base $(CONFIG_EXT_BIOS_WIN_BASE) --ext-win-size $(CONFIG_EXT_BIOS_WIN_SIZE)
+
+endif # CONFIG_FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW
diff --git a/src/soc/intel/common/block/fast_spi/mmap_boot.c b/src/soc/intel/common/block/fast_spi/mmap_boot.c
new file mode 100644
index 0000000000..8435a855f5
--- /dev/null
+++ b/src/soc/intel/common/block/fast_spi/mmap_boot.c
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * This file provides a custom boot media device for the platforms that support additional
+ * window for BIOS regions greater than 16MiB. If the mainboard uses a smaller BIOS region, then
+ * the additional window is unused.
+ */
+
+#include <boot_device.h>
+#include <commonlib/region.h>
+#include <console/console.h>
+#include <fmap.h>
+#include <intelblocks/fast_spi.h>
+
+enum window_type {
+ /* Fixed decode window of max 16MiB size just below 4G boundary */
+ FIXED_DECODE_WINDOW,
+ /* Additional decode window for mapping BIOS region greater than 16MiB */
+ EXT_BIOS_DECODE_WINDOW,
+ TOTAL_DECODE_WINDOWS,
+};
+
+static struct xlate_region_device real_dev;
+static struct mem_region_device shadow_devs[TOTAL_DECODE_WINDOWS];
+static struct xlate_window real_dev_windows[TOTAL_DECODE_WINDOWS];
+
+static void initialize_window(enum window_type type, uintptr_t host_base,
+ uintptr_t flash_base, size_t size)
+{
+ mem_region_device_ro_init(&shadow_devs[type], (void *)host_base, size);
+ xlate_window_init(&real_dev_windows[type], &shadow_devs[type].rdev,
+ flash_base, size);
+ printk(BIOS_INFO, "MMAP window: SPI flash base=0x%lx, Host base=0x%lx, Size=0x%zx\n",
+ flash_base, host_base, size);
+}
+
+/*
+ *
+ * +--------------+
+ * | |
+ * | |
+ * | |
+ * ^ +------------+--------------------------^--------------------------------+ 0xffffffff
+ * | | | | | |
+ * | | | | | |
+ * | | | + | FIXED |
+ * | | | fixed_win_size | DECODE |
+ * | | BIOS | + | WINDOW |
+ * + | region | | | |
+ * bios_size | (Region 1) | | | |
+ * + | | | | |
+ * | | | | | |
+ * | | | fixed_win_flash_base+----v--------------------------------+ fixed_win_host_base
+ * | | | | | |
+ * | | | | | |
+ * | | | | | Other MMIO |
+ * v | | | | |
+ * bios_start +------------+ ext_win_flash_base | | |
+ * | | + | | |
+ * | | | | | |
+ * | | | | | |
+ * | | | +-----^------------------------------------------------------------^
+ * 0 +------------+ | | | | |
+ * | + | EXT_BIOS | |
+ * SPI flash | ext_win_size | DECODE | |
+ * address | + | WINDOW | +
+ * space | | | | CONFIG_EXT_BIOS_WIN_SIZE
+ * +--------------v-------------------------------+ ext_win_host_base +
+ * | | |
+ * | Unused | |
+ * | | |
+ * +--------------+ CONFIG_EXT_BIOS_WIN_BASE+--v
+ * | |
+ * | |
+ * | |
+ * +--------------+
+ *
+ * Host address
+ * space
+ */
+static void bios_mmap_init(void)
+{
+ static bool init_done;
+
+ size_t bios_size, bios_start;
+
+ uintptr_t fixed_win_host_base, fixed_win_flash_base;
+ uintptr_t ext_win_host_base, ext_win_flash_base;
+ size_t fixed_win_size, ext_win_size;
+
+ size_t win_count = 0;
+
+ if (init_done)
+ return;
+
+ /* Read the offset and size of BIOS region in the SPI flash address space. */
+ bios_start = fast_spi_get_bios_region(&bios_size);
+
+ /*
+ * By default, fixed decode window (maximum size 16MiB) is mapped just below the 4G
+ * boundary. This window maps the top part of the BIOS region in the SPI flash address
+ * space to the host address space.
+ */
+ fixed_win_size = MIN(16 * MiB, bios_size);
+ fixed_win_host_base = 4ULL * GiB - fixed_win_size;
+ fixed_win_flash_base = bios_start + bios_size - fixed_win_size;
+
+ initialize_window(FIXED_DECODE_WINDOW, fixed_win_host_base, fixed_win_flash_base,
+ fixed_win_size);
+ win_count++;
+
+ _Static_assert(CONFIG_EXT_BIOS_WIN_BASE != 0, "Extended BIOS window base cannot be 0!");
+ _Static_assert(CONFIG_EXT_BIOS_WIN_SIZE != 0, "Extended BIOS window size cannot be 0!");
+
+ /*
+ * Remaining portion of the BIOS region up to a maximum of CONFIG_EXT_BIOS_WIN_SIZE is
+ * mapped at the top of the extended window if the BIOS region is greater than 16MiB.
+ *
+ * If the BIOS region is not greater than 16MiB, then the extended window is not
+ * enabled.
+ */
+ ext_win_size = MIN(CONFIG_EXT_BIOS_WIN_SIZE, bios_size - fixed_win_size);
+
+ if (ext_win_size) {
+ ext_win_host_base = CONFIG_EXT_BIOS_WIN_BASE + CONFIG_EXT_BIOS_WIN_SIZE -
+ ext_win_size;
+ ext_win_flash_base = fixed_win_flash_base - ext_win_size;
+ initialize_window(EXT_BIOS_DECODE_WINDOW, ext_win_host_base,
+ ext_win_flash_base, ext_win_size);
+ win_count++;
+ }
+
+ xlate_region_device_ro_init(&real_dev, win_count, real_dev_windows, CONFIG_ROM_SIZE);
+
+ init_done = true;
+}
+
+const struct region_device *boot_device_ro(void)
+{
+ bios_mmap_init();
+
+ return &real_dev.rdev;
+}
+
+void fast_spi_get_ext_bios_window(uintptr_t *base, size_t *size)
+{
+ const struct region_device *rd = &shadow_devs[EXT_BIOS_DECODE_WINDOW].rdev;
+
+ bios_mmap_init();
+
+ *size = region_device_sz(rd);
+
+ if (*size == 0) {
+ *base = 0;
+ } else {
+ /*
+ * This is a memory region device. So, mmap returns the base address of the
+ * device. Also, as this is a memory region device, unmap is a no-op.
+ */
+ *base = (uintptr_t)rdev_mmap_full(rd);
+ }
+}
diff --git a/src/soc/intel/common/block/include/intelblocks/fast_spi.h b/src/soc/intel/common/block/include/intelblocks/fast_spi.h
index 52ffdb319d..0a7e64dad4 100644
--- a/src/soc/intel/common/block/include/intelblocks/fast_spi.h
+++ b/src/soc/intel/common/block/include/intelblocks/fast_spi.h
@@ -74,4 +74,11 @@ bool fast_spi_wpd_status(void);
*/
void fast_spi_enable_wp(void);
+/*
+ * Get base and size of extended BIOS decode window used at runtime in host address space. If
+ * the BIOS region is not greater than 16MiB, then this function returns 0 for both base and
+ * size.
+ */
+void fast_spi_get_ext_bios_window(uintptr_t *base, size_t *size);
+
#endif /* SOC_INTEL_COMMON_BLOCK_FAST_SPI_H */