soc/amd/common/gfx: add support for VBIOS caching, selective GOP init

One of the main functions performed by the FSP GOP driver is to modify
the ATOMBIOS tables (part of the VBIOS) in memory based on the display
output configuration. This device-specific modified VBIOS can be cached
in a FMAP region specific for that purpose, then loaded into memory
instead of the "generic" VBIOS, saving the ~130ms execution time of the
GOP driver.

As this approach only works when no pre-OS display output is needed,
limit its use to ChromeOS builds, with the GOP driver enabled, and
not booting in either recovery or developer modes.

SoCs supporting this feature will need to selectively run the FSP GOP
driver as needed, using the same criteria used here to determine
whether to load the VBIOS from CBFS or from the FMAP cache.

Boards utilizing this feature will need to add a dedicated FMAP region
with the appropriate name/size, and select the required Kconfig options.

BUG=b:255812886
TEST=tested with rest of patch train

Change-Id: Ib9cfd192500d411655a3c8fa436098897428109e
Signed-off-by: Matt DeVillier <matt.devillier@amd.corp-partner.google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/70858
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Jon Murphy <jpmurphy@google.com>
This commit is contained in:
Matt DeVillier 2022-12-16 17:14:35 -06:00 committed by Felix Held
parent 6e0c78b87f
commit e5e8286262
3 changed files with 138 additions and 1 deletions

View File

@ -10,3 +10,19 @@ config SOC_AMD_COMMON_BLOCK_GRAPHICS_ATIF
Select this option to provide ATIF method with display brightness querying. Select this option to provide ATIF method with display brightness querying.
Currently, the exported values only open up 0-255 as the brightness range for Currently, the exported values only open up 0-255 as the brightness range for
the display. the display.
config SOC_AMD_GFX_CACHE_VBIOS_IN_FMAP
bool "Support for caching modified VBIOS tables in flash"
depends on SOC_AMD_COMMON_BLOCK_GRAPHICS && CHROMEOS && RUN_FSP_GOP
default n
help
Enable support for flash based VBIOS cache.
config USE_SELECTIVE_GOP_INIT
bool "Run FSP GOP driver only when needed for recovery/developer modes"
depends on SOC_AMD_GFX_CACHE_VBIOS_IN_FMAP
default n
help
Select this option to only run the FSP GOP driver when needed for pre-OS display init
(eg, Recovery and Developer Modes). Otherwise, use cached VBIOS/ATOMBIOS tables.
Selecting this option will save approx. 130ms boot time on the normal boot path.

View File

