blob: c4f58397e8dc6671ff1b0abbc0d81fe4ff620752 [file] [log] [blame]
Angel Ponsf23ae0b2020-04-02 23:48:12 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer5c554632012-04-04 00:09:50 +02002
Furquan Shaikh76cedd22020-05-02 10:24:23 -07003#include <acpi/acpi.h>
4#include <acpi/acpigen.h>
Elyes Haouasad65e8c2022-10-31 14:02:13 +01005#include <console/console.h>
6#include <cpu/cpu.h>
Stefan Reinauer5c554632012-04-04 00:09:50 +02007#include <cpu/intel/speedstep.h>
8#include <cpu/intel/turbo.h>
Elyes Haouasad65e8c2022-10-31 14:02:13 +01009#include <cpu/x86/msr.h>
Stefan Reinauer5c554632012-04-04 00:09:50 +020010#include <device/device.h>
Elyes HAOUAS7cf1f202020-07-22 07:53:53 +020011#include <stdint.h>
12
Stefan Reinauer5c554632012-04-04 00:09:50 +020013#include "model_206ax.h"
14#include "chip.h"
15
Patrick Rudolph588c6f02023-09-30 10:45:33 +020016#define MWAIT_RES(state, sub_state) \
17 { \
18 .addrl = (((state) << 4) | (sub_state)), \
19 .space_id = ACPI_ADDRESS_SPACE_FIXED, \
20 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL, \
21 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT, \
22 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD, \
23 }
24
Angel Pons85790d02021-01-21 21:12:27 +010025/*
26 * List of supported C-states in this processor
27 *
28 * Latencies are typical worst-case package exit time in uS
29 * taken from the SandyBridge BIOS specification.
30 */
Patrick Rudolph588c6f02023-09-30 10:45:33 +020031static acpi_cstate_t cstate_map[NUM_C_STATES] = {
32 [C_STATE_C0] = { },
33 [C_STATE_C1] = {
Angel Pons85790d02021-01-21 21:12:27 +010034 .latency = 1,
35 .power = 1000,
Patrick Rudolph588c6f02023-09-30 10:45:33 +020036 .resource = MWAIT_RES(0, 0),
Angel Pons85790d02021-01-21 21:12:27 +010037 },
Patrick Rudolph588c6f02023-09-30 10:45:33 +020038 [C_STATE_C1E] = {
Angel Pons85790d02021-01-21 21:12:27 +010039 .latency = 1,
40 .power = 1000,
Patrick Rudolph588c6f02023-09-30 10:45:33 +020041 .resource = MWAIT_RES(0, 1),
Angel Pons85790d02021-01-21 21:12:27 +010042 },
Patrick Rudolph588c6f02023-09-30 10:45:33 +020043 [C_STATE_C3] = {
Angel Pons85790d02021-01-21 21:12:27 +010044 .latency = 63,
45 .power = 500,
Patrick Rudolph588c6f02023-09-30 10:45:33 +020046 .resource = MWAIT_RES(1, 0),
Angel Pons85790d02021-01-21 21:12:27 +010047 },
Patrick Rudolph588c6f02023-09-30 10:45:33 +020048 [C_STATE_C6] = {
Angel Pons85790d02021-01-21 21:12:27 +010049 .latency = 87,
50 .power = 350,
Patrick Rudolph588c6f02023-09-30 10:45:33 +020051 .resource = MWAIT_RES(2, 0),
Angel Pons85790d02021-01-21 21:12:27 +010052 },
Patrick Rudolph588c6f02023-09-30 10:45:33 +020053 [C_STATE_C7] = {
Angel Pons85790d02021-01-21 21:12:27 +010054 .latency = 90,
55 .power = 200,
Patrick Rudolph588c6f02023-09-30 10:45:33 +020056 .resource = MWAIT_RES(3, 0),
Angel Pons85790d02021-01-21 21:12:27 +010057 },
Patrick Rudolph588c6f02023-09-30 10:45:33 +020058 [C_STATE_C7S] = {
Angel Pons85790d02021-01-21 21:12:27 +010059 .latency = 90,
60 .power = 200,
Patrick Rudolph588c6f02023-09-30 10:45:33 +020061 .resource = MWAIT_RES(3, 1),
Angel Pons85790d02021-01-21 21:12:27 +010062 },
63};
64
Patrick Rudolph13064322023-09-25 08:10:58 +020065static const char *const c_state_names[] = {"C0", "C1", "C1E", "C3", "C6", "C7", "C7S"};
66
Evgeny Zinoviev920d2b72020-06-16 08:23:09 +030067static int get_logical_cores_per_package(void)
Stefan Reinauer5c554632012-04-04 00:09:50 +020068{
Evgeny Zinoviev920d2b72020-06-16 08:23:09 +030069 msr_t msr = rdmsr(MSR_CORE_THREAD_COUNT);
70 return msr.lo & 0xffff;
Stefan Reinauer5c554632012-04-04 00:09:50 +020071}
72
Patrick Rudolph13064322023-09-25 08:10:58 +020073static void print_supported_cstates(void)
74{
75 uint8_t state, substate;
76
77 printk(BIOS_DEBUG, "Supported C-states: ");
78
79 for (size_t i = 0; i < ARRAY_SIZE(cstate_map); i++) {
80 state = (cstate_map[i].resource.addrl >> 4) + 1;
81 substate = cstate_map[i].resource.addrl & 0xf;
82
83 /* CPU C0 is always supported */
84 if (i == 0 || cpu_get_c_substate_support(state) > substate)
85 printk(BIOS_DEBUG, " %s", c_state_names[i]);
86 }
87 printk(BIOS_DEBUG, "\n");
88}
89
Arthur Heymanscdb26fd2021-11-15 20:12:02 +010090static void generate_C_state_entries(const struct device *dev)
Stefan Reinauer5c554632012-04-04 00:09:50 +020091{
Arthur Heymanse64b8ac2022-12-12 19:28:44 +010092 struct cpu_intel_model_206ax_config *conf = dev->chip_info;
Stefan Reinauer5c554632012-04-04 00:09:50 +020093
Angel Ponsd8b9e562021-01-04 17:37:46 +010094 const int acpi_cstates[3] = { conf->acpi_c1, conf->acpi_c2, conf->acpi_c3 };
95
96 acpi_cstate_t acpi_cstate_map[ARRAY_SIZE(acpi_cstates)] = { 0 };
Angel Ponsd8b9e562021-01-04 17:37:46 +010097 /* Count number of active C-states */
98 int count = 0;
99
100 for (int i = 0; i < ARRAY_SIZE(acpi_cstates); i++) {
Angel Pons85790d02021-01-21 21:12:27 +0100101 if (acpi_cstates[i] > 0 && acpi_cstates[i] < ARRAY_SIZE(cstate_map)) {
102 acpi_cstate_map[count] = cstate_map[acpi_cstates[i]];
Angel Ponsd8b9e562021-01-04 17:37:46 +0100103 acpi_cstate_map[count].ctype = i + 1;
104 count++;
105 }
106 }
107 acpigen_write_CST_package(acpi_cstate_map, count);
Stefan Reinauer5c554632012-04-04 00:09:50 +0200108}
109
110static acpi_tstate_t tss_table_fine[] = {
111 { 100, 1000, 0, 0x00, 0 },
112 { 94, 940, 0, 0x1f, 0 },
113 { 88, 880, 0, 0x1e, 0 },
114 { 82, 820, 0, 0x1d, 0 },
115 { 75, 760, 0, 0x1c, 0 },
116 { 69, 700, 0, 0x1b, 0 },
117 { 63, 640, 0, 0x1a, 0 },
118 { 57, 580, 0, 0x19, 0 },
119 { 50, 520, 0, 0x18, 0 },
120 { 44, 460, 0, 0x17, 0 },
121 { 38, 400, 0, 0x16, 0 },
122 { 32, 340, 0, 0x15, 0 },
123 { 25, 280, 0, 0x14, 0 },
124 { 19, 220, 0, 0x13, 0 },
125 { 13, 160, 0, 0x12, 0 },
126};
127
128static acpi_tstate_t tss_table_coarse[] = {
129 { 100, 1000, 0, 0x00, 0 },
130 { 88, 875, 0, 0x1f, 0 },
131 { 75, 750, 0, 0x1e, 0 },
132 { 63, 625, 0, 0x1d, 0 },
133 { 50, 500, 0, 0x1c, 0 },
134 { 38, 375, 0, 0x1b, 0 },
135 { 25, 250, 0, 0x1a, 0 },
136 { 13, 125, 0, 0x19, 0 },
137};
138
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100139static void generate_T_state_entries(int core, int cores_per_package)
Stefan Reinauer5c554632012-04-04 00:09:50 +0200140{
Stefan Reinauer5c554632012-04-04 00:09:50 +0200141 /* Indicate SW_ALL coordination for T-states */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100142 acpigen_write_TSD_package(core, cores_per_package, SW_ALL);
Stefan Reinauer5c554632012-04-04 00:09:50 +0200143
144 /* Indicate FFixedHW so OS will use MSR */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100145 acpigen_write_empty_PTC();
Stefan Reinauer5c554632012-04-04 00:09:50 +0200146
147 /* Set a T-state limit that can be modified in NVS */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100148 acpigen_write_TPC("\\TLVL");
Stefan Reinauer5c554632012-04-04 00:09:50 +0200149
150 /*
151 * CPUID.(EAX=6):EAX[5] indicates support
152 * for extended throttle levels.
153 */
154 if (cpuid_eax(6) & (1 << 5))
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100155 acpigen_write_TSS_package(
Stefan Reinauer5c554632012-04-04 00:09:50 +0200156 ARRAY_SIZE(tss_table_fine), tss_table_fine);
157 else
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100158 acpigen_write_TSS_package(
Stefan Reinauer5c554632012-04-04 00:09:50 +0200159 ARRAY_SIZE(tss_table_coarse), tss_table_coarse);
Stefan Reinauer5c554632012-04-04 00:09:50 +0200160}
161
162static int calculate_power(int tdp, int p1_ratio, int ratio)
163{
164 u32 m;
165 u32 power;
166
167 /*
168 * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
169 *
170 * Power = (ratio / p1_ratio) * m * tdp
171 */
172
173 m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
174 m = (m * m) / 1000;
175
176 power = ((ratio * 100000 / p1_ratio) / 100);
177 power *= (m / 100) * (tdp / 1000);
178 power /= 1000;
179
180 return (int)power;
181}
182
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100183static void generate_P_state_entries(int core, int cores_per_package)
Stefan Reinauer5c554632012-04-04 00:09:50 +0200184{
Stefan Reinauer5c554632012-04-04 00:09:50 +0200185 int ratio_min, ratio_max, ratio_turbo, ratio_step;
186 int coord_type, power_max, power_unit, num_entries;
187 int ratio, power, clock, clock_max;
188 msr_t msr;
189
190 /* Determine P-state coordination type from MISC_PWR_MGMT[0] */
191 msr = rdmsr(MSR_MISC_PWR_MGMT);
192 if (msr.lo & MISC_PWR_MGMT_EIST_HW_DIS)
193 coord_type = SW_ANY;
194 else
195 coord_type = HW_ALL;
196
197 /* Get bus ratio limits and calculate clock speeds */
198 msr = rdmsr(MSR_PLATFORM_INFO);
199 ratio_min = (msr.hi >> (40-32)) & 0xff; /* Max Efficiency Ratio */
Duncan Laurie77dbbac2012-06-25 09:51:59 -0700200
201 /* Determine if this CPU has configurable TDP */
202 if (cpu_config_tdp_levels()) {
203 /* Set max ratio to nominal TDP ratio */
204 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
205 ratio_max = msr.lo & 0xff;
206 } else {
207 /* Max Non-Turbo Ratio */
208 ratio_max = (msr.lo >> 8) & 0xff;
209 }
Stefan Reinauer5c554632012-04-04 00:09:50 +0200210 clock_max = ratio_max * SANDYBRIDGE_BCLK;
211
212 /* Calculate CPU TDP in mW */
213 msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
214 power_unit = 2 << ((msr.lo & 0xf) - 1);
215 msr = rdmsr(MSR_PKG_POWER_SKU);
216 power_max = ((msr.lo & 0x7fff) / power_unit) * 1000;
217
218 /* Write _PCT indicating use of FFixedHW */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100219 acpigen_write_empty_PCT();
Stefan Reinauer5c554632012-04-04 00:09:50 +0200220
221 /* Write _PPC with no limit on supported P-state */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100222 acpigen_write_PPC_NVS();
Stefan Reinauer5c554632012-04-04 00:09:50 +0200223
224 /* Write PSD indicating configured coordination type */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100225 acpigen_write_PSD_package(core, cores_per_package, coord_type);
Stefan Reinauer5c554632012-04-04 00:09:50 +0200226
227 /* Add P-state entries in _PSS table */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100228 acpigen_write_name("_PSS");
Stefan Reinauer5c554632012-04-04 00:09:50 +0200229
230 /* Determine ratio points */
231 ratio_step = PSS_RATIO_STEP;
232 num_entries = (ratio_max - ratio_min) / ratio_step;
233 while (num_entries > PSS_MAX_ENTRIES-1) {
234 ratio_step <<= 1;
235 num_entries >>= 1;
236 }
237
238 /* P[T] is Turbo state if enabled */
239 if (get_turbo_state() == TURBO_ENABLED) {
240 /* _PSS package count including Turbo */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100241 acpigen_write_package(num_entries + 2);
Stefan Reinauer5c554632012-04-04 00:09:50 +0200242
243 msr = rdmsr(MSR_TURBO_RATIO_LIMIT);
244 ratio_turbo = msr.lo & 0xff;
245
246 /* Add entry for Turbo ratio */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100247 acpigen_write_PSS_package(
Stefan Reinauer5c554632012-04-04 00:09:50 +0200248 clock_max + 1, /*MHz*/
249 power_max, /*mW*/
250 PSS_LATENCY_TRANSITION, /*lat1*/
251 PSS_LATENCY_BUSMASTER, /*lat2*/
252 ratio_turbo << 8, /*control*/
253 ratio_turbo << 8); /*status*/
254 } else {
255 /* _PSS package count without Turbo */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100256 acpigen_write_package(num_entries + 1);
Stefan Reinauer5c554632012-04-04 00:09:50 +0200257 }
258
259 /* First regular entry is max non-turbo ratio */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100260 acpigen_write_PSS_package(
Stefan Reinauer5c554632012-04-04 00:09:50 +0200261 clock_max, /*MHz*/
262 power_max, /*mW*/
263 PSS_LATENCY_TRANSITION, /*lat1*/
264 PSS_LATENCY_BUSMASTER, /*lat2*/
265 ratio_max << 8, /*control*/
266 ratio_max << 8); /*status*/
267
268 /* Generate the remaining entries */
269 for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
270 ratio >= ratio_min; ratio -= ratio_step) {
Stefan Reinauer5c554632012-04-04 00:09:50 +0200271 /* Calculate power at this ratio */
272 power = calculate_power(power_max, ratio_max, ratio);
273 clock = ratio * SANDYBRIDGE_BCLK;
274
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100275 acpigen_write_PSS_package(
Stefan Reinauer5c554632012-04-04 00:09:50 +0200276 clock, /*MHz*/
277 power, /*mW*/
278 PSS_LATENCY_TRANSITION, /*lat1*/
279 PSS_LATENCY_BUSMASTER, /*lat2*/
280 ratio << 8, /*control*/
281 ratio << 8); /*status*/
282 }
283
284 /* Fix package length */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100285 acpigen_pop_len();
Stefan Reinauer5c554632012-04-04 00:09:50 +0200286}
287
Kyösti Mälkkid521b962023-04-12 21:44:49 +0300288static void generate_cpu_entry(const struct device *device, int cpu, int core, int cores_per_package)
289{
290 /* Generate Scope(\_SB) { Device(CPUx */
291 acpigen_write_processor_device(cpu * cores_per_package + core);
292
293 /* Generate P-state tables */
294 generate_P_state_entries(cpu, cores_per_package);
295
296 /* Generate C-state tables */
297 generate_C_state_entries(device);
298
299 /* Generate T-state tables */
300 generate_T_state_entries(cpu, cores_per_package);
301
302 acpigen_write_processor_device_end();
303}
304
Furquan Shaikh7536a392020-04-24 21:59:21 -0700305void generate_cpu_entries(const struct device *device)
Stefan Reinauer5c554632012-04-04 00:09:50 +0200306{
Stefan Reinauer5c554632012-04-04 00:09:50 +0200307 int totalcores = dev_count_cpu();
Evgeny Zinoviev920d2b72020-06-16 08:23:09 +0300308 int cores_per_package = get_logical_cores_per_package();
Kyösti Mälkkie39a3e32023-04-12 16:39:12 +0300309 int numcpus = totalcores / cores_per_package;
Stefan Reinauer5c554632012-04-04 00:09:50 +0200310
311 printk(BIOS_DEBUG, "Found %d CPU(s) with %d core(s) each.\n",
312 numcpus, cores_per_package);
313
Patrick Rudolph13064322023-09-25 08:10:58 +0200314 print_supported_cstates();
315
Kyösti Mälkkid521b962023-04-12 21:44:49 +0300316 for (int cpu_id = 0; cpu_id < numcpus; cpu_id++)
317 for (int core_id = 0; core_id < cores_per_package; core_id++)
318 generate_cpu_entry(device, cpu_id, core_id, cores_per_package);
Arthur Heymans04008a92018-11-28 12:13:54 +0100319
320 /* PPKG is usually used for thermal management
321 of the first and only package. */
322 acpigen_write_processor_package("PPKG", 0, cores_per_package);
323
324 /* Add a method to notify processor nodes */
325 acpigen_write_processor_cnot(cores_per_package);
Stefan Reinauer5c554632012-04-04 00:09:50 +0200326}
327
328struct chip_operations cpu_intel_model_206ax_ops = {
Stefan Reinauer0b7b7b62012-07-10 17:13:04 -0700329 CHIP_NAME("Intel SandyBridge/IvyBridge CPU")
Stefan Reinauer5c554632012-04-04 00:09:50 +0200330};