diff --git a/src/soc/amd/common/block/graphics/Kconfig b/src/soc/amd/common/block/graphics/Kconfig index c277a0b23f..511f304373 100644 --- a/src/soc/amd/common/block/graphics/Kconfig +++ b/src/soc/amd/common/block/graphics/Kconfig @@ -10,3 +10,19 @@ config SOC_AMD_COMMON_BLOCK_GRAPHICS_ATIF 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 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. diff --git a/src/soc/amd/common/block/graphics/graphics.c b/src/soc/amd/common/block/graphics/graphics.c index 8910240d76..843bf787ee 100644 --- a/src/soc/amd/common/block/graphics/graphics.c +++ b/src/soc/amd/common/block/graphics/graphics.c @@ -2,13 +2,20 @@ #include #include +#include #include -#include +#include #include +#include +#include #include +#include #include #include +static bool vbios_loaded_from_cache = false; +static uint8_t vbios_data[VBIOS_CACHE_FMAP_SIZE]; + #define ATIF_FUNCTION_VERIFY_INTERFACE 0x0 struct atif_verify_interface_output { uint16_t size; /* Size of this object, including size field */ @@ -142,6 +149,13 @@ static void graphics_set_resources(struct device *const dev) return; 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); if (rom == NULL) return; @@ -167,6 +181,92 @@ static void graphics_dev_init(struct device *const 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 = { .read_resources = pci_dev_read_resources, .set_resources = graphics_set_resources, diff --git a/src/soc/amd/common/block/include/amdblocks/vbios_cache.h b/src/soc/amd/common/block/include/amdblocks/vbios_cache.h new file mode 100644 index 0000000000..e9425723b9 --- /dev/null +++ b/src/soc/amd/common/block/include/amdblocks/vbios_cache.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef __VBIOS_CACHE_H__ +#define __VBIOS_CACHE_H__ + +#include + +#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__ */