amd/picasso: Load x86 microcode from CBFS modules

Combine the Ucode binaries for 3 revisions of CPU into one
CBFS module.
This should be moved to the AMD common code later.

BUG=b:153580119
TEST=mandolin

Change-Id: Ib08a65b93c045afc97952a809670c85831c0faf7
Signed-off-by: Zheng Bao <zheng.bao@amd.com>
Signed-off-by: Zheng Bao <fishbaozi@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41719
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
diff --git a/src/soc/amd/picasso/Kconfig b/src/soc/amd/picasso/Kconfig
index 5ba0c1b..2bd9c09 100644
--- a/src/soc/amd/picasso/Kconfig
+++ b/src/soc/amd/picasso/Kconfig
@@ -54,6 +54,7 @@
 	select FSP_USES_CB_STACK
 	select UDK_2017_BINDING
 	select HAVE_CF9_RESET
+	select SUPPORT_CPU_UCODE_IN_CBFS
 
 config PRERAM_CBMEM_CONSOLE_SIZE
 	hex
diff --git a/src/soc/amd/picasso/Makefile.inc b/src/soc/amd/picasso/Makefile.inc
index 8012f97..7fce124 100644
--- a/src/soc/amd/picasso/Makefile.inc
+++ b/src/soc/amd/picasso/Makefile.inc
@@ -64,6 +64,7 @@
 ramstage-y += psp.c
 ramstage-y += fsp_params.c
 ramstage-y += config.c
+ramstage-y += update_microcode.c
 
 all-y += reset.c
 
@@ -281,9 +282,6 @@
 OPT_PSP_PMUD_FILE2=$(call add_opt_prefix, $(PSP_PMUD_FILE2), --subprogram 0 --instance 4 --pmu-data)
 OPT_PSP_PMUD_FILE3=$(call add_opt_prefix, $(PSP_PMUD_FILE3), --subprogram 1 --instance 1 --pmu-data)
 OPT_PSP_PMUD_FILE4=$(call add_opt_prefix, $(PSP_PMUD_FILE4), --subprogram 1 --instance 4 --pmu-data)
-OPT_PSP_UCODE_FILE1=$(call add_opt_prefix, $(PSP_UCODE_FILE1), --instance 0 --ucode)
-OPT_PSP_UCODE_FILE2=$(call add_opt_prefix, $(PSP_UCODE_FILE2), --instance 1 --ucode)
-OPT_PSP_UCODE_FILE3=$(call add_opt_prefix, $(PSP_UCODE_FILE3), --instance 2 --ucode)
 OPT_MP2CFG_FILE=$(call add_opt_prefix, $(PSP_MP2CFG_FILE), --mp2-config)
 
 # Copy prebuild APCBs if they exist
@@ -342,9 +340,6 @@
 			$(call strip_quotes, $(PSP_PMUD_FILE2)) \
 			$(call strip_quotes, $(PSP_PMUD_FILE3)) \
 			$(call strip_quotes, $(PSP_PMUD_FILE4)) \
-			$(call strip_quotes, $(PSP_UCODE_FILE1)) \
-			$(call strip_quotes, $(PSP_UCODE_FILE2)) \
-			$(call strip_quotes, $(PSP_UCODE_FILE3)) \
 			$(call strip_quotes, $(PSP_MP2CFG_FILE)) \
 			$(call strip_quotes, $(PSP_SMUFW1_SUB1_FILE)) \
 			$(call strip_quotes, $(PSP_SMUFW1_SUB2_FILE)) \
@@ -399,9 +394,6 @@
 		$(OPT_PSP_PMUD_FILE2) \
 		$(OPT_PSP_PMUD_FILE3) \
 		$(OPT_PSP_PMUD_FILE4) \
-		$(OPT_PSP_UCODE_FILE1) \
-		$(OPT_PSP_UCODE_FILE2) \
-		$(OPT_PSP_UCODE_FILE3) \
 		$(OPT_MP2CFG_FILE) \
 		$(OPT_ABL0_FILE) \
 		$(OPT_ABL1_FILE) \
@@ -461,4 +453,6 @@
 
 $(call strip_quotes,$(CONFIG_FSP_M_CBFS))-options := -b $(CONFIG_FSP_M_ADDR)
 
