1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * From Coreboot file of the same name
4  *
5  * Copyright (C) 2011 The Chromium Authors.
6  */
7 
8 #include <common.h>
9 #include <log.h>
10 #include <asm/cpu.h>
11 #include <asm/global_data.h>
12 #include <asm/msr.h>
13 #include <asm/processor.h>
14 #include <asm/turbo.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 #ifdef CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED
get_global_turbo_state(void)19 static inline int get_global_turbo_state(void)
20 {
21 	return TURBO_UNKNOWN;
22 }
23 
set_global_turbo_state(int state)24 static inline void set_global_turbo_state(int state)
25 {
26 }
27 #else
get_global_turbo_state(void)28 static inline int get_global_turbo_state(void)
29 {
30 	return gd->arch.turbo_state;
31 }
32 
set_global_turbo_state(int state)33 static inline void set_global_turbo_state(int state)
34 {
35 	gd->arch.turbo_state = state;
36 }
37 #endif
38 
39 /* gcc 7.3 does not wwant to drop strings, so use #ifdef */
40 #ifndef CONFIG_TPL_BUILD
41 static const char *const turbo_state_desc[] = {
42 	[TURBO_UNKNOWN]		= "unknown",
43 	[TURBO_UNAVAILABLE]	= "unavailable",
44 	[TURBO_DISABLED]	= "available but hidden",
45 	[TURBO_ENABLED]		= "available and visible"
46 };
47 #endif
48 
49 /*
50  * Determine the current state of Turbo and cache it for later.
51  * Turbo is a package level config so it does not need to be
52  * enabled on every core.
53  */
turbo_get_state(void)54 int turbo_get_state(void)
55 {
56 	struct cpuid_result cpuid_regs;
57 	int turbo_en, turbo_cap;
58 	msr_t msr;
59 	int turbo_state = get_global_turbo_state();
60 
61 	/* Return cached state if available */
62 	if (turbo_state != TURBO_UNKNOWN)
63 		return turbo_state;
64 
65 	cpuid_regs = cpuid(CPUID_LEAF_PM);
66 	turbo_cap = !!(cpuid_regs.eax & PM_CAP_TURBO_MODE);
67 
68 	msr = msr_read(MSR_IA32_MISC_ENABLE);
69 	turbo_en = !(msr.hi & MISC_DISABLE_TURBO);
70 
71 	if (!turbo_cap && turbo_en) {
72 		/* Unavailable */
73 		turbo_state = TURBO_UNAVAILABLE;
74 	} else if (!turbo_cap && !turbo_en) {
75 		/* Available but disabled */
76 		turbo_state = TURBO_DISABLED;
77 	} else if (turbo_cap && turbo_en) {
78 		/* Available */
79 		turbo_state = TURBO_ENABLED;
80 	}
81 
82 	set_global_turbo_state(turbo_state);
83 #ifndef CONFIG_TPL_BUILD
84 	debug("Turbo is %s\n", turbo_state_desc[turbo_state]);
85 #endif
86 	return turbo_state;
87 }
88 
turbo_enable(void)89 void turbo_enable(void)
90 {
91 	msr_t msr;
92 
93 	/* Only possible if turbo is available but hidden */
94 	if (turbo_get_state() == TURBO_DISABLED) {
95 		/* Clear Turbo Disable bit in Misc Enables */
96 		msr = msr_read(MSR_IA32_MISC_ENABLE);
97 		msr.hi &= ~MISC_DISABLE_TURBO;
98 		msr_write(MSR_IA32_MISC_ENABLE, msr);
99 
100 		/* Update cached turbo state */
101 		set_global_turbo_state(TURBO_ENABLED);
102 		debug("Turbo has been enabled\n");
103 	}
104 }
105