blob: fa163d7e49e52f7440e29cc0513c274d568b6126 [file] [log] [blame]
/* 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>
#include <spi_flash.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);
}
}
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);
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;
}