+cpu_microcode_bins += $(wildcard 3rdparty/amd_blobs/picasso/PSP/UcodePatch_*.bin)
+
 endif # ($(CONFIG_SOC_AMD_PICASSO),y)
diff --git a/src/soc/amd/picasso/cpu.c b/src/soc/amd/picasso/cpu.c
index 96edd70..97a1780 100644
--- a/src/soc/amd/picasso/cpu.c
+++ b/src/soc/amd/picasso/cpu.c
@@ -16,6 +16,7 @@
 #include <soc/smi.h>
 #include <soc/iomap.h>
 #include <console/console.h>
+#include <cpu/amd/microcode.h>
 
 /*
  * MP and SMM loading initialization.
@@ -108,6 +109,8 @@
 {
 	check_mca();
 	setup_lapic();
+
+	amd_update_microcode_from_cbfs();
 }
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/soc/amd/picasso/update_microcode.c b/src/soc/amd/picasso/update_microcode.c
new file mode 100644
index 0000000..8f3d3e2
--- /dev/null
+++ b/src/soc/amd/picasso/update_microcode.c
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <stdint.h>
+#include <cpu/amd/microcode.h>
+#include <commonlib/helpers.h>
+#include <console/console.h>
+#include <cpu/x86/msr.h>
+#include <cpu/amd/msr.h>
+#include <cbfs.h>
+
+#define MPB_MAX_SIZE 3200
+#define MPB_DATA_OFFSET 32
+
+struct microcode {
+	uint32_t date_code;
+	uint32_t patch_id;
+
+	uint16_t mc_patch_data_id;
+	uint8_t reserved1[6];
+
+	uint32_t chipset1_dev_id;
+	uint32_t chipset2_dev_id;
+
+	uint16_t processor_rev_id;
+
+	uint8_t chipset1_rev_id;
+	uint8_t chipset2_rev_id;
+
+	uint8_t reserved2[4];
+
+	uint8_t m_patch_data[MPB_MAX_SIZE-MPB_DATA_OFFSET];
+} __packed;
+
+static void apply_microcode_patch(const struct microcode *m)
+{
+	uint32_t new_patch_id;
+	msr_t msr;
+
+	msr.hi = (uint64_t)(uintptr_t)m >> 32;
+	msr.lo = (uintptr_t)m & 0xffffffff;
+
+	wrmsr(MSR_PATCH_LOADER, msr);
+
+	printk(BIOS_DEBUG, "microcode: patch id to apply = 0x%08x\n",
+		m->patch_id);
+
+	msr = rdmsr(MSR_PATCH_LEVEL);
+	new_patch_id = msr.lo;
+
+	if (new_patch_id == m->patch_id)
+		printk(BIOS_INFO, "microcode: being updated to patch id = 0x%08x succeeded\n",
+			new_patch_id);
+	else
+		printk(BIOS_ERR, "microcode: being updated to patch id = 0x%08x failed\n",
+			new_patch_id);
+}
+
+static uint16_t get_equivalent_processor_rev_id(void)
+{
+	uint32_t cpuid_family = cpuid_eax(1);
+
+	return (uint16_t)((cpuid_family & 0xff0000) >> 8 | (cpuid_family & 0xff));
+}
+
+static void amd_update_microcode(const void *ucode, size_t ucode_len,
+				uint16_t equivalent_processor_rev_id)
+{
+	const struct microcode *m;
+
+	for (m = (struct microcode *)ucode;
+		m < (struct microcode *)ucode + ucode_len/MPB_MAX_SIZE; m++) {
+		if (m->processor_rev_id == equivalent_processor_rev_id)
+			apply_microcode_patch(m);
+	}
+}
+
+void amd_update_microcode_from_cbfs(void)
+{
+	const void *ucode;
+	size_t ucode_len;
+	uint16_t equivalent_processor_rev_id = get_equivalent_processor_rev_id();
+
+	ucode = cbfs_boot_map_with_leak("cpu_microcode_blob.bin",
+					CBFS_TYPE_MICROCODE, &ucode_len);
+	if (!ucode) {
+		printk(BIOS_WARNING, "cpu_microcode_blob.bin not found. Skipping updates.\n");
+		return;
+	}
+
+	amd_update_microcode(ucode, ucode_len, equivalent_processor_rev_id);
+}