aboutsummaryrefslogtreecommitdiff
path: root/src/soc/intel/common/block/fast_spi/mmap_boot.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel/common/block/fast_spi/mmap_boot.c')
-rw-r--r--src/soc/intel/common/block/fast_spi/mmap_boot.c162
1 files changed, 162 insertions, 0 deletions
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);
+ }
+}