diff options
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.c | 162 |
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); + } +} |