blob: e6c5abfcd3b86ab05ae6fb5074e51693972ea386 [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
Angel Ponse0e28902020-08-03 13:26:21 +020089unsigned long acpi_fill_madt(unsigned long current)
90{
91 /* Local APICs */
92 current = acpi_create_madt_lapics(current);
93
94 /* IOAPIC */
95 current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current,
96 2, IO_APIC_ADDR, 0);
97
98 current = acpi_madt_irq_overrides(current);
99
100 return current;
101}
102
Angel Pons06e44a82020-07-07 17:34:21 +0200103static acpi_tstate_t soc_tss_table[] = {
Duncan Laurie8923be52013-11-05 13:02:30 -0800104 { 100, 1000, 0, 0x00, 0 },
Angel Pons06e44a82020-07-07 17:34:21 +0200105 { 88, 875, 0, 0x1e, 0 },
106 { 75, 750, 0, 0x1c, 0 },
107 { 63, 625, 0, 0x1a, 0 },
108 { 50, 500, 0, 0x18, 0 },
109 { 38, 375, 0, 0x16, 0 },
110 { 25, 250, 0, 0x14, 0 },
111 { 13, 125, 0, 0x12, 0 },
Duncan Laurie8923be52013-11-05 13:02:30 -0800112};
113
Angel Pons06e44a82020-07-07 17:34:21 +0200114static void generate_t_state_entries(int core, int cores_per_package)
Duncan Laurie8923be52013-11-05 13:02:30 -0800115{
Duncan Laurie8923be52013-11-05 13:02:30 -0800116 /* Indicate SW_ALL coordination for T-states */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200117 acpigen_write_TSD_package(core, cores_per_package, SW_ALL);
Duncan Laurie8923be52013-11-05 13:02:30 -0800118
119 /* Indicate FFixedHW so OS will use MSR */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200120 acpigen_write_empty_PTC();
Duncan Laurie8923be52013-11-05 13:02:30 -0800121
122 /* Set NVS controlled T-state limit */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200123 acpigen_write_TPC("\\TLVL");
Duncan Laurie8923be52013-11-05 13:02:30 -0800124
125 /* Write TSS table for MSR access */
Angel Pons06e44a82020-07-07 17:34:21 +0200126 acpigen_write_TSS_package(ARRAY_SIZE(soc_tss_table), soc_tss_table);
Duncan Laurie8923be52013-11-05 13:02:30 -0800127}
128
129static int calculate_power(int tdp, int p1_ratio, int ratio)
130{
Angel Pons06e44a82020-07-07 17:34:21 +0200131 u32 m, power;
Duncan Laurie8923be52013-11-05 13:02:30 -0800132
133 /*
134 * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
Duncan Laurie8923be52013-11-05 13:02:30 -0800135 */
136
137 m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
138 m = (m * m) / 1000;
139
Angel Pons06e44a82020-07-07 17:34:21 +0200140 /*
141 * Power = (ratio / p1_ratio) * m * TDP
142 */
Duncan Laurie8923be52013-11-05 13:02:30 -0800143 power = ((ratio * 100000 / p1_ratio) / 100);
144 power *= (m / 100) * (tdp / 1000);
145 power /= 1000;
146
147 return (int)power;
148}
149
Angel Pons06e44a82020-07-07 17:34:21 +0200150static void generate_p_state_entries(int core, int cores_per_package)
Duncan Laurie8923be52013-11-05 13:02:30 -0800151{
Duncan Laurie8923be52013-11-05 13:02:30 -0800152 int ratio_min, ratio_max, ratio_turbo, ratio_step, ratio_range_2;
153 int coord_type, power_max, power_unit, num_entries;
154 int ratio, power, clock, clock_max;
155 int vid, vid_turbo, vid_min, vid_max, vid_range_2;
156 u32 control_status;
157 const struct pattrs *pattrs = pattrs_get();
158 msr_t msr;
159
160 /* Inputs from CPU attributes */
161 ratio_max = pattrs->iacore_ratios[IACORE_MAX];
162 ratio_min = pattrs->iacore_ratios[IACORE_LFM];
163 vid_max = pattrs->iacore_vids[IACORE_MAX];
164 vid_min = pattrs->iacore_vids[IACORE_LFM];
165
Aaron Durbin4177db52014-02-05 14:55:26 -0600166 /* Set P-states coordination type based on MSR disable bit */
Duncan Laurie31ac9e32014-03-28 10:52:13 -0700167 coord_type = (pattrs->num_cpus > 2) ? SW_ALL : HW_ALL;
Duncan Laurie8923be52013-11-05 13:02:30 -0800168
169 /* Max Non-Turbo Frequency */
170 clock_max = (ratio_max * pattrs->bclk_khz) / 1000;
171
172 /* Calculate CPU TDP in mW */
173 msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
174 power_unit = 1 << (msr.lo & 0xf);
175 msr = rdmsr(MSR_PKG_POWER_LIMIT);
176 power_max = ((msr.lo & 0x7fff) / power_unit) * 1000;
177
178 /* Write _PCT indicating use of FFixedHW */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200179 acpigen_write_empty_PCT();
Duncan Laurie8923be52013-11-05 13:02:30 -0800180
Duncan Lauriead8d9132013-12-10 07:41:33 -0800181 /* Write _PPC with NVS specified limit on supported P-state */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200182 acpigen_write_PPC_NVS();
Duncan Laurie8923be52013-11-05 13:02:30 -0800183
184 /* Write PSD indicating configured coordination type */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200185 acpigen_write_PSD_package(core, 1, coord_type);
Duncan Laurie8923be52013-11-05 13:02:30 -0800186
187 /* Add P-state entries in _PSS table */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200188 acpigen_write_name("_PSS");
Duncan Laurie8923be52013-11-05 13:02:30 -0800189
190 /* Determine ratio points */
191 ratio_step = 1;
192 num_entries = (ratio_max - ratio_min) / ratio_step;
193 while (num_entries > 15) { /* ACPI max is 15 ratios */
194 ratio_step <<= 1;
195 num_entries >>= 1;
196 }
197
198 /* P[T] is Turbo state if enabled */
199 if (get_turbo_state() == TURBO_ENABLED) {
200 /* _PSS package count including Turbo */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200201 acpigen_write_package(num_entries + 2);
Duncan Laurie8923be52013-11-05 13:02:30 -0800202
203 ratio_turbo = pattrs->iacore_ratios[IACORE_TURBO];
204 vid_turbo = pattrs->iacore_vids[IACORE_TURBO];
205 control_status = (ratio_turbo << 8) | vid_turbo;
206
207 /* Add entry for Turbo ratio */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200208 acpigen_write_PSS_package(
Angel Pons06e44a82020-07-07 17:34:21 +0200209 clock_max + 1, /* MHz */
210 power_max, /* mW */
211 10, /* lat1 */
212 10, /* lat2 */
213 control_status, /* control */
214 control_status); /* status */
Duncan Laurie8923be52013-11-05 13:02:30 -0800215 } else {
216 /* _PSS package count without Turbo */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200217 acpigen_write_package(num_entries + 1);
Duncan Laurie8923be52013-11-05 13:02:30 -0800218 ratio_turbo = ratio_max;
219 vid_turbo = vid_max;
220 }
221
222 /* First regular entry is max non-turbo ratio */
223 control_status = (ratio_max << 8) | vid_max;
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200224 acpigen_write_PSS_package(
Angel Pons06e44a82020-07-07 17:34:21 +0200225 clock_max, /* MHz */
226 power_max, /* mW */
227 10, /* lat1 */
228 10, /* lat2 */
229 control_status, /* control */
230 control_status); /* status */
Duncan Laurie8923be52013-11-05 13:02:30 -0800231
232 /* Set up ratio and vid ranges for VID calculation */
233 ratio_range_2 = (ratio_turbo - ratio_min) * 2;
234 vid_range_2 = (vid_turbo - vid_min) * 2;
235
236 /* Generate the remaining entries */
237 for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
238 ratio >= ratio_min; ratio -= ratio_step) {
239
240 /* Calculate VID for this ratio */
Angel Pons06e44a82020-07-07 17:34:21 +0200241 vid = ((ratio - ratio_min) * vid_range_2) / ratio_range_2 + vid_min;
242
Duncan Laurie8923be52013-11-05 13:02:30 -0800243 /* Round up if remainder */
244 if (((ratio - ratio_min) * vid_range_2) % ratio_range_2)
245 vid++;
246
247 /* Calculate power at this ratio */
248 power = calculate_power(power_max, ratio_max, ratio);
249 clock = (ratio * pattrs->bclk_khz) / 1000;
250 control_status = (ratio << 8) | (vid & 0xff);
251
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200252 acpigen_write_PSS_package(
Angel Pons06e44a82020-07-07 17:34:21 +0200253 clock, /* MHz */
254 power, /* mW */
255 10, /* lat1 */
256 10, /* lat2 */
257 control_status, /* control */
258 control_status); /* status */
Duncan Laurie8923be52013-11-05 13:02:30 -0800259 }
260
261 /* Fix package length */
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200262 acpigen_pop_len();
Duncan Laurie8923be52013-11-05 13:02:30 -0800263}
264
Furquan Shaikh7536a392020-04-24 21:59:21 -0700265void generate_cpu_entries(const struct device *device)
Duncan Laurie8923be52013-11-05 13:02:30 -0800266{
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200267 int core;
Duncan Laurie8923be52013-11-05 13:02:30 -0800268 const struct pattrs *pattrs = pattrs_get();
269
Arthur Heymansa7833052018-11-28 12:20:14 +0100270 for (core = 0; core < pattrs->num_cpus; core++) {
Christian Walterbe3979c2019-12-18 15:07:59 +0100271 /* Generate processor \_SB.CPUx */
Michael Niewöhner2353cd92021-10-04 16:59:49 +0200272 acpigen_write_processor(core, 0, 0);
Duncan Laurie8923be52013-11-05 13:02:30 -0800273
274 /* Generate P-state tables */
Angel Pons06e44a82020-07-07 17:34:21 +0200275 generate_p_state_entries(core, pattrs->num_cpus);
Duncan Laurie8923be52013-11-05 13:02:30 -0800276
277 /* Generate C-state tables */
Angel Pons06e44a82020-07-07 17:34:21 +0200278 acpigen_write_CST_package(cstate_map, ARRAY_SIZE(cstate_map));
Duncan Laurie8923be52013-11-05 13:02:30 -0800279
280 /* Generate T-state tables */
Angel Pons06e44a82020-07-07 17:34:21 +0200281 generate_t_state_entries(core, pattrs->num_cpus);
Duncan Laurie8923be52013-11-05 13:02:30 -0800282
Vladimir Serbinenko7fb149d2014-10-08 22:56:27 +0200283 acpigen_pop_len();
Duncan Laurie8923be52013-11-05 13:02:30 -0800284 }
Arthur Heymansa7833052018-11-28 12:20:14 +0100285
286 /* PPKG is usually used for thermal management
287 of the first and only package. */
288 acpigen_write_processor_package("PPKG", 0, pattrs->num_cpus);
289
290 /* Add a method to notify processor nodes */
291 acpigen_write_processor_cnot(pattrs->num_cpus);
Aaron Durbin303525b2013-11-05 11:42:32 -0600292}
Aaron Durbin1af36632013-11-07 10:42:16 -0600293
294unsigned long acpi_madt_irq_overrides(unsigned long current)
295{
296 int sci_irq = acpi_sci_irq();
297 acpi_madt_irqoverride_t *irqovr;
298 uint16_t sci_flags = MP_IRQ_TRIGGER_LEVEL;
299
300 /* INT_SRC_OVR */
301 irqovr = (void *)current;
302 current += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
303
304 if (sci_irq >= 20)
305 sci_flags |= MP_IRQ_POLARITY_LOW;
306 else
307 sci_flags |= MP_IRQ_POLARITY_HIGH;
308
309 irqovr = (void *)current;
Angel Pons06e44a82020-07-07 17:34:21 +0200310 current += acpi_create_madt_irqoverride(irqovr, 0, sci_irq, sci_irq, sci_flags);
Aaron Durbin1af36632013-11-07 10:42:16 -0600311
312 return current;
313}