blob: 7987f8e36a97125ec19579e3d6584068fc2cb148 [file] [log] [blame]
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007-2009 coresystems GmbH
5 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 of
10 * the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020016 */
17
18#include <console/console.h>
19#include <device/device.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020020#include <string.h>
21#include <arch/acpi.h>
22#include <cpu/cpu.h>
23#include <cpu/x86/mtrr.h>
24#include <cpu/x86/msr.h>
25#include <cpu/x86/lapic.h>
26#include <cpu/intel/microcode.h>
27#include <cpu/intel/speedstep.h>
28#include <cpu/intel/turbo.h>
29#include <cpu/x86/cache.h>
30#include <cpu/x86/name.h>
31#include <pc80/mc146818rtc.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020032#include "model_2065x.h"
33#include "chip.h"
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +020034#include <cpu/intel/smm/gen1/smi.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020035
36/*
Martin Roth4c3ab732013-07-08 16:23:54 -060037 * List of supported C-states in this processor
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020038 *
39 * Latencies are typical worst-case package exit time in uS
40 * taken from the SandyBridge BIOS specification.
41 */
42static acpi_cstate_t cstate_map[] = {
43 { /* 0: C0 */
44 },{ /* 1: C1 */
45 .latency = 1,
46 .power = 1000,
47 .resource = {
48 .addrl = 0x00, /* MWAIT State 0 */
49 .space_id = ACPI_ADDRESS_SPACE_FIXED,
50 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
51 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
52 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
53 }
54 },
55 { /* 2: C1E */
56 .latency = 1,
57 .power = 1000,
58 .resource = {
59 .addrl = 0x01, /* MWAIT State 0 Sub-state 1 */
60 .space_id = ACPI_ADDRESS_SPACE_FIXED,
61 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
62 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
63 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
64 }
65 },
66 { /* 3: C3 */
67 .latency = 63,
68 .power = 500,
69 .resource = {
70 .addrl = 0x10, /* MWAIT State 1 */
71 .space_id = ACPI_ADDRESS_SPACE_FIXED,
72 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
73 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
74 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
75 }
76 },
77 { /* 4: C6 */
78 .latency = 87,
79 .power = 350,
80 .resource = {
81 .addrl = 0x20, /* MWAIT State 2 */
82 .space_id = ACPI_ADDRESS_SPACE_FIXED,
83 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
84 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
85 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
86 }
87 },
88 { /* 5: C7 */
89 .latency = 90,
90 .power = 200,
91 .resource = {
92 .addrl = 0x30, /* MWAIT State 3 */
93 .space_id = ACPI_ADDRESS_SPACE_FIXED,
94 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
95 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
96 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
97 }
98 },
99 { /* 6: C7S */
100 .latency = 90,
101 .power = 200,
102 .resource = {
103 .addrl = 0x31, /* MWAIT State 3 Sub-state 1 */
104 .space_id = ACPI_ADDRESS_SPACE_FIXED,
105 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
106 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
107 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
108 }
109 },
110 { 0 }
111};
112
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +0200113int cpu_get_apic_id_map(int *apic_id_map)
114{
115 int i;
116 struct cpuid_result result;
117 unsigned threads_per_package, threads_per_core;
118
119 /* Logical processors (threads) per core */
120 result = cpuid_ext(0xb, 0);
121 threads_per_core = result.ebx & 0xffff;
122
123 /* Logical processors (threads) per package */
124 result = cpuid_ext(0xb, 1);
125 threads_per_package = result.ebx & 0xffff;
126
127 for (i = 0; i < threads_per_package && i < CONFIG_MAX_CPUS; ++i) {
128 apic_id_map[i] = (i % threads_per_core)
129 + ((i / threads_per_core) << 2);
130 }
131
132 return threads_per_package;
133}
134
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200135static void enable_vmx(void)
136{
137 struct cpuid_result regs;
138 msr_t msr;
139 int enable = CONFIG_ENABLE_VMX;
140
141 regs = cpuid(1);
142 /* Check that the VMX is supported before reading or writing the MSR. */
143 if (!((regs.ecx & CPUID_VMX) || (regs.ecx & CPUID_SMX)))
144 return;
145
146 msr = rdmsr(IA32_FEATURE_CONTROL);
147
148 if (msr.lo & (1 << 0)) {
149 printk(BIOS_ERR, "VMX is locked, so %s will do nothing\n", __func__);
150 /* VMX locked. If we set it again we get an illegal
151 * instruction
152 */
153 return;
154 }
155
156 /* The IA32_FEATURE_CONTROL MSR may initialize with random values.
157 * It must be cleared regardless of VMX config setting.
158 */
159 msr.hi = msr.lo = 0;
160
161 printk(BIOS_DEBUG, "%s VMX\n", enable ? "Enabling" : "Disabling");
162
163 /* Even though the Intel manual says you must set the lock bit in addition
164 * to the VMX bit in order for VMX to work, it is incorrect. Thus we leave
165 * it unlocked for the OS to manage things itself. This is good for a few
166 * reasons:
167 * - No need to reflash the bios just to toggle the lock bit.
168 * - The VMX bits really really should match each other across cores, so
169 * hard locking it on one while another has the opposite setting can
170 * easily lead to crashes as code using VMX migrates between them.
171 * - Vendors that want to "upsell" from a bios that disables+locks to
172 * one that doesn't is sleazy.
173 * By leaving this to the OS (e.g. Linux), people can do exactly what they
174 * want on the fly, and do it correctly (e.g. across multiple cores).
175 */
176 if (enable) {
177 msr.lo |= (1 << 2);
178 if (regs.ecx & CPUID_SMX)
179 msr.lo |= (1 << 1);
180 }
181
182 wrmsr(IA32_FEATURE_CONTROL, msr);
183}
184
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200185
186int cpu_config_tdp_levels(void)
187{
188 msr_t platform_info;
189
190 /* Minimum CPU revision */
191 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
192 return 0;
193
194 /* Bits 34:33 indicate how many levels supported */
195 platform_info = rdmsr(MSR_PLATFORM_INFO);
196 return (platform_info.hi >> 1) & 3;
197}
198
199
200static void configure_thermal_target(void)
201{
202 struct cpu_intel_model_2065x_config *conf;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100203 struct device *lapic;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200204 msr_t msr;
205
206 /* Find pointer to CPU configuration */
207 lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
208 if (!lapic || !lapic->chip_info)
209 return;
210 conf = lapic->chip_info;
211
Martin Roth4c3ab732013-07-08 16:23:54 -0600212 /* Set TCC activation offset if supported */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200213 msr = rdmsr(MSR_PLATFORM_INFO);
214 if ((msr.lo & (1 << 30)) && conf->tcc_offset) {
215 msr = rdmsr(MSR_TEMPERATURE_TARGET);
216 msr.lo &= ~(0xf << 24); /* Bits 27:24 */
217 msr.lo |= (conf->tcc_offset & 0xf) << 24;
218 wrmsr(MSR_TEMPERATURE_TARGET, msr);
219 }
220}
221
222static void configure_misc(void)
223{
224 msr_t msr;
225
226 msr = rdmsr(IA32_MISC_ENABLE);
227 msr.lo |= (1 << 0); /* Fast String enable */
228 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
229 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
230 wrmsr(IA32_MISC_ENABLE, msr);
231
232 /* Disable Thermal interrupts */
233 msr.lo = 0;
234 msr.hi = 0;
235 wrmsr(IA32_THERM_INTERRUPT, msr);
236
237#ifdef DISABLED
238 /* Enable package critical interrupt only */
239 msr.lo = 1 << 4;
240 msr.hi = 0;
241 wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
242#endif
243}
244
245static void enable_lapic_tpr(void)
246{
247 msr_t msr;
248
249 msr = rdmsr(MSR_PIC_MSG_CONTROL);
250 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
251 wrmsr(MSR_PIC_MSG_CONTROL, msr);
252}
253
254
255static void set_max_ratio(void)
256{
257 msr_t msr, perf_ctl;
258
259 perf_ctl.hi = 0;
260
261 /* Check for configurable TDP option */
262 if (cpu_config_tdp_levels()) {
263 /* Set to nominal TDP ratio */
264 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
265 perf_ctl.lo = (msr.lo & 0xff) << 8;
266 } else {
267 /* Platform Info bits 15:8 give max ratio */
268 msr = rdmsr(MSR_PLATFORM_INFO);
269 perf_ctl.lo = msr.lo & 0xff00;
270 }
271 wrmsr(IA32_PERF_CTL, perf_ctl);
272
273 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
Vladimir Serbinenko71f35eb2013-11-12 23:32:52 +0100274 ((perf_ctl.lo >> 8) & 0xff) * NEHALEM_BCLK);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200275}
276
277static void set_energy_perf_bias(u8 policy)
278{
279#ifdef DISABLED
280 msr_t msr;
281
282 /* Energy Policy is bits 3:0 */
283 msr = rdmsr(IA32_ENERGY_PERFORMANCE_BIAS);
284 msr.lo &= ~0xf;
285 msr.lo |= policy & 0xf;
286 wrmsr(IA32_ENERGY_PERFORMANCE_BIAS, msr);
287
288 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
289 policy);
290#endif
291}
292
293static void configure_mca(void)
294{
295 msr_t msr;
296 int i;
297
298 msr.lo = msr.hi = 0;
299 /* This should only be done on a cold boot */
300 for (i = 0; i < 7; i++)
301 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
302}
303
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200304/*
305 * Initialize any extra cores/threads in this package.
306 */
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100307static void intel_cores_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200308{
309 struct cpuid_result result;
310 unsigned threads_per_package, threads_per_core, i;
311
312 /* Logical processors (threads) per core */
313 result = cpuid_ext(0xb, 0);
314 threads_per_core = result.ebx & 0xffff;
315
316 /* Logical processors (threads) per package */
317 result = cpuid_ext(0xb, 1);
318 threads_per_package = result.ebx & 0xffff;
319
320 /* Only initialize extra cores from BSP */
321 if (cpu->path.apic.apic_id)
322 return;
323
324 printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
325 cpu->path.apic.apic_id, threads_per_package/threads_per_core,
326 threads_per_core);
327
328 for (i = 1; i < threads_per_package; ++i) {
329 struct device_path cpu_path;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100330 struct device *new;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200331
Elyes HAOUASd82be922016-07-28 18:58:27 +0200332 /* Build the CPU device path */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200333 cpu_path.type = DEVICE_PATH_APIC;
334 cpu_path.apic.apic_id =
Vladimir Serbinenko10b39742014-02-19 22:00:00 +0100335 cpu->path.apic.apic_id + (i % threads_per_core)
336 + ((i / threads_per_core) << 2);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200337
Elyes HAOUASd82be922016-07-28 18:58:27 +0200338 /* Allocate the new CPU device structure */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200339 new = alloc_dev(cpu->bus, &cpu_path);
340 if (!new)
341 continue;
342
343 printk(BIOS_DEBUG, "CPU: %u has core %u\n",
344 cpu->path.apic.apic_id,
345 new->path.apic.apic_id);
346
347#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
Elyes HAOUASd82be922016-07-28 18:58:27 +0200348 /* Start the new CPU */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200349 if (!start_cpu(new)) {
350 /* Record the error in cpu? */
351 printk(BIOS_ERR, "CPU %u would not start!\n",
352 new->path.apic.apic_id);
353 }
354#endif
355 }
356}
357
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100358static void model_2065x_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200359{
360 char processor_name[49];
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200361
362 /* Turn on caching if we haven't already */
363 x86_enable_cache();
364
365 intel_update_microcode_from_cbfs();
366
367 /* Clear out pending MCEs */
368 configure_mca();
369
370 /* Print processor name */
371 fill_processor_name(processor_name);
372 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
373 printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid (), boot_cpu ());
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200374
375 /* Setup MTRRs based on physical address size */
Aaron Durbin2a081372016-03-07 16:23:47 -0600376 x86_setup_mtrrs_with_detect();
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200377 x86_mtrr_check();
378
379 /* Setup Page Attribute Tables (PAT) */
380 // TODO set up PAT
381
Elyes HAOUASd6e96862016-08-21 10:12:15 +0200382 /* Enable the local CPU APICs */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200383 enable_lapic_tpr();
384 setup_lapic();
385
386 /* Enable virtualization if enabled in CMOS */
387 enable_vmx();
388
389 /* Configure Enhanced SpeedStep and Thermal Sensors */
390 configure_misc();
391
392 /* Thermal throttle activation offset */
393 configure_thermal_target();
394
395 /* Set energy policy */
396 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
397
398 /* Set Max Ratio */
399 set_max_ratio();
400
401 /* Enable Turbo */
402 enable_turbo();
403
404 /* Start up extra cores */
405 intel_cores_init(cpu);
406}
407
408static struct device_operations cpu_dev_ops = {
409 .init = model_2065x_init,
410};
411
412static struct cpu_device_id cpu_table[] = {
Vladimir Serbinenko5ef42202014-02-01 16:24:22 +0100413 { X86_VENDOR_INTEL, 0x20652 }, /* Intel Nehalem */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200414 { X86_VENDOR_INTEL, 0x20655 }, /* Intel Nehalem */
415 { 0, 0 },
416};
417
418static const struct cpu_driver driver __cpu_driver = {
419 .ops = &cpu_dev_ops,
420 .id_table = cpu_table,
421 .cstates = cstate_map,
422};