blob: a642afdfd4c584cd885083cd9e75e050c70d56e8 [file] [log] [blame]
Angel Ponsf23ae0b2020-04-02 23:48:12 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +02003
Arthur Heymansb66ee552018-05-15 16:35:45 +02004#include <assert.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +02005#include <console/console.h>
6#include <device/device.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +02007#include <arch/acpi.h>
8#include <cpu/cpu.h>
9#include <cpu/x86/mtrr.h>
10#include <cpu/x86/msr.h>
11#include <cpu/x86/lapic.h>
Arthur Heymansb66ee552018-05-15 16:35:45 +020012#include <cpu/x86/mp.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020013#include <cpu/intel/microcode.h>
14#include <cpu/intel/speedstep.h>
15#include <cpu/intel/turbo.h>
16#include <cpu/x86/cache.h>
17#include <cpu/x86/name.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020018#include "model_2065x.h"
19#include "chip.h"
Kyösti Mälkkif091f4d2019-08-14 03:49:21 +030020#include <cpu/intel/smm_reloc.h>
Matt DeVilliered6fe2f2016-12-14 16:12:43 -060021#include <cpu/intel/common/common.h>
Elyes HAOUASdda17fa2019-10-27 13:09:37 +010022#include <smp/node.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020023
24/*
Martin Roth4c3ab732013-07-08 16:23:54 -060025 * List of supported C-states in this processor
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020026 *
27 * Latencies are typical worst-case package exit time in uS
28 * taken from the SandyBridge BIOS specification.
29 */
30static acpi_cstate_t cstate_map[] = {
31 { /* 0: C0 */
Lee Leahy9d62e7e2017-03-15 17:40:50 -070032 }, { /* 1: C1 */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020033 .latency = 1,
34 .power = 1000,
35 .resource = {
36 .addrl = 0x00, /* MWAIT State 0 */
37 .space_id = ACPI_ADDRESS_SPACE_FIXED,
38 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
39 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010040 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020041 }
42 },
43 { /* 2: C1E */
44 .latency = 1,
45 .power = 1000,
46 .resource = {
47 .addrl = 0x01, /* MWAIT State 0 Sub-state 1 */
48 .space_id = ACPI_ADDRESS_SPACE_FIXED,
49 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
50 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010051 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020052 }
53 },
54 { /* 3: C3 */
55 .latency = 63,
56 .power = 500,
57 .resource = {
58 .addrl = 0x10, /* MWAIT State 1 */
59 .space_id = ACPI_ADDRESS_SPACE_FIXED,
60 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
61 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010062 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020063 }
64 },
65 { /* 4: C6 */
66 .latency = 87,
67 .power = 350,
68 .resource = {
69 .addrl = 0x20, /* MWAIT State 2 */
70 .space_id = ACPI_ADDRESS_SPACE_FIXED,
71 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
72 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010073 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020074 }
75 },
76 { /* 5: C7 */
77 .latency = 90,
78 .power = 200,
79 .resource = {
80 .addrl = 0x30, /* MWAIT State 3 */
81 .space_id = ACPI_ADDRESS_SPACE_FIXED,
82 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
83 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010084 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020085 }
86 },
87 { /* 6: C7S */
88 .latency = 90,
89 .power = 200,
90 .resource = {
91 .addrl = 0x31, /* MWAIT State 3 Sub-state 1 */
92 .space_id = ACPI_ADDRESS_SPACE_FIXED,
93 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
94 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010095 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020096 }
97 },
98 { 0 }
99};
100
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200101int cpu_config_tdp_levels(void)
102{
103 msr_t platform_info;
104
105 /* Minimum CPU revision */
106 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
107 return 0;
108
109 /* Bits 34:33 indicate how many levels supported */
110 platform_info = rdmsr(MSR_PLATFORM_INFO);
111 return (platform_info.hi >> 1) & 3;
112}
113
114
115static void configure_thermal_target(void)
116{
117 struct cpu_intel_model_2065x_config *conf;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100118 struct device *lapic;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200119 msr_t msr;
120
121 /* Find pointer to CPU configuration */
122 lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
123 if (!lapic || !lapic->chip_info)
124 return;
125 conf = lapic->chip_info;
126
Martin Roth4c3ab732013-07-08 16:23:54 -0600127 /* Set TCC activation offset if supported */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200128 msr = rdmsr(MSR_PLATFORM_INFO);
129 if ((msr.lo & (1 << 30)) && conf->tcc_offset) {
130 msr = rdmsr(MSR_TEMPERATURE_TARGET);
131 msr.lo &= ~(0xf << 24); /* Bits 27:24 */
132 msr.lo |= (conf->tcc_offset & 0xf) << 24;
133 wrmsr(MSR_TEMPERATURE_TARGET, msr);
134 }
135}
136
137static void configure_misc(void)
138{
139 msr_t msr;
140
141 msr = rdmsr(IA32_MISC_ENABLE);
142 msr.lo |= (1 << 0); /* Fast String enable */
Lee Leahy7b5f12b92017-03-15 17:16:59 -0700143 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200144 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
145 wrmsr(IA32_MISC_ENABLE, msr);
146
147 /* Disable Thermal interrupts */
148 msr.lo = 0;
149 msr.hi = 0;
150 wrmsr(IA32_THERM_INTERRUPT, msr);
151
152#ifdef DISABLED
153 /* Enable package critical interrupt only */
154 msr.lo = 1 << 4;
155 msr.hi = 0;
156 wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
157#endif
158}
159
160static void enable_lapic_tpr(void)
161{
162 msr_t msr;
163
164 msr = rdmsr(MSR_PIC_MSG_CONTROL);
165 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
166 wrmsr(MSR_PIC_MSG_CONTROL, msr);
167}
168
169
170static void set_max_ratio(void)
171{
172 msr_t msr, perf_ctl;
173
174 perf_ctl.hi = 0;
175
176 /* Check for configurable TDP option */
177 if (cpu_config_tdp_levels()) {
178 /* Set to nominal TDP ratio */
179 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
180 perf_ctl.lo = (msr.lo & 0xff) << 8;
181 } else {
182 /* Platform Info bits 15:8 give max ratio */
183 msr = rdmsr(MSR_PLATFORM_INFO);
184 perf_ctl.lo = msr.lo & 0xff00;
185 }
186 wrmsr(IA32_PERF_CTL, perf_ctl);
187
188 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
Angel Pons95de2312020-02-17 13:08:53 +0100189 ((perf_ctl.lo >> 8) & 0xff) * IRONLAKE_BCLK);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200190}
191
192static void set_energy_perf_bias(u8 policy)
193{
194#ifdef DISABLED
195 msr_t msr;
196
197 /* Energy Policy is bits 3:0 */
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200198 msr = rdmsr(IA32_ENERGY_PERF_BIAS);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200199 msr.lo &= ~0xf;
200 msr.lo |= policy & 0xf;
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200201 wrmsr(IA32_ENERGY_PERF_BIAS, msr);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200202
203 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
204 policy);
205#endif
206}
207
208static void configure_mca(void)
209{
210 msr_t msr;
211 int i;
212
213 msr.lo = msr.hi = 0;
214 /* This should only be done on a cold boot */
215 for (i = 0; i < 7; i++)
216 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
217}
218
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100219static void model_2065x_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200220{
221 char processor_name[49];
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200222
223 /* Turn on caching if we haven't already */
224 x86_enable_cache();
225
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200226 /* Clear out pending MCEs */
227 configure_mca();
228
229 /* Print processor name */
230 fill_processor_name(processor_name);
231 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
Lee Leahy9d62e7e2017-03-15 17:40:50 -0700232 printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid(),
233 boot_cpu());
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200234
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200235 /* Setup Page Attribute Tables (PAT) */
236 // TODO set up PAT
237
Elyes HAOUASd6e96862016-08-21 10:12:15 +0200238 /* Enable the local CPU APICs */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200239 enable_lapic_tpr();
240 setup_lapic();
241
Matt DeVilliered6fe2f2016-12-14 16:12:43 -0600242 /* Set virtualization based on Kconfig option */
Matt DeVillierf9aed652018-12-15 15:57:33 -0600243 set_vmx_and_lock();
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200244
245 /* Configure Enhanced SpeedStep and Thermal Sensors */
246 configure_misc();
247
248 /* Thermal throttle activation offset */
249 configure_thermal_target();
250
251 /* Set energy policy */
252 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
253
254 /* Set Max Ratio */
255 set_max_ratio();
256
257 /* Enable Turbo */
258 enable_turbo();
Arthur Heymansb66ee552018-05-15 16:35:45 +0200259}
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200260
Arthur Heymansb66ee552018-05-15 16:35:45 +0200261/* MP initialization support. */
262static const void *microcode_patch;
263
264static void pre_mp_init(void)
265{
266 /* Setup MTRRs based on physical address size. */
267 x86_setup_mtrrs_with_detect();
268 x86_mtrr_check();
269}
270
271static int get_cpu_count(void)
272{
273 msr_t msr;
274 int num_threads;
275 int num_cores;
276
Elyes HAOUASa6a396d2019-05-26 13:25:30 +0200277 msr = rdmsr(MSR_CORE_THREAD_COUNT);
Arthur Heymansb66ee552018-05-15 16:35:45 +0200278 num_threads = (msr.lo >> 0) & 0xffff;
279 num_cores = (msr.lo >> 16) & 0xffff;
280 printk(BIOS_DEBUG, "CPU has %u cores, %u threads enabled.\n",
281 num_cores, num_threads);
282
283 return num_threads;
284}
285
286static void get_microcode_info(const void **microcode, int *parallel)
287{
288 microcode_patch = intel_microcode_find();
289 *microcode = microcode_patch;
290 *parallel = 1;
291}
292
293static void per_cpu_smm_trigger(void)
294{
295 /* Relocate the SMM handler. */
296 smm_relocate();
297
298 /* After SMM relocation a 2nd microcode load is required. */
299 intel_microcode_load_unlocked(microcode_patch);
300}
301
302static void post_mp_init(void)
303{
304 /* Now that all APs have been relocated as well as the BSP let SMIs
305 * start flowing. */
Kyösti Mälkkifaf20d32019-08-14 05:41:41 +0300306 smm_southbridge_enable_smi();
Arthur Heymansb66ee552018-05-15 16:35:45 +0200307
308 /* Lock down the SMRAM space. */
309 smm_lock();
310}
311
312
313static const struct mp_ops mp_ops = {
314 .pre_mp_init = pre_mp_init,
315 .get_cpu_count = get_cpu_count,
316 .get_smm_info = smm_info,
317 .get_microcode_info = get_microcode_info,
318 .pre_mp_smm_init = smm_initialize,
319 .per_cpu_smm_trigger = per_cpu_smm_trigger,
320 .relocation_handler = smm_relocation_handler,
321 .post_mp_init = post_mp_init,
322};
323
Kyösti Mälkkib3267e02019-08-13 16:44:04 +0300324void mp_init_cpus(struct bus *cpu_bus)
Arthur Heymansb66ee552018-05-15 16:35:45 +0200325{
326 if (mp_init_with_smm(cpu_bus, &mp_ops))
327 printk(BIOS_ERR, "MP initialization failure.\n");
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200328}
329
330static struct device_operations cpu_dev_ops = {
331 .init = model_2065x_init,
332};
333
Angel Ponsa8305e72020-02-17 14:24:04 +0100334/* Arrandale / Clarkdale CPU IDs */
Jonathan Neuschäfer8f06ce32017-11-20 01:56:44 +0100335static const struct cpu_device_id cpu_table[] = {
Angel Ponsa8305e72020-02-17 14:24:04 +0100336 { X86_VENDOR_INTEL, 0x20650 },
337 { X86_VENDOR_INTEL, 0x20651 },
338 { X86_VENDOR_INTEL, 0x20652 },
339 { X86_VENDOR_INTEL, 0x20654 },
340 { X86_VENDOR_INTEL, 0x20655 },
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200341 { 0, 0 },
342};
343
344static const struct cpu_driver driver __cpu_driver = {
345 .ops = &cpu_dev_ops,
346 .id_table = cpu_table,
347 .cstates = cstate_map,
348};