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 <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/86584
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Naresh <naresh.solanki.2011@gmail.com>
This commit is contained in:
Patrick Rudolph 2025-02-22 15:09:00 +01:00 committed by Matt DeVillier
commit cbbf380fa4
4 changed files with 187 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,163 @@
/* 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);
}
/*
*
* 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;
}

View file

@ -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