diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Kconfig | 27 | ||||
-rw-r--r-- | src/include/device/device.h | 4 | ||||
-rw-r--r-- | src/include/fw_config.h | 53 | ||||
-rw-r--r-- | src/lib/Makefile.inc | 5 | ||||
-rw-r--r-- | src/lib/fw_config.c | 94 |
5 files changed, 183 insertions, 0 deletions
diff --git a/src/Kconfig b/src/Kconfig index 2a2a144235..b96d51f526 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -323,6 +323,33 @@ config BOOTSPLASH_FILE The path and filename of the file to use as graphical bootsplash screen. The file format has to be jpg. +config FW_CONFIG + bool "Firmware Configuration Probing" + default n + help + Enable support for probing devices with fw_config. This is a simple + bitmask broken into fields and options for probing. + +config FW_CONFIG_SOURCE_CBFS + bool "Obtain Firmware Configuration value from CBFS" + depends on FW_CONFIG + default n + help + With this option enabled coreboot will look for the 32bit firmware + configuration value in CBFS at the selected prefix with the file name + "fw_config". This option will override other sources and allow the + local image to preempt the mainboard selected source. + +config FW_CONFIG_SOURCE_CHROMEEC_CBI + bool "Obtain Firmware Configuration value from Google Chrome EC CBI" + depends on FW_CONFIG && EC_GOOGLE_CHROMEEC + default n + help + This option tells coreboot to read the firmware configuration value + from the Google Chrome Embedded Controller CBI interface. This source + is not tried if FW_CONFIG_SOURCE_CBFS is enabled and the value was + found in CBFS. + config HAVE_RAMPAYLOAD bool diff --git a/src/include/device/device.h b/src/include/device/device.h index 46efbfe679..082dcbb4d3 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -8,6 +8,7 @@ #include <smbios.h> #include <types.h> +struct fw_config; struct device; struct pci_operations; struct i2c_bus_operations; @@ -147,6 +148,9 @@ struct device { #endif #endif DEVTREE_CONST void *chip_info; + + /* Zero-terminated array of fields and options to probe. */ + DEVTREE_CONST struct fw_config *probe_list; }; /** diff --git a/src/include/fw_config.h b/src/include/fw_config.h new file mode 100644 index 0000000000..d41afd6c5d --- /dev/null +++ b/src/include/fw_config.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __FW_CONFIG__ +#define __FW_CONFIG__ + +#include <device/device.h> +#include <static.h> /* Provides fw_config definitions from devicetree.cb */ +#include <stdbool.h> +#include <stdint.h> + +/** + * struct fw_config - Firmware configuration field and option. + * @field_name: Name of the field that this option belongs to. + * @option_name: Name of the option within this field. + * @mask: Bitmask of the field. + * @value: Value of the option within the mask. + */ +struct fw_config { + const char *field_name; + const char *option_name; + uint32_t mask; + uint32_t value; +}; + +/* Generate a pointer to a compound literal of the fw_config structure. */ +#define FW_CONFIG(__field, __option) (&(const struct fw_config) { \ + .field_name = FW_CONFIG_FIELD_##__field##_NAME, \ + .option_name = FW_CONFIG_FIELD_##__field##_OPTION_##__option##_NAME, \ + .mask = FW_CONFIG_FIELD_##__field##_MASK, \ + .value = FW_CONFIG_FIELD_##__field##_OPTION_##__option##_VALUE \ +}) + +#if CONFIG(FW_CONFIG) + +/** + * fw_config_probe() - Check if field and option matches. + * @match: Structure containing field and option to probe. + * + * Return %true if match is found, %false if match is not found. + */ +bool fw_config_probe(const struct fw_config *match); + +#else + +static inline bool fw_config_probe(const struct fw_config *match) +{ + /* Always return true when probing with disabled fw_config. */ + return true; +} + +#endif /* CONFIG(FW_CONFIG) */ + +#endif /* __FW_CONFIG__ */ diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 6511c0c328..e0003bd1cf 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -159,6 +159,11 @@ romstage-y += hexdump.c verstage-y += hexdump.c smm-y += hexdump.c +bootblock-$(CONFIG_FW_CONFIG) += fw_config.c +verstage-$(CONFIG_FW_CONFIG) += fw_config.c +romstage-$(CONFIG_FW_CONFIG) += fw_config.c +ramstage-$(CONFIG_FW_CONFIG) += fw_config.c + bootblock-$(CONFIG_ESPI_DEBUG) += espi_debug.c verstage-$(CONFIG_ESPI_DEBUG) += espi_debug.c romstage-$(CONFIG_ESPI_DEBUG) += espi_debug.c diff --git a/src/lib/fw_config.c b/src/lib/fw_config.c new file mode 100644 index 0000000000..e97cfdc72a --- /dev/null +++ b/src/lib/fw_config.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <cbfs.h> +#include <console/console.h> +#include <device/device.h> +#include <ec/google/chromeec/ec.h> +#include <fw_config.h> +#include <stdbool.h> +#include <stdint.h> + +/** + * fw_config_get() - Provide firmware configuration value. + * + * Return 32bit firmware configuration value determined for the system. + */ +static uint32_t fw_config_get(void) +{ + static uint32_t fw_config_value; + static bool fw_config_value_initialized; + + /* Nothing to prepare if setup is already done. */ + if (fw_config_value_initialized) + return fw_config_value; + fw_config_value_initialized = true; + + /* Look in CBFS to allow override of value. */ + if (CONFIG(FW_CONFIG_SOURCE_CBFS)) { + if (cbfs_boot_load_file(CONFIG_CBFS_PREFIX "/fw_config", + &fw_config_value, sizeof(fw_config_value), + CBFS_TYPE_RAW) != sizeof(fw_config_value)) { + printk(BIOS_WARNING, "%s: Could not get fw_config from CBFS\n", + __func__); + fw_config_value = 0; + } else { + printk(BIOS_INFO, "FW_CONFIG value from CBFS is 0x%08x\n", + fw_config_value); + return fw_config_value; + } + } + + /* Read the value from EC CBI. */ + if (CONFIG(FW_CONFIG_SOURCE_CHROMEEC_CBI)) { + if (google_chromeec_cbi_get_fw_config(&fw_config_value)) + printk(BIOS_WARNING, "%s: Could not get fw_config from EC\n", __func__); + } + + printk(BIOS_INFO, "FW_CONFIG value is 0x%08x\n", fw_config_value); + return fw_config_value; +} + +bool fw_config_probe(const struct fw_config *match) +{ + /* Compare to system value. */ + if ((fw_config_get() & match->mask) == match->value) { + if (match->field_name && match->option_name) + printk(BIOS_INFO, "fw_config match found: %s=%s\n", match->field_name, + match->option_name); + else + printk(BIOS_INFO, "fw_config match found: mask=0x%08x value=0x%08x\n", + match->mask, match->value); + return true; + } + + return false; +} + +#if ENV_RAMSTAGE +static void fw_config_init(void *unused) +{ + struct device *dev; + + for (dev = all_devices; dev; dev = dev->next) { + const struct fw_config *probe; + bool match = false; + + if (!dev->probe_list) + continue; + + for (probe = dev->probe_list; probe && probe->mask != 0; probe++) { + if (fw_config_probe(probe)) { + match = true; + break; + } + } + + if (!match) { + printk(BIOS_INFO, "%s disabled by fw_config\n", dev_path(dev)); + dev->enabled = 0; + } + } +} +BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_ENTRY, fw_config_init, NULL); +#endif |