x86: Add Intel speedstep and turbo mode code

Intel chips have a turbo mode where they can run faster for a short period
until they reach thermal limits. Add code to adjust and query this feature.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/x86/cpu/turbo.c b/arch/x86/cpu/turbo.c
new file mode 100644
index 0000000..254d0de
--- /dev/null
+++ b/arch/x86/cpu/turbo.c
@@ -0,0 +1,98 @@
+/*
+ * From Coreboot file of the same name
+ *
+ * Copyright (C) 2011 The Chromium Authors.
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <asm/cpu.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+#include <asm/turbo.h>
+
+#if CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED
+static inline int get_global_turbo_state(void)
+{
+	return TURBO_UNKNOWN;
+}
+
+static inline void set_global_turbo_state(int state)
+{
+}
+#else
+static int g_turbo_state = TURBO_UNKNOWN;
+
+static inline int get_global_turbo_state(void)
+{
+	return g_turbo_state;
+}
+
+static inline void set_global_turbo_state(int state)
+{
+	g_turbo_state = state;
+}
+#endif
+
+static const char *const turbo_state_desc[] = {
+	[TURBO_UNKNOWN]		= "unknown",
+	[TURBO_UNAVAILABLE]	= "unavailable",
+	[TURBO_DISABLED]	= "available but hidden",
+	[TURBO_ENABLED]		= "available and visible"
+};
+
+/*
+ * Determine the current state of Turbo and cache it for later.
+ * Turbo is a package level config so it does not need to be
+ * enabled on every core.
+ */
+int turbo_get_state(void)
+{
+	struct cpuid_result cpuid_regs;
+	int turbo_en, turbo_cap;
+	msr_t msr;
+	int turbo_state = get_global_turbo_state();
+
+	/* Return cached state if available */
+	if (turbo_state != TURBO_UNKNOWN)
+		return turbo_state;
+
+	cpuid_regs = cpuid(CPUID_LEAF_PM);
+	turbo_cap = !!(cpuid_regs.eax & PM_CAP_TURBO_MODE);
+
+	msr = msr_read(MSR_IA32_MISC_ENABLES);
+	turbo_en = !(msr.hi & H_MISC_DISABLE_TURBO);
+
+	if (!turbo_cap && turbo_en) {
+		/* Unavailable */
+		turbo_state = TURBO_UNAVAILABLE;
+	} else if (!turbo_cap && !turbo_en) {
+		/* Available but disabled */
+		turbo_state = TURBO_DISABLED;
+	} else if (turbo_cap && turbo_en) {
+		/* Available */
+		turbo_state = TURBO_ENABLED;
+	}
+
+	set_global_turbo_state(turbo_state);
+	debug("Turbo is %s\n", turbo_state_desc[turbo_state]);
+	return turbo_state;
+}
+
+void turbo_enable(void)
+{
+	msr_t msr;
+
+	/* Only possible if turbo is available but hidden */
+	if (turbo_get_state() == TURBO_DISABLED) {
+		/* Clear Turbo Disable bit in Misc Enables */
+		msr = msr_read(MSR_IA32_MISC_ENABLES);
+		msr.hi &= ~H_MISC_DISABLE_TURBO;
+		msr_write(MSR_IA32_MISC_ENABLES, msr);
+
+		/* Update cached turbo state */
+		set_global_turbo_state(TURBO_ENABLED);
+		debug("Turbo has been enabled\n");
+	}
+}