src/lib: Add FW_CONFIG_SOURCE_VPD

Read fw_config value from VPD.
This new option can be used where chrome EC is not supported like
pre-silicon platform and fw_config can be updated by VPD tool in OS.

TEST= boot to OS and read fw_config from vpd
1. Boot to OS
2. Write "fw_config" in VPD
   ex) vpd -i "RW_VPD" -s "fw_config"="1"
3. reboot and check fw_config value from coreboot log

Signed-off-by: Wonkyu Kim <wonkyu.kim@intel.com>
Change-Id: I4df7d5612e18957416a40ab854fa63c8b11b4216
Reviewed-on: https://review.coreboot.org/c/coreboot/+/58839
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
diff --git a/src/Kconfig b/src/Kconfig
index e30152d..e1d0c00 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -416,6 +416,16 @@
 	  local image to preempt the mainboard selected source and can be used as
 	  FW_CONFIG_SOURCE_CHROMEEC_CBI fallback option.
 
+config FW_CONFIG_SOURCE_VPD
+	bool "Obtain Firmware Configuration value from VPD"
+	depends on FW_CONFIG && VPD
+	default n
+	help
+	  With this option enabled coreboot will look for the 32bit firmware
+	  configuration value in VPD key name "fw_config".  This option will
+	  override other sources and allow the local image to preempt the mainboard
+	  selected source and can be used for other FW_CONFIG_SOURCEs fallback option.
+
 config HAVE_RAMPAYLOAD
 	bool
 
diff --git a/src/lib/fw_config.c b/src/lib/fw_config.c
index 3546736..72cf225 100644
--- a/src/lib/fw_config.c
+++ b/src/lib/fw_config.c
@@ -11,6 +11,7 @@
 #include <lib.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <drivers/vpd/vpd.h>
 
 uint64_t fw_config_get(void)
 {
@@ -44,6 +45,17 @@
 				fw_config_value);
 	}
 
+	if (CONFIG(FW_CONFIG_SOURCE_VPD) && fw_config_value == UNDEFINED_FW_CONFIG) {
+		int vpd_value;
+		if (vpd_get_int("fw_config", VPD_RW_THEN_RO, &vpd_value)) {
+			fw_config_value = vpd_value;
+			printk(BIOS_INFO, "FW_CONFIG value from VPD is 0x%" PRIx64 "\n",
+				fw_config_value);
+		} else
+			printk(BIOS_WARNING, "%s: Could not get fw_config from vpd\n",
+				__func__);
+	}
+
 	return fw_config_value;
 }