@ -2,13 +2,20 @@
#include <acpi/acpi_device.h> #include <acpi/acpi_device.h>
#include <acpi/acpigen.h> #include <acpi/acpigen.h>
#include <amdblocks/vbios_cache.h>
#include <boot/coreboot_tables.h> #include <boot/coreboot_tables.h>
#include <device/pci.h> #include <bootstate.h>
#include <console/console.h> #include <console/console.h>
#include <device/pci.h>
#include <fmap.h>
#include <fsp/graphics.h> #include <fsp/graphics.h>
#include <security/vboot/vboot_common.h>
#include <soc/intel/common/vbt.h> #include <soc/intel/common/vbt.h>
#include <timestamp.h> #include <timestamp.h>
static bool vbios_loaded_from_cache = false;
static uint8_t vbios_data[VBIOS_CACHE_FMAP_SIZE];
#define ATIF_FUNCTION_VERIFY_INTERFACE 0x0 #define ATIF_FUNCTION_VERIFY_INTERFACE 0x0
struct atif_verify_interface_output { struct atif_verify_interface_output {
uint16_t size; /* Size of this object, including size field */ uint16_t size; /* Size of this object, including size field */
@ -142,6 +149,13 @@ static void graphics_set_resources(struct device *const dev)
return; return;
timestamp_add_now(TS_OPROM_INITIALIZE); timestamp_add_now(TS_OPROM_INITIALIZE);
if (CONFIG(USE_SELECTIVE_GOP_INIT) && vbios_cache_is_valid()) {
if (!vboot_recovery_mode_enabled() && !vboot_developer_mode_enabled()) {
vbios_load_from_cache();
timestamp_add_now(TS_OPROM_COPY_END);
return;
}
}
rom = pci_rom_probe(dev); rom = pci_rom_probe(dev);
if (rom == NULL) if (rom == NULL)
return; return;
@ -167,6 +181,92 @@ static void graphics_dev_init(struct device *const dev)
pci_dev_init(dev); pci_dev_init(dev);
} }
static void read_vbios_cache_from_fmap(void *unused)
{
struct region_device rw_vbios_cache;
int32_t region_size;
if (!CONFIG(SOC_AMD_GFX_CACHE_VBIOS_IN_FMAP))
return;
if (fmap_locate_area_as_rdev(VBIOS_CACHE_FMAP_NAME, &rw_vbios_cache)) {
printk(BIOS_ERR, "%s: No %s FMAP section.\n", __func__, VBIOS_CACHE_FMAP_NAME);
return;
}
region_size = region_device_sz(&rw_vbios_cache);
if (region_size != VBIOS_CACHE_FMAP_SIZE) {
printk(BIOS_ERR, "%s: %s FMAP size mismatch for VBIOS cache (%d vs %d).\n",
__func__, VBIOS_CACHE_FMAP_NAME, VBIOS_CACHE_FMAP_SIZE, region_size);
return;
}
/* Read cached VBIOS data into buffer */
if (rdev_readat(&rw_vbios_cache, &vbios_data, 0, VBIOS_CACHE_FMAP_SIZE) != VBIOS_CACHE_FMAP_SIZE) {
printk(BIOS_ERR, "Failed to read vbios data from flash; rdev_readat() failed.\n");
return;
}
printk(BIOS_SPEW, "VBIOS cache successfully read from FMAP.\n");
}
static void write_vbios_cache_to_fmap(void *unused)
{
if (!CONFIG(SOC_AMD_GFX_CACHE_VBIOS_IN_FMAP))
return;
/* Don't save if VBIOS loaded from cache / data unchanged */
if (vbios_loaded_from_cache == true) {
printk(BIOS_SPEW, "VBIOS data loaded from cache; not saving\n");
return;
}
struct region_device rw_vbios_cache;
if (fmap_locate_area_as_rdev_rw(VBIOS_CACHE_FMAP_NAME, &rw_vbios_cache)) {
printk(BIOS_ERR, "%s: No %s FMAP section.\n", __func__, VBIOS_CACHE_FMAP_NAME);
return;
}
/* copy from PCI_VGA_RAM_IMAGE_START to rdev */
if (rdev_writeat(&rw_vbios_cache, (void *)PCI_VGA_RAM_IMAGE_START, 0,
VBIOS_CACHE_FMAP_SIZE) != VBIOS_CACHE_FMAP_SIZE)
printk(BIOS_ERR, "Failed to save vbios data to flash; rdev_writeat() failed.\n");
printk(BIOS_SPEW, "VBIOS cache successfully written to FMAP.\n");
}
/*
* Loads cached VBIOS data into legacy oprom location.
*
* Assumes user has called vbios_cache_is_valid() and checked for success
*/
void vbios_load_from_cache(void)
{
/* copy cached vbios data from buffer to PCI_VGA_RAM_IMAGE_START */
memcpy((void *)PCI_VGA_RAM_IMAGE_START, vbios_data, VBIOS_CACHE_FMAP_SIZE);
/* mark cache as used so we know not to write it later */
vbios_loaded_from_cache = true;
}
/*
* Return true if VBIOS cache data is valid
*
* For now, just compare first 2 bytes of data
* TODO: replace with TPM hash verification once implemented
*/
bool vbios_cache_is_valid(void)
{
bool is_valid = vbios_data[0] == 0x55 && vbios_data[1] == 0xaa;
printk(BIOS_SPEW, "VBIOS cache is %s\n", is_valid ? "valid" : "invalid");
return is_valid;
}
BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_EXIT, read_vbios_cache_from_fmap, NULL);
BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_ENTRY, write_vbios_cache_to_fmap, NULL);
const struct device_operations amd_graphics_ops = { const struct device_operations amd_graphics_ops = {
.read_resources = pci_dev_read_resources, .read_resources = pci_dev_read_resources,
.set_resources = graphics_set_resources, .set_resources = graphics_set_resources,

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#ifndef __VBIOS_CACHE_H__
#define __VBIOS_CACHE_H__
#include <types.h>
#define VBIOS_CACHE_FMAP_NAME "RW_VBIOS_CACHE"
#define VBIOS_CACHE_FMAP_SIZE 0x10000
/*
* Return true if VBIOS cache contains valid data
*/
bool vbios_cache_is_valid(void);
/*
* Loads cached VBIOS data into legacy oprom location.
*/
void vbios_load_from_cache(void);
#endif /* __VBIOS_CACHE_H__ */