Attention is currently required from: Felix Held, Fred Reitberger, Jason Glenesk, Matt DeVillier.
Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/86584?usp=email )
Change subject: soc/amd/common/block/lpc: Use ROM3 window if possible ......................................................................
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.
TEST: Disabled ROM2 mapping and booted from ROM3 mapping in x86_64 on amd/birman+.
Change-Id: I8976273cfb31765d7f893b3fc137f117c63b6553 Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/soc/amd/common/block/lpc/Kconfig M src/soc/amd/common/block/lpc/Makefile.mk A src/soc/amd/common/block/lpc/mmap_boot_rom3.c M src/soc/amd/glinda/Kconfig 4 files changed, 186 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/86584/1
diff --git a/src/soc/amd/common/block/lpc/Kconfig b/src/soc/amd/common/block/lpc/Kconfig index 9f41f22..2e10679 100644 --- a/src/soc/amd/common/block/lpc/Kconfig +++ b/src/soc/amd/common/block/lpc/Kconfig @@ -65,3 +65,20 @@ SMU will lock up at times if the port80h enable bit is cleared. Select this option to retain the port80 enable bit while clearing other enable bits in the ESPI Decode register. + + +config SOC_AMD_COMMON_BLOCK_LPC_USE_ROM3 + bool + default y if !SOC_AMD_COMMON_BLOCK_LPC_SPI_DMA && 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. diff --git a/src/soc/amd/common/block/lpc/Makefile.mk b/src/soc/amd/common/block/lpc/Makefile.mk index 11de514..60b4059 100644 --- a/src/soc/amd/common/block/lpc/Makefile.mk +++ b/src/soc/amd/common/block/lpc/Makefile.mk @@ -14,3 +14,8 @@ endif # CONFIG_SOC_AMD_COMMON_BLOCK_LPC_SPI_DMA
all-$(CONFIG_SOC_AMD_COMMON_BLOCK_USE_ESPI) += espi_util.c + +ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK_LPC_USE_ROM3),y) +all_x86-y += mmap_boot_rom3.c +smm-y += mmap_boot_rom3.c +endif # CONFIG_SOC_AMD_COMMON_BLOCK_LPC_USE_ROM3 diff --git a/src/soc/amd/common/block/lpc/mmap_boot_rom3.c b/src/soc/amd/common/block/lpc/mmap_boot_rom3.c new file mode 100644 index 0000000..cecef1d --- /dev/null +++ b/src/soc/amd/common/block/lpc/mmap_boot_rom3.c @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <boot_device.h> +#include <spi_flash.h> +#include <stdint.h> +#include <amdblocks/lpc.h> + +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); +} + +/* + * + * +--------------+ + * | | + * | | + * | | + * 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 (CONFIG_CPU_PT_ROM_MAP_GB >= DIV_ROUND_UP(rom3_end, GiB)); + } + + if (CONFIG_ROM_SIZE > 16 * MiB && + rom3_start > 0 && + rom3_size > 16 * MiB && + CONFIG_CPU_PT_ROM_MAP_GB >= DIV_ROUND_UP(rom3_end, GiB)) { + + 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 70bdb69..1f1afec 100644 --- a/src/soc/amd/glinda/Kconfig +++ b/src/soc/amd/glinda/Kconfig @@ -100,6 +100,9 @@ string default "soc/amd/glinda/chipset.cb"
+config CPU_PT_ROM_MAP_GB + default 1024 + config EARLY_RESERVED_DRAM_BASE hex default 0x2000000