summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt DeVillier <matt.devillier@amd.corp-partner.google.com>2022-12-16 17:14:35 -0600
committerFelix Held <felix-coreboot@felixheld.de>2023-02-10 16:02:10 +0000
commite5e82862627eaf6d7edeb29af8b5c71d628e8c3c (patch)
treefb23183cd6bafd8ad1bc579adad355dccdae922f
parent6e0c78b87fe4bad7f02b893bf1f1ce8d3bbf84d8 (diff)
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>
-rw-r--r--src/soc/amd/common/block/graphics/Kconfig16
-rw-r--r--src/soc/amd/common/block/graphics/graphics.c102
-rw-r--r--src/soc/amd/common/block/include/amdblocks/vbios_cache.h21
3 files changed, 138 insertions, 1 deletions
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 <acpi/acpi_device.h>
#include <acpi/acpigen.h>
+#include <amdblocks/vbios_cache.h>
#include <boot/coreboot_tables.h>
-#include <device/pci.h>
+#include <bootstate.h>
#include <console/console.h>
+#include <device/pci.h>
+#include <fmap.h>
#include <fsp/graphics.h>
+#include <security/vboot/vboot_common.h>
#include <soc/intel/common/vbt.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
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 <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__ */