x86: Move microcode code to a common location

This code is used on several Intel CPUs. Move it into a common location.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile
index 5dd9573..ca4e171 100644
--- a/arch/x86/cpu/intel_common/Makefile
+++ b/arch/x86/cpu/intel_common/Makefile
@@ -5,3 +5,6 @@
 #
 
 obj-$(CONFIG_HAVE_MRC) += car.o
+ifndef CONFIG_TARGET_EFI
+obj-y += microcode.o
+endif
diff --git a/arch/x86/cpu/intel_common/car.S b/arch/x86/cpu/intel_common/car.S
index 1defabf..81ac976 100644
--- a/arch/x86/cpu/intel_common/car.S
+++ b/arch/x86/cpu/intel_common/car.S
@@ -12,12 +12,12 @@
  */
 
 #include <common.h>
+#include <asm/microcode.h>
 #include <asm/msr-index.h>
 #include <asm/mtrr.h>
 #include <asm/post.h>
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
-#include <asm/arch/microcode.h>
 
 #define MTRR_PHYS_BASE_MSR(reg) (0x200 + 2 * (reg))
 #define MTRR_PHYS_MASK_MSR(reg) (0x200 + 2 * (reg) + 1)
diff --git a/arch/x86/cpu/intel_common/microcode.c b/arch/x86/cpu/intel_common/microcode.c
new file mode 100644
index 0000000..3054fab
--- /dev/null
+++ b/arch/x86/cpu/intel_common/microcode.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Copyright (C) 2000 Ronald G. Minnich
+ *
+ * Microcode update for Intel PIII and later CPUs
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <asm/cpu.h>
+#include <asm/microcode.h>
+#include <asm/msr.h>
+#include <asm/msr-index.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct microcode_update - standard microcode header from Intel
+ *
+ * We read this information out of the device tree and use it to determine
+ * whether the update is applicable or not. We also use the same structure
+ * to read information from the CPU.
+ */
+struct microcode_update {
+	uint header_version;
+	uint update_revision;
+	uint date_code;
+	uint processor_signature;
+	uint checksum;
+	uint loader_revision;
+	uint processor_flags;
+	const void *data;
+	int size;
+};
+
+static int microcode_decode_node(const void *blob, int node,
+				 struct microcode_update *update)
+{
+	update->data = fdt_getprop(blob, node, "data", &update->size);
+	if (!update->data)
+		return -EINVAL;
+	update->data += UCODE_HEADER_LEN;
+	update->size -= UCODE_HEADER_LEN;
+
+	update->header_version = fdtdec_get_int(blob, node,
+						"intel,header-version", 0);
+	update->update_revision = fdtdec_get_int(blob, node,
+						 "intel,update-revision", 0);
+	update->date_code = fdtdec_get_int(blob, node,
+					   "intel,date-code", 0);
+	update->processor_signature = fdtdec_get_int(blob, node,
+					"intel,processor-signature", 0);
+	update->checksum = fdtdec_get_int(blob, node, "intel,checksum", 0);
+	update->loader_revision = fdtdec_get_int(blob, node,
+						 "intel,loader-revision", 0);
+	update->processor_flags = fdtdec_get_int(blob, node,
+						 "intel,processor-flags", 0);
+
+	return 0;
+}
+
+static inline uint32_t microcode_read_rev(void)
+{
+	/*
+	 * Some Intel CPUs can be very finicky about the CPUID sequence used.
+	 * So this is implemented in assembly so that it works reliably.
+	 */
+	uint32_t low, high;
+
+	asm volatile (
+		"xorl %%eax, %%eax\n"
+		"xorl %%edx, %%edx\n"
+		"movl %2, %%ecx\n"
+		"wrmsr\n"
+		"movl $0x01, %%eax\n"
+		"cpuid\n"
+		"movl %2, %%ecx\n"
+		"rdmsr\n"
+		: /* outputs */
+		"=a" (low), "=d" (high)
+		: /* inputs */
+		"i" (MSR_IA32_UCODE_REV)
+		: /* clobbers */
+		 "ebx", "ecx"
+	);
+
+	return high;
+}
+
+static void microcode_read_cpu(struct microcode_update *cpu)
+{
+	/* CPUID sets MSR 0x8B iff a microcode update has been loaded. */
+	unsigned int x86_model, x86_family;
+	struct cpuid_result result;
+	uint32_t low, high;
+
+	wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+	result = cpuid(1);
+	rdmsr(MSR_IA32_UCODE_REV, low, cpu->update_revision);
+	x86_model = (result.eax >> 4) & 0x0f;
+	x86_family = (result.eax >> 8) & 0x0f;
+	cpu->processor_signature = result.eax;
+
+	cpu->processor_flags = 0;
+	if ((x86_model >= 5) || (x86_family > 6)) {
+		rdmsr(0x17, low, high);
+		cpu->processor_flags = 1 << ((high >> 18) & 7);
+	}
+	debug("microcode: sig=%#x pf=%#x revision=%#x\n",
+	      cpu->processor_signature, cpu->processor_flags,
+	      cpu->update_revision);
+}
+
+/* Get a microcode update from the device tree and apply it */
+int microcode_update_intel(void)
+{
+	struct microcode_update cpu, update;
+	const void *blob = gd->fdt_blob;
+	int skipped;
+	int count;
+	int node;
+	int ret;
+	int rev;
+
+	microcode_read_cpu(&cpu);
+	node = 0;
+	count = 0;
+	skipped = 0;
+	do {
+		node = fdtdec_next_compatible(blob, node,
+					      COMPAT_INTEL_MICROCODE);
+		if (node < 0) {
+			debug("%s: Found %d updates\n", __func__, count);
+			return count ? 0 : skipped ? -EEXIST : -ENOENT;
+		}
+
+		ret = microcode_decode_node(blob, node, &update);
+		if (ret) {
+			debug("%s: Unable to decode update: %d\n", __func__,
+			      ret);
+			return ret;
+		}
+		if (!(update.processor_signature == cpu.processor_signature &&
+		      (update.processor_flags & cpu.processor_flags))) {
+			debug("%s: Skipping non-matching update, sig=%x, pf=%x\n",
+			      __func__, update.processor_signature,
+			      update.processor_flags);
+			skipped++;
+			continue;
+		}
+		wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0);
+		rev = microcode_read_rev();
+		debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n",
+		      rev, update.date_code & 0xffff,
+		      (update.date_code >> 24) & 0xff,
+		      (update.date_code >> 16) & 0xff);
+		if (update.update_revision != rev) {
+			printf("Microcode update failed\n");
+			return -EFAULT;
+		}
+		count++;
+	} while (1);
+}