summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Kconfig27
-rw-r--r--src/include/device/device.h4
-rw-r--r--src/include/fw_config.h53
-rw-r--r--src/lib/Makefile.inc5
-rw-r--r--src/lib/fw_config.c94
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