blob: b91134fe20c82a30a8ffd557a8b8d9120f6376a8 [file] [log] [blame]
Angel Ponsc3f58f62020-04-05 15:46:41 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin61cd57b2013-10-30 14:36:11 -05002
Furquan Shaikh76cedd22020-05-02 10:24:23 -07003#include <acpi/acpi.h>
4#include <acpi/acpigen.h>
Angel Ponse0e28902020-08-03 13:26:21 +02005#include <arch/ioapic.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02006#include <device/mmio.h>
Aaron Durbin1af36632013-11-07 10:42:16 -06007#include <arch/smp/mpspec.h>
8#include <console/console.h>
Aaron Durbin303525b2013-11-05 11:42:32 -06009#include <cpu/x86/smm.h>
Aaron Durbin61cd57b2013-10-30 14:36:11 -050010#include <types.h>
Duncan Laurie8923be52013-11-05 13:02:30 -080011#include <cpu/x86/msr.h>
Duncan Laurie8923be52013-11-05 13:02:30 -080012#include <cpu/intel/turbo.h>
Aaron Durbin61cd57b2013-10-30 14:36:11 -050013
Julius Werner18ea2d32014-10-07 16:42:17 -070014#include <soc/acpi.h>
15#include <soc/iomap.h>
16#include <soc/irq.h>
17#include <soc/msr.h>
18#include <soc/pattrs.h>
Angel Ponsb5320b22020-07-07 18:27:30 +020019#include <soc/pm.h>
Aaron Durbin61cd57b2013-10-30 14:36:11 -050020
Duncan Laurie8923be52013-11-05 13:02:30 -080021#define MWAIT_RES(state, sub_state) \
22 { \
23 .addrl = (((state) << 4) | (sub_state)), \
24 .space_id = ACPI_ADDRESS_SPACE_FIXED, \
25 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL, \
26 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT, \
27 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD, \
28 }
29
30/* C-state map without S0ix */
31static acpi_cstate_t cstate_map[] = {
32 {
33 /* C1 */
34 .ctype = 1, /* ACPI C1 */
35 .latency = 1,
36 .power = 1000,
37 .resource = MWAIT_RES(0, 0),
38 },
39 {
40 /* C6NS with no L2 shrink */
41 /* NOTE: this substate is above CPUID limit */
42 .ctype = 2, /* ACPI C2 */
43 .latency = 500,
44 .power = 10,
Duncan Laurie22f1dcd2013-12-02 10:14:47 -080045 .resource = MWAIT_RES(5, 1),
Duncan Laurie8923be52013-11-05 13:02:30 -080046 },
47 {
48 /* C6FS with full L2 shrink */
49 .ctype = 3, /* ACPI C3 */
50 .latency = 1500, /* 1.5ms worst case */
Aaron Durbin4177db52014-02-05 14:55:26 -060051 .power = 1,
Duncan Laurie8923be52013-11-05 13:02:30 -080052 .resource = MWAIT_RES(5, 2),
53 }
54};
55
Angel Pons91ca2dd2020-07-12 14:24:48 +020056int acpi_sci_irq(void)
Aaron Durbin1af36632013-11-07 10:42:16 -060057{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080058 u32 *actl = (u32 *)(ILB_BASE_ADDRESS + ACTL);
Aaron Durbin1af36632013-11-07 10:42:16 -060059 int scis;
60 static int sci_irq;
61
62 if (sci_irq)
63 return sci_irq;
64
65 /* Determine how SCI is routed. */
66 scis = read32(actl) & SCIS_MASK;
67 switch (scis) {
68 case SCIS_IRQ9:
69 case SCIS_IRQ10:
70 case SCIS_IRQ11:
71 sci_irq = scis - SCIS_IRQ9 + 9;
72 break;
73 case SCIS_IRQ20:
74 case SCIS_IRQ21:
75 case SCIS_IRQ22:
76 case SCIS_IRQ23:
77 sci_irq = scis - SCIS_IRQ20 + 20;
78 break;
79 default:
80 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
81 sci_irq = 9;
82 break;
83 }
84
85 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
86 return sci_irq;
87}
88
Duncan Laurie03ff2a22013-11-04 17:15:20 -080089unsigned long acpi_fill_mcfg(unsigned long current)
90{
91 current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current,
Kyösti Mälkki6d085442021-02-14 01:55:18 +020092 CONFIG_MMCONF_BASE_ADDRESS, 0, 0, CONFIG_MMCONF_BUS_NUMBER - 1);
Duncan Laurie03ff2a22013-11-04 17:15:20 -080093 return current;
94}
Aaron Durbin303525b2013-11-05 11:42:32 -060095
Angel Ponse0e28902020-08-03 13:26:21 +020096unsigned long acpi_fill_madt(unsigned long current)
97{
98 /* Local APICs */
99 current = acpi_create_madt_lapics(current);
100
101 /* IOAPIC */
102 current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current,
103 2, IO_APIC_ADDR, 0);
104
105 current = acpi_madt_irq_overrides(current);
106
107 return current;
108}
109
Angel Pons06e44a82020-07-07 17:34:21 +0200110static acpi_tstate_t soc_tss_table[] = {
Duncan Laurie8923be52013-11-05 13:02:30 -0800111 { 100, 1000, 0, 0x00, 0 },
Angel Pons06e44a82020-07-07 17:34:21 +0200112 { 88, 875, 0, 0x1e, 0 },
113 { 75, 750, 0, 0x1c, 0 },
114 { 63, 625, 0, 0x1a, 0 },
115 { 50, 500, 0, 0x18, 0 },
116 { 38, 375, 0, 0x16, 0 },
117 { 25, 250, 0, 0x14, 0 },
118 { 13, 125, 0, 0x12, 0 },
Duncan Laurie8923be52013-11-05 13:02:30 -0800119};
120
Angel Pons06e44a82020-07-07 17:34:21 +0200121static void generate_t_state_entries(int core, int cores_per_package)
Duncan Laurie8923be52013-11-05 13:02:30 -0800122{
Duncan Laurie8923be52013-11-05 13:02:30 -0800123 /* Indicate SW_ALL coordination for T-states */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200124 acpigen_write_TSD_package(core, cores_per_package, SW_ALL);
Duncan Laurie8923be52013-11-05 13:02:30 -0800125
126 /* Indicate FFixedHW so OS will use MSR */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200127 acpigen_write_empty_PTC();
Duncan Laurie8923be52013-11-05 13:02:30 -0800128
129 /* Set NVS controlled T-state limit */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200130 acpigen_write_TPC("\\TLVL");
Duncan Laurie8923be52013-11-05 13:02:30 -0800131
132 /* Write TSS table for MSR access */
Angel Pons06e44a82020-07-07 17:34:21 +0200133 acpigen_write_TSS_package(ARRAY_SIZE(soc_tss_table), soc_tss_table);
Duncan Laurie8923be52013-11-05 13:02:30 -0800134}
135
136static int calculate_power(int tdp, int p1_ratio, int ratio)
137{
Angel Pons06e44a82020-07-07 17:34:21 +0200138 u32 m, power;
Duncan Laurie8923be52013-11-05 13:02:30 -0800139
140 /*
141 * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
Duncan Laurie8923be52013-11-05 13:02:30 -0800142 */
143
144 m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
145 m = (m * m) / 1000;
146
Angel Pons06e44a82020-07-07 17:34:21 +0200147 /*
148 * Power = (ratio / p1_ratio) * m * TDP
149 */
Duncan Laurie8923be52013-11-05 13:02:30 -0800150 power = ((ratio * 100000 / p1_ratio) / 100);
151 power *= (m / 100) * (tdp / 1000);
152 power /= 1000;
153
154 return (int)power;
155}
156
Angel Pons06e44a82020-07-07 17:34:21 +0200157static void generate_p_state_entries(int core, int cores_per_package)
Duncan Laurie8923be52013-11-05 13:02:30 -0800158{
Duncan Laurie8923be52013-11-05 13:02:30 -0800159 int ratio_min, ratio_max, ratio_turbo, ratio_step, ratio_range_2;
160 int coord_type, power_max, power_unit, num_entries;
161 int ratio, power, clock, clock_max;
162 int vid, vid_turbo, vid_min, vid_max, vid_range_2;
163 u32 control_status;
164 const struct pattrs *pattrs = pattrs_get();
165 msr_t msr;
166
167 /* Inputs from CPU attributes */
168 ratio_max = pattrs->iacore_ratios[IACORE_MAX];
169 ratio_min = pattrs->iacore_ratios[IACORE_LFM];
170 vid_max = pattrs->iacore_vids[IACORE_MAX];
171 vid_min = pattrs->iacore_vids[IACORE_LFM];
172
Aaron Durbin4177db52014-02-05 14:55:26 -0600173 /* Set P-states coordination type based on MSR disable bit */
Duncan Laurie31ac9e32014-03-28 10:52:13 -0700174 coord_type = (pattrs->num_cpus > 2) ? SW_ALL : HW_ALL;
Duncan Laurie8923be52013-11-05 13:02:30 -0800175
176 /* Max Non-Turbo Frequency */
177 clock_max = (ratio_max * pattrs->bclk_khz) / 1000;
178
179 /* Calculate CPU TDP in mW */
180 msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
181 power_unit = 1 << (msr.lo & 0xf);
182 msr = rdmsr(MSR_PKG_POWER_LIMIT);
183 power_max = ((msr.lo & 0x7fff) / power_unit) * 1000;
184
185 /* Write _PCT indicating use of FFixedHW */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200186 acpigen_write_empty_PCT();
Duncan Laurie8923be52013-11-05 13:02:30 -0800187
Duncan Lauriead8d9132013-12-10 07:41:33 -0800188 /* Write _PPC with NVS specified limit on supported P-state */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200189 acpigen_write_PPC_NVS();
Duncan Laurie8923be52013-11-05 13:02:30 -0800190
191 /* Write PSD indicating configured coordination type */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200192 acpigen_write_PSD_package(core, 1, coord_type);
Duncan Laurie8923be52013-11-05 13:02:30 -0800193
194 /* Add P-state entries in _PSS table */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200195 acpigen_write_name("_PSS");
Duncan Laurie8923be52013-11-05 13:02:30 -0800196
197 /* Determine ratio points */
198 ratio_step = 1;
199 num_entries = (ratio_max - ratio_min) / ratio_step;
200 while (num_entries > 15) { /* ACPI max is 15 ratios */
201 ratio_step <<= 1;
202 num_entries >>= 1;
203 }
204
205 /* P[T] is Turbo state if enabled */
206 if (get_turbo_state() == TURBO_ENABLED) {
207 /* _PSS package count including Turbo */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200208 acpigen_write_package(num_entries + 2);
Duncan Laurie8923be52013-11-05 13:02:30 -0800209
210 ratio_turbo = pattrs->iacore_ratios[IACORE_TURBO];
211 vid_turbo = pattrs->iacore_vids[IACORE_TURBO];
212 control_status = (ratio_turbo << 8) | vid_turbo;
213
214 /* Add entry for Turbo ratio */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200215 acpigen_write_PSS_package(
Angel Pons06e44a82020-07-07 17:34:21 +0200216 clock_max + 1, /* MHz */
217 power_max, /* mW */
218 10, /* lat1 */
219 10, /* lat2 */
220 control_status, /* control */
221 control_status); /* status */
Duncan Laurie8923be52013-11-05 13:02:30 -0800222 } else {
223 /* _PSS package count without Turbo */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200224 acpigen_write_package(num_entries + 1);
Duncan Laurie8923be52013-11-05 13:02:30 -0800225 ratio_turbo = ratio_max;
226 vid_turbo = vid_max;
227 }
228
229 /* First regular entry is max non-turbo ratio */
230 control_status = (ratio_max << 8) | vid_max;
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200231 acpigen_write_PSS_package(
Angel Pons06e44a82020-07-07 17:34:21 +0200232 clock_max, /* MHz */
233 power_max, /* mW */
234 10, /* lat1 */
235 10, /* lat2 */
236 control_status, /* control */
237 control_status); /* status */
Duncan Laurie8923be52013-11-05 13:02:30 -0800238
239 /* Set up ratio and vid ranges for VID calculation */
240 ratio_range_2 = (ratio_turbo - ratio_min) * 2;
241 vid_range_2 = (vid_turbo - vid_min) * 2;
242
243 /* Generate the remaining entries */
244 for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
245 ratio >= ratio_min; ratio -= ratio_step) {
246
247 /* Calculate VID for this ratio */
Angel Pons06e44a82020-07-07 17:34:21 +0200248 vid = ((ratio - ratio_min) * vid_range_2) / ratio_range_2 + vid_min;
249
Duncan Laurie8923be52013-11-05 13:02:30 -0800250 /* Round up if remainder */
251 if (((ratio - ratio_min) * vid_range_2) % ratio_range_2)
252 vid++;
253
254 /* Calculate power at this ratio */
255 power = calculate_power(power_max, ratio_max, ratio);
256 clock = (ratio * pattrs->bclk_khz) / 1000;
257 control_status = (ratio << 8) | (vid & 0xff);
258
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200259 acpigen_write_PSS_package(
Angel Pons06e44a82020-07-07 17:34:21 +0200260 clock, /* MHz */
261 power, /* mW */
262 10, /* lat1 */
263 10, /* lat2 */
264 control_status, /* control */
265 control_status); /* status */
Duncan Laurie8923be52013-11-05 13:02:30 -0800266 }
267
268 /* Fix package length */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200269 acpigen_pop_len();
Duncan Laurie8923be52013-11-05 13:02:30 -0800270}
271
Furquan Shaikh7536a392020-04-24 21:59:21 -0700272void generate_cpu_entries(const struct device *device)
Duncan Laurie8923be52013-11-05 13:02:30 -0800273{
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200274 int core;
Duncan Laurie8923be52013-11-05 13:02:30 -0800275 const struct pattrs *pattrs = pattrs_get();
276
Arthur Heymansa7833052018-11-28 12:20:14 +0100277 for (core = 0; core < pattrs->num_cpus; core++) {
Christian Walterbe3979c2019-12-18 15:07:59 +0100278 /* Generate processor \_SB.CPUx */
Michael Niewöhner2353cd92021-10-04 16:59:49 +0200279 acpigen_write_processor(core, 0, 0);
Duncan Laurie8923be52013-11-05 13:02:30 -0800280
281 /* Generate P-state tables */
Angel Pons06e44a82020-07-07 17:34:21 +0200282 generate_p_state_entries(core, pattrs->num_cpus);
Duncan Laurie8923be52013-11-05 13:02:30 -0800283
284 /* Generate C-state tables */
Angel Pons06e44a82020-07-07 17:34:21 +0200285 acpigen_write_CST_package(cstate_map, ARRAY_SIZE(cstate_map));
Duncan Laurie8923be52013-11-05 13:02:30 -0800286
287 /* Generate T-state tables */
Angel Pons06e44a82020-07-07 17:34:21 +0200288 generate_t_state_entries(core, pattrs->num_cpus);
Duncan Laurie8923be52013-11-05 13:02:30 -0800289
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200290 acpigen_pop_len();
Duncan Laurie8923be52013-11-05 13:02:30 -0800291 }
Arthur Heymansa7833052018-11-28 12:20:14 +0100292
293 /* PPKG is usually used for thermal management
294 of the first and only package. */
295 acpigen_write_processor_package("PPKG", 0, pattrs->num_cpus);
296
297 /* Add a method to notify processor nodes */
298 acpigen_write_processor_cnot(pattrs->num_cpus);
Aaron Durbin303525b2013-11-05 11:42:32 -0600299}
Aaron Durbin1af36632013-11-07 10:42:16 -0600300
301unsigned long acpi_madt_irq_overrides(unsigned long current)
302{
303 int sci_irq = acpi_sci_irq();
304 acpi_madt_irqoverride_t *irqovr;
305 uint16_t sci_flags = MP_IRQ_TRIGGER_LEVEL;
306
307 /* INT_SRC_OVR */
308 irqovr = (void *)current;
309 current += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
310
311 if (sci_irq >= 20)
312 sci_flags |= MP_IRQ_POLARITY_LOW;
313 else
314 sci_flags |= MP_IRQ_POLARITY_HIGH;
315
316 irqovr = (void *)current;
Angel Pons06e44a82020-07-07 17:34:21 +0200317 current += acpi_create_madt_irqoverride(irqovr, 0, sci_irq, sci_irq, sci_flags);
Aaron Durbin1af36632013-11-07 10:42:16 -0600318
319 return current;
320}