From cbbf380fa4699882dfc28556ca571f36dcfae775 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Sat, 22 Feb 2025 15:09:00 +0100 Subject: [PATCH] soc/amd/common/block/lpc: Use ROM3 window if possible On x86_64 use the ROM3 window to access the SPI flash. Use the same mechanism as on Intel, where the lower 16Mbyte are mapped using ROM2 window and the upper pages are mapped using the ROM3 window. By default the ROM3 window resides in high MMIO and thus needs 1024GiB of the address space to be identity mapped in the page tables. This allows legacy 32-bit code to work on mappings in the lower 16MiB of the flash chip. Introduces new messages in coreboot log: [INFO ] ROM2 Decode Window: SPI flash base=0x0, Host base=0xff000000, Size=0x1000000 [INFO ] ROM3 Decode Window: SPI flash base=0x1000000, Host base=0xfd01000000, Size=0x3000000 TEST: Disabled ROM2 mapping and booted from ROM3 mapping in x86_64 on amd/birman+. Change-Id: I8976273cfb31765d7f893b3fc137f117c63b6553 Signed-off-by: Patrick Rudolph Reviewed-on: https://review.coreboot.org/c/coreboot/+/86584 Tested-by: build bot (Jenkins) Reviewed-by: Naresh --- src/soc/amd/common/block/spi/Kconfig | 18 ++ src/soc/amd/common/block/spi/Makefile.mk | 3 + src/soc/amd/common/block/spi/mmap_boot_rom3.c | 163 ++++++++++++++++++ src/soc/amd/glinda/Kconfig | 3 + 4 files changed, 187 insertions(+) create mode 100644 src/soc/amd/common/block/spi/mmap_boot_rom3.c 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