diff --git a/src/soc/amd/common/block/spi/Kconfig b/src/soc/amd/common/block/spi/Kconfig index 88b118276c..085c02a2f6 100644 --- a/src/soc/amd/common/block/spi/Kconfig +++ b/src/soc/amd/common/block/spi/Kconfig @@ -16,11 +16,29 @@ config SOC_AMD_COMMON_BLOCK_SPI_4DW_BURST help Select this option to keep the 4 DWORD burst support enabled. +config SOC_AMD_COMMON_BLOCK_SPI_MMAP_USE_ROM3 + bool + default y if ROM_SIZE > 0x01000000 + depends on !SOC_AMD_PICASSO && !SOC_AMD_STONEYRIDGE + depends on !SOC_AMD_COMMON_BLOCK_LPC_SPI_DMA + depends on USE_X86_64_SUPPORT + # Enable X86_CUSTOM_BOOTMEDIA because the fast SPI controller + # driver provides a custom boot media device when multiple decode + # windows are used for the BIOS region. + select X86_CUSTOM_BOOTMEDIA + help + AMD specific SPI flash access. The lower 16MiB of the SPI flash are + memory mapped on the ROM2 window and the upper SPI flash is mapped using + the ROM3 window in high MMIO. The ROM3 window maps up to 64MiB of the + SPI flash. The default address of ROM3 is below 1024GiB address boundary + and thus can only be used in x86_64 mode. + config SOC_AMD_COMMON_BLOCK_SPI_MMAP def_bool y select X86_CUSTOM_BOOTMEDIA depends on SOC_AMD_COMMON_BLOCK_SPI depends on !SOC_AMD_COMMON_BLOCK_LPC_SPI_DMA + depends on !SOC_AMD_COMMON_BLOCK_SPI_MMAP_USE_ROM3 help This option is required when CONFIG_ROM_SIZE is greater than 16 MiB. This flash driver still only mmaps 16 MiB of the flash (depending diff --git a/src/soc/amd/common/block/spi/Makefile.mk b/src/soc/amd/common/block/spi/Makefile.mk index b80e204ec3..0dc78d9f3b 100644 --- a/src/soc/amd/common/block/spi/Makefile.mk +++ b/src/soc/amd/common/block/spi/Makefile.mk @@ -4,6 +4,9 @@ ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK_SPI),y) all_x86-$(CONFIG_SOC_AMD_COMMON_BLOCK_SPI_MMAP) += mmap_boot.c smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_SPI_MMAP) += mmap_boot.c +all-$(CONFIG_SOC_AMD_COMMON_BLOCK_SPI_MMAP_USE_ROM3) += mmap_boot_rom3.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_SPI_MMAP_USE_ROM3) += mmap_boot_rom3.c + bootblock-y += fch_spi_ctrl.c romstage-y += fch_spi_ctrl.c verstage-y += fch_spi_ctrl.c diff --git a/src/soc/amd/common/block/spi/mmap_boot_rom3.c b/src/soc/amd/common/block/spi/mmap_boot_rom3.c new file mode 100644 index 0000000000..bda3a4d92e --- /dev/null +++ b/src/soc/amd/common/block/spi/mmap_boot_rom3.c @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include + +enum window_type { + /* Fixed decode window of max 16MiB size just below 4G boundary */ + ROM2_DECODE_WINDOW, + /* Additional decode window for mapping BIOS region greater than 16MiB */ + ROM3_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(const size_t win_idx, const enum window_type type, + uintptr_t host_base, uintptr_t flash_base, size_t size) +{ + mem_region_device_ro_init(&shadow_devs[win_idx], (void *)host_base, size); + xlate_window_init(&real_dev_windows[win_idx], &shadow_devs[win_idx].rdev, + flash_base, size); + printk(BIOS_INFO, "ROM%d Decode Window: ", + (type == ROM2_DECODE_WINDOW) ? 2 : 3); + printk(BIOS_INFO, "SPI flash base=0x%lx, Host base=0x%lx, Size=0x%zx\n", + flash_base, host_base, size); +} + +/* + * + * Note: This configuration assumes no flash remapping (fch_spi_rom_remapping() = 0). + * + * +--------------+ + * | | + * | | + * | | + * CONFIG_ROM_SIZE +------------+--------------------------+--------------------------------+- rom3_end + * | | ^ | | + * | | | | ROM3 | + * | | | | | + * | | | | | + * | | + | | + * | | rom3_size | | + * | | + | | + * | SPI ROM | | | | + * | | +----+-----------------+--------------+ + * | | | | | | + * | | | | | | + * | | | V | | + * | | | +---0xfd00000000--+--------------+- rom3_start + * | | | | | + * | | | | | + * | | | | Other MMIO | + * | | | | | + * +------------+ --------------------+---------0x100000000--+--------------+- rom2_end + * | | ^ | | + * | | | | | + * | | rom2_size | ROM2 | + * | | | | | + * | | V | | + * 0 +------------+ ------------------------------0xFF0000000--+--------------+- rom2_start + * | | + * SPI flash | | + * address | | + * space | | + * +--------------+ + * + * Host address + * space + */ +static void bios_mmap_init(void) +{ + static bool init_done; + size_t win_count = 0; + size_t map_win_size = 0; + + if (init_done) + return; + + /* + * By default, fixed decode window (maximum size 16MiB) is mapped just + * below the 4G boundary. This window maps the bottom part of the BIOS + * region in the SPI flash address space to the host address space. + */ + size_t rom2_size = 0; + const uintptr_t rom2_start = lpc_get_rom2_region(&rom2_size); + if (rom2_start && rom2_size) { + initialize_window(win_count, ROM2_DECODE_WINDOW, rom2_start, 0, rom2_size); + win_count++; + map_win_size += rom2_size; + } + + /* + * Remaining portion of the BIOS region up to a maximum of 64MiB is + * mapped at the bottom of the ROM3 if the BIOS region is greater than 16MiB. + * The ROM3 window is only used when it's inside the identity mapped + * page tables used by x86_64. + * + * If the BIOS region is not greater than 16MiB, then the ROM3 window is not + * enabled. + */ + size_t rom3_size; + const uint64_t rom3_start = lpc_get_rom3_region(&rom3_size); + const uint64_t rom3_end = rom3_start + rom3_size; + + if (CONFIG_ROM_SIZE > 16 * MiB) { + assert(rom3_start); + assert(rom3_size > 16 * MiB); + assert(DIV_ROUND_UP(rom3_end, GiB) < CONFIG_CPU_PT_ROM_MAP_GB); + } + + if (CONFIG_ROM_SIZE > 16 * MiB && + rom3_start > 0 && + rom3_size > 16 * MiB && + DIV_ROUND_UP(rom3_end, GiB) < CONFIG_CPU_PT_ROM_MAP_GB) { + + const size_t ext_win_size = MIN(rom3_size, CONFIG_ROM_SIZE - rom2_size); + + initialize_window(win_count, ROM3_DECODE_WINDOW, + rom3_start + rom2_size, rom2_size, ext_win_size); + win_count++; + map_win_size += ext_win_size; + } + + assert(map_win_size == CONFIG_ROM_SIZE); + xlate_region_device_ro_init(&real_dev, win_count, real_dev_windows, map_win_size); + + init_done = true; +} + +const struct region_device *boot_device_ro(void) +{ + bios_mmap_init(); + + return &real_dev.rdev; +} + +uint32_t spi_flash_get_mmap_windows(struct flash_mmap_window *table) +{ + int i; + uint32_t count = 0; + + bios_mmap_init(); + + for (i = 0; i < TOTAL_DECODE_WINDOWS; i++) { + if (region_sz(&real_dev_windows[i].sub_region) == 0) + continue; + + count++; + table->flash_base = region_offset(&real_dev_windows[i].sub_region); + /* FIXME: Allow SPI mmap in 64-bit address space */ + if ((uintptr_t)rdev_mmap_full(&shadow_devs[i].rdev) < 4ULL * GiB) + table->host_base = (uintptr_t)rdev_mmap_full(&shadow_devs[i].rdev); + table->size = region_sz(&real_dev_windows[i].sub_region); + + table++; + } + + return count; +} diff --git a/src/soc/amd/glinda/Kconfig b/src/soc/amd/glinda/Kconfig index cfee669184..868a984bcc 100644 --- a/src/soc/amd/glinda/Kconfig +++ b/src/soc/amd/glinda/Kconfig @@ -101,6 +101,9 @@ config CHIPSET_DEVICETREE string default "soc/amd/glinda/chipset.cb" +config CPU_PT_ROM_MAP_GB + default 1024 + config EARLY_RESERVED_DRAM_BASE hex default 0x2000000