blob: 7c99df36c08b4533722318bc04e4997c91fca6f7 [file] [log] [blame]
Angel Ponsf23ae0b2020-04-02 23:48:12 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin76c37002012-10-30 09:03:43 -05002
3#include <types.h>
4#include <console/console.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07005#include <acpi/acpi.h>
6#include <acpi/acpigen.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05007#include <arch/cpu.h>
8#include <cpu/x86/msr.h>
9#include <cpu/intel/speedstep.h>
10#include <cpu/intel/turbo.h>
11#include <device/device.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050012#include "haswell.h"
13#include "chip.h"
14
Duncan Laurie1ad55642013-03-07 14:08:04 -080015#include <southbridge/intel/lynxpoint/pch.h>
16
Angel Ponsba5761a2020-10-28 18:50:26 +010017static int cstate_set_lp[3] = {
Angel Ponsbda1c552020-10-29 00:08:24 +010018 C_STATE_C1E,
19 C_STATE_C3,
20 C_STATE_C7S_LONG_LAT,
Angel Ponsba5761a2020-10-28 18:50:26 +010021};
22
23static int cstate_set_trad[3] = {
Angel Ponsbda1c552020-10-29 00:08:24 +010024 C_STATE_C1,
25 C_STATE_C3,
26 C_STATE_C6_LONG_LAT,
Angel Ponsba5761a2020-10-28 18:50:26 +010027};
28
Aaron Durbin76c37002012-10-30 09:03:43 -050029static int get_cores_per_package(void)
30{
31 struct cpuinfo_x86 c;
32 struct cpuid_result result;
33 int cores = 1;
34
35 get_fms(&c, cpuid_eax(1));
36 if (c.x86 != 6)
37 return 1;
38
39 result = cpuid_ext(0xb, 1);
40 cores = result.ebx & 0xff;
41
42 return cores;
43}
44
Aaron Durbin76c37002012-10-30 09:03:43 -050045static acpi_tstate_t tss_table_fine[] = {
46 { 100, 1000, 0, 0x00, 0 },
47 { 94, 940, 0, 0x1f, 0 },
48 { 88, 880, 0, 0x1e, 0 },
49 { 82, 820, 0, 0x1d, 0 },
50 { 75, 760, 0, 0x1c, 0 },
51 { 69, 700, 0, 0x1b, 0 },
52 { 63, 640, 0, 0x1a, 0 },
53 { 57, 580, 0, 0x19, 0 },
54 { 50, 520, 0, 0x18, 0 },
55 { 44, 460, 0, 0x17, 0 },
56 { 38, 400, 0, 0x16, 0 },
57 { 32, 340, 0, 0x15, 0 },
58 { 25, 280, 0, 0x14, 0 },
59 { 19, 220, 0, 0x13, 0 },
60 { 13, 160, 0, 0x12, 0 },
61};
62
63static acpi_tstate_t tss_table_coarse[] = {
64 { 100, 1000, 0, 0x00, 0 },
65 { 88, 875, 0, 0x1f, 0 },
66 { 75, 750, 0, 0x1e, 0 },
67 { 63, 625, 0, 0x1d, 0 },
68 { 50, 500, 0, 0x1c, 0 },
69 { 38, 375, 0, 0x1b, 0 },
70 { 25, 250, 0, 0x1a, 0 },
71 { 13, 125, 0, 0x19, 0 },
72};
73
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +010074static void generate_T_state_entries(int core, int cores_per_package)
Aaron Durbin76c37002012-10-30 09:03:43 -050075{
Aaron Durbin76c37002012-10-30 09:03:43 -050076 /* Indicate SW_ALL coordination for T-states */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +010077 acpigen_write_TSD_package(core, cores_per_package, SW_ALL);
Aaron Durbin76c37002012-10-30 09:03:43 -050078
79 /* Indicate FFixedHW so OS will use MSR */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +010080 acpigen_write_empty_PTC();
Aaron Durbin76c37002012-10-30 09:03:43 -050081
82 /* Set a T-state limit that can be modified in NVS */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +010083 acpigen_write_TPC("\\TLVL");
Aaron Durbin76c37002012-10-30 09:03:43 -050084
85 /*
86 * CPUID.(EAX=6):EAX[5] indicates support
87 * for extended throttle levels.
88 */
89 if (cpuid_eax(6) & (1 << 5))
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +010090 acpigen_write_TSS_package(
Aaron Durbin76c37002012-10-30 09:03:43 -050091 ARRAY_SIZE(tss_table_fine), tss_table_fine);
92 else
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +010093 acpigen_write_TSS_package(
Aaron Durbin76c37002012-10-30 09:03:43 -050094 ARRAY_SIZE(tss_table_coarse), tss_table_coarse);
Aaron Durbin76c37002012-10-30 09:03:43 -050095}
96
Angel Pons2aaf7c02020-09-24 18:03:18 +020097static void generate_C_state_entries(void)
98{
Angel Ponsba5761a2020-10-28 18:50:26 +010099 acpi_cstate_t map[3];
100 int *set;
101 int i;
102
Angel Pons2aaf7c02020-09-24 18:03:18 +0200103 struct cpu_info *info;
104 struct cpu_driver *cpu;
Angel Pons2aaf7c02020-09-24 18:03:18 +0200105
106 /* Find CPU map of supported C-states */
107 info = cpu_info();
108 if (!info)
109 return;
110 cpu = find_cpu_driver(info->cpu);
111 if (!cpu || !cpu->cstates)
112 return;
113
Angel Ponsba5761a2020-10-28 18:50:26 +0100114 if (haswell_is_ult())
115 set = cstate_set_lp;
116 else
117 set = cstate_set_trad;
Angel Pons2aaf7c02020-09-24 18:03:18 +0200118
Angel Ponsba5761a2020-10-28 18:50:26 +0100119 for (i = 0; i < ARRAY_SIZE(map); i++) {
120 map[i] = cpu->cstates[set[i]];
121 map[i].ctype = i + 1;
122 }
Angel Pons2aaf7c02020-09-24 18:03:18 +0200123
Angel Ponsba5761a2020-10-28 18:50:26 +0100124 /* Generate C-state tables */
125 acpigen_write_CST_package(map, ARRAY_SIZE(map));
Angel Pons2aaf7c02020-09-24 18:03:18 +0200126}
127
Aaron Durbin76c37002012-10-30 09:03:43 -0500128static int calculate_power(int tdp, int p1_ratio, int ratio)
129{
130 u32 m;
131 u32 power;
132
133 /*
134 * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
135 *
136 * Power = (ratio / p1_ratio) * m * tdp
137 */
138
139 m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
140 m = (m * m) / 1000;
141
142 power = ((ratio * 100000 / p1_ratio) / 100);
143 power *= (m / 100) * (tdp / 1000);
144 power /= 1000;
145
146 return (int)power;
147}
148
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100149static void generate_P_state_entries(int core, int cores_per_package)
Aaron Durbin76c37002012-10-30 09:03:43 -0500150{
Aaron Durbin76c37002012-10-30 09:03:43 -0500151 int ratio_min, ratio_max, ratio_turbo, ratio_step;
152 int coord_type, power_max, power_unit, num_entries;
153 int ratio, power, clock, clock_max;
154 msr_t msr;
155
156 /* Determine P-state coordination type from MISC_PWR_MGMT[0] */
157 msr = rdmsr(MSR_MISC_PWR_MGMT);
158 if (msr.lo & MISC_PWR_MGMT_EIST_HW_DIS)
159 coord_type = SW_ANY;
160 else
161 coord_type = HW_ALL;
162
163 /* Get bus ratio limits and calculate clock speeds */
164 msr = rdmsr(MSR_PLATFORM_INFO);
165 ratio_min = (msr.hi >> (40-32)) & 0xff; /* Max Efficiency Ratio */
166
167 /* Determine if this CPU has configurable TDP */
168 if (cpu_config_tdp_levels()) {
169 /* Set max ratio to nominal TDP ratio */
170 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
171 ratio_max = msr.lo & 0xff;
172 } else {
173 /* Max Non-Turbo Ratio */
174 ratio_max = (msr.lo >> 8) & 0xff;
175 }
Angel Ponsca965492020-10-28 19:15:36 +0100176 clock_max = ratio_max * CPU_BCLK;
Aaron Durbin76c37002012-10-30 09:03:43 -0500177
178 /* Calculate CPU TDP in mW */
179 msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
180 power_unit = 2 << ((msr.lo & 0xf) - 1);
181 msr = rdmsr(MSR_PKG_POWER_SKU);
182 power_max = ((msr.lo & 0x7fff) / power_unit) * 1000;
183
184 /* Write _PCT indicating use of FFixedHW */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100185 acpigen_write_empty_PCT();
Aaron Durbin76c37002012-10-30 09:03:43 -0500186
187 /* Write _PPC with no limit on supported P-state */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100188 acpigen_write_PPC_NVS();
Aaron Durbin76c37002012-10-30 09:03:43 -0500189
190 /* Write PSD indicating configured coordination type */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100191 acpigen_write_PSD_package(core, 1, coord_type);
Aaron Durbin76c37002012-10-30 09:03:43 -0500192
193 /* Add P-state entries in _PSS table */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100194 acpigen_write_name("_PSS");
Aaron Durbin76c37002012-10-30 09:03:43 -0500195
196 /* Determine ratio points */
197 ratio_step = PSS_RATIO_STEP;
198 num_entries = (ratio_max - ratio_min) / ratio_step;
199 while (num_entries > PSS_MAX_ENTRIES-1) {
200 ratio_step <<= 1;
201 num_entries >>= 1;
202 }
203
204 /* P[T] is Turbo state if enabled */
205 if (get_turbo_state() == TURBO_ENABLED) {
206 /* _PSS package count including Turbo */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100207 acpigen_write_package(num_entries + 2);
Aaron Durbin76c37002012-10-30 09:03:43 -0500208
209 msr = rdmsr(MSR_TURBO_RATIO_LIMIT);
210 ratio_turbo = msr.lo & 0xff;
211
212 /* Add entry for Turbo ratio */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100213 acpigen_write_PSS_package(
Aaron Durbin76c37002012-10-30 09:03:43 -0500214 clock_max + 1, /*MHz*/
215 power_max, /*mW*/
216 PSS_LATENCY_TRANSITION, /*lat1*/
217 PSS_LATENCY_BUSMASTER, /*lat2*/
218 ratio_turbo << 8, /*control*/
219 ratio_turbo << 8); /*status*/
220 } else {
221 /* _PSS package count without Turbo */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100222 acpigen_write_package(num_entries + 1);
Aaron Durbin76c37002012-10-30 09:03:43 -0500223 }
224
225 /* First regular entry is max non-turbo ratio */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100226 acpigen_write_PSS_package(
Aaron Durbin76c37002012-10-30 09:03:43 -0500227 clock_max, /*MHz*/
228 power_max, /*mW*/
229 PSS_LATENCY_TRANSITION, /*lat1*/
230 PSS_LATENCY_BUSMASTER, /*lat2*/
231 ratio_max << 8, /*control*/
232 ratio_max << 8); /*status*/
233
234 /* Generate the remaining entries */
235 for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
236 ratio >= ratio_min; ratio -= ratio_step) {
237
238 /* Calculate power at this ratio */
239 power = calculate_power(power_max, ratio_max, ratio);
Angel Ponsca965492020-10-28 19:15:36 +0100240 clock = ratio * CPU_BCLK;
Aaron Durbin76c37002012-10-30 09:03:43 -0500241
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100242 acpigen_write_PSS_package(
Aaron Durbin76c37002012-10-30 09:03:43 -0500243 clock, /*MHz*/
244 power, /*mW*/
245 PSS_LATENCY_TRANSITION, /*lat1*/
246 PSS_LATENCY_BUSMASTER, /*lat2*/
247 ratio << 8, /*control*/
248 ratio << 8); /*status*/
249 }
250
251 /* Fix package length */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100252 acpigen_pop_len();
Aaron Durbin76c37002012-10-30 09:03:43 -0500253}
254
Furquan Shaikh7536a392020-04-24 21:59:21 -0700255void generate_cpu_entries(const struct device *device)
Aaron Durbin76c37002012-10-30 09:03:43 -0500256{
Duncan Laurie1ad55642013-03-07 14:08:04 -0800257 int coreID, cpuID, pcontrol_blk = get_pmbase(), plen = 6;
Aaron Durbin76c37002012-10-30 09:03:43 -0500258 int totalcores = dev_count_cpu();
259 int cores_per_package = get_cores_per_package();
260 int numcpus = totalcores/cores_per_package;
261
262 printk(BIOS_DEBUG, "Found %d CPU(s) with %d core(s) each.\n",
263 numcpus, cores_per_package);
264
Martin Roth9944b282014-08-11 11:24:55 -0600265 for (cpuID = 1; cpuID <= numcpus; cpuID++) {
Lee Leahy9d62e7e2017-03-15 17:40:50 -0700266 for (coreID = 1; coreID <= cores_per_package; coreID++) {
267 if (coreID > 1) {
Aaron Durbin76c37002012-10-30 09:03:43 -0500268 pcontrol_blk = 0;
269 plen = 0;
270 }
271
Christian Walterbe3979c2019-12-18 15:07:59 +0100272 /* Generate processor \_SB.CPUx */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100273 acpigen_write_processor(
Angel Pons2aaf7c02020-09-24 18:03:18 +0200274 (cpuID - 1) * cores_per_package+coreID - 1,
Aaron Durbin76c37002012-10-30 09:03:43 -0500275 pcontrol_blk, plen);
276
277 /* Generate P-state tables */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100278 generate_P_state_entries(
Angel Pons2aaf7c02020-09-24 18:03:18 +0200279 coreID - 1, cores_per_package);
Aaron Durbin76c37002012-10-30 09:03:43 -0500280
281 /* Generate C-state tables */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100282 generate_C_state_entries();
Aaron Durbin76c37002012-10-30 09:03:43 -0500283
284 /* Generate T-state tables */
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100285 generate_T_state_entries(
Angel Pons2aaf7c02020-09-24 18:03:18 +0200286 cpuID - 1, cores_per_package);
Aaron Durbin76c37002012-10-30 09:03:43 -0500287
Vladimir Serbinenkobe0fd0a2014-11-04 21:10:59 +0100288 acpigen_pop_len();
Aaron Durbin76c37002012-10-30 09:03:43 -0500289 }
290 }
Arthur Heymansc54d14f2018-11-28 12:09:23 +0100291
292 /* PPKG is usually used for thermal management
293 of the first and only package. */
294 acpigen_write_processor_package("PPKG", 0, cores_per_package);
295
296 /* Add a method to notify processor nodes */
297 acpigen_write_processor_cnot(cores_per_package);
Aaron Durbin76c37002012-10-30 09:03:43 -0500298}
299
300struct chip_operations cpu_intel_haswell_ops = {
301 CHIP_NAME("Intel Haswell CPU")
302};