1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
5 #include <cpu/intel/speedstep.h>
6 #include <cpu/x86/msr.h>
11 * @brief Gather speedstep limits for current processor
13 * At least power limits are processor type specific. Penryn introduced half
14 * steps in bus ratios. Don't know about Atom processors.
16 static void speedstep_get_limits(sst_params_t
*const params
)
20 const uint16_t cpu_id
= (cpuid_eax(1) >> 4) & 0xffff;
21 const uint32_t state_mask
=
22 /* Penryn supports non integer (i.e. half) ratios. */
23 ((cpu_id
== 0x1067) ? SPEEDSTEP_RATIO_NONINT
: 0)
24 | SPEEDSTEP_RATIO_VALUE_MASK
| SPEEDSTEP_VID_MASK
;
26 /* Initialize params to zero. */
27 memset(params
, '\0', sizeof(*params
));
29 /* Read Super-LFM parameters. */
30 if (((rdmsr(MSR_EXTENDED_CONFIG
).lo
>> 27) & 3) == 3) {/*supported and
32 msr
= rdmsr(MSR_FSB_CLOCK_VCC
);
33 params
->slfm
= SPEEDSTEP_STATE_FROM_MSR(msr
.lo
, state_mask
);
34 params
->slfm
.dynfsb
= 1;
35 params
->slfm
.is_slfm
= 1;
38 /* Read normal minimum parameters. */
39 msr
= rdmsr(MSR_THERM2_CTL
);
40 params
->min
= SPEEDSTEP_STATE_FROM_MSR(msr
.lo
, state_mask
);
42 /* Read normal maximum parameters. */
43 /* Newer CPUs provide the normal maximum settings in
44 IA32_PLATFORM_ID. The values in IA32_PERF_STATUS change
45 when using turbo mode. */
46 msr
= rdmsr(IA32_PLATFORM_ID
);
47 params
->max
= SPEEDSTEP_STATE_FROM_MSR(msr
.lo
, state_mask
);
48 if (cpu_id
== 0x006e) {
49 /* Looks like Yonah CPUs don't have the frequency ratio in
50 IA32_PLATFORM_ID. Use IA32_PERF_STATUS instead, the reading
51 should be reliable as those CPUs don't have turbo mode. */
52 msr
= rdmsr(IA32_PERF_STATUS
);
53 params
->max
.ratio
= (msr
.hi
& SPEEDSTEP_RATIO_VALUE_MASK
)
54 >> SPEEDSTEP_RATIO_SHIFT
;
57 /* Read turbo parameters. */
58 msr
= rdmsr(MSR_FSB_CLOCK_VCC
);
59 if ((msr
.hi
& (1 << (63 - 32))) &&
61 !(rdmsr(IA32_MISC_ENABLE
).hi
& (1 << (38 - 32)))) {
63 params
->turbo
= SPEEDSTEP_STATE_FROM_MSR(msr
.hi
, state_mask
);
64 params
->turbo
.is_turbo
= 1;
67 /* Set power limits by processor type. */
68 /* Defined values match the normal voltage versions only. But
69 they are only a hint for OSPM, so this should not hurt much. */
73 params
->min
.power
= SPEEDSTEP_MIN_POWER_YONAH
;
74 params
->max
.power
= SPEEDSTEP_MAX_POWER_YONAH
;
78 params
->slfm
.power
= SPEEDSTEP_SLFM_POWER_PENRYN
;
79 params
->min
.power
= SPEEDSTEP_MIN_POWER_PENRYN
;
80 params
->max
.power
= SPEEDSTEP_MAX_POWER_PENRYN
;
81 params
->turbo
.power
= SPEEDSTEP_MAX_POWER_PENRYN
;
86 /* Use Merom values by default (as before). */
87 params
->slfm
.power
= SPEEDSTEP_SLFM_POWER_MEROM
;
88 params
->min
.power
= SPEEDSTEP_MIN_POWER_MEROM
;
89 params
->max
.power
= SPEEDSTEP_MAX_POWER_MEROM
;
90 params
->turbo
.power
= SPEEDSTEP_MAX_POWER_MEROM
;
96 * @brief Generate full p-states table from processor parameters
98 * This is generic code and should work at least for Merom and Penryn
99 * processors. It is used to generate ACPI tables and configure EMTTM.
101 void speedstep_gen_pstates(sst_table_t
*const table
)
104 /* Gather speedstep limits. */
105 speedstep_get_limits(¶ms
);
107 /*\ First, find the number of normal states: \*/
109 /* Calculate with doubled values to work
110 around non-integer (.5) bus ratios. */
111 const int power_diff2
= (params
.max
.power
- params
.min
.power
) * 2;
112 const int vid_diff2
= (params
.max
.vid
- params
.min
.vid
) * 2;
113 const int max_ratio2
= SPEEDSTEP_DOUBLE_RATIO(params
.max
);
114 const int min_ratio2
= SPEEDSTEP_DOUBLE_RATIO(params
.min
);
115 const int ratio_diff2
= max_ratio2
- min_ratio2
;
116 /* Calculate number of normal states (LFM to HFM, min to max). */
117 /* Increase step size, until all states fit into the table.
118 (Note: First try should always work, if
119 SPEEDSTEP_MAX_NORMAL_STATES is set correctly.) */
120 int states
, step2
= 0;
122 step2
+= 2 * 2; /* Must be a multiple of 2 (doubled). */
123 states
= ratio_diff2
/ step2
+ 1;
124 } while (states
> SPEEDSTEP_MAX_NORMAL_STATES
);
126 printk(BIOS_INFO
, "Enhanced Speedstep processor with "
127 "more than %d possible p-states.\n",
128 SPEEDSTEP_MAX_NORMAL_STATES
);
129 if (states
< 2) /* Report at least two normal states. */
132 /*\ Now, fill the table: \*/
134 table
->num_states
= 0;
136 /* Add turbo state if supported. */
137 if (params
.turbo
.is_turbo
)
138 table
->states
[table
->num_states
++] = params
.turbo
;
141 table
->states
[table
->num_states
] = params
.max
;
142 /* Work around HFM and LFM having the same bus ratio. */
143 if ((params
.max
.dynfsb
== params
.min
.dynfsb
) &&
144 (params
.max
.nonint
== params
.min
.nonint
) &&
145 (params
.max
.ratio
== params
.min
.ratio
))
146 table
->states
[table
->num_states
].vid
= params
.min
.vid
;
150 /* Now, add all other normal states based on LFM (min). */
151 const int power_step
= (power_diff2
/ states
) / 2;
152 const int vid_step
= (vid_diff2
/ states
) / 2;
153 const int ratio_step
= step2
/ 2;
154 int power
= params
.min
.power
+ (states
- 1) * power_step
;
155 int vid
= params
.min
.vid
+ (states
- 1) * vid_step
;
156 int ratio
= params
.min
.ratio
+ (states
- 1) * ratio_step
;
157 for (; states
> 0; --states
) {
158 table
->states
[table
->num_states
++] =
159 (sst_state_t
){ 0, 0, ratio
, vid
, 0, 0, power
};
165 /* At last, add Super-LFM state if supported. */
166 if (params
.slfm
.is_slfm
)
167 table
->states
[table
->num_states
++] = params
.slfm
;