blob: f79aba564b47a5663080d9410617cf315ee31f87 [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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301 USA
21 */
22
23#include <console/console.h>
24#include <device/device.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020025#include <string.h>
26#include <arch/acpi.h>
27#include <cpu/cpu.h>
28#include <cpu/x86/mtrr.h>
29#include <cpu/x86/msr.h>
30#include <cpu/x86/lapic.h>
31#include <cpu/intel/microcode.h>
32#include <cpu/intel/speedstep.h>
33#include <cpu/intel/turbo.h>
34#include <cpu/x86/cache.h>
35#include <cpu/x86/name.h>
36#include <pc80/mc146818rtc.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020037#include "model_2065x.h"
38#include "chip.h"
39
40/*
Martin Roth4c3ab732013-07-08 16:23:54 -060041 * List of supported C-states in this processor
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020042 *
43 * Latencies are typical worst-case package exit time in uS
44 * taken from the SandyBridge BIOS specification.
45 */
46static acpi_cstate_t cstate_map[] = {
47 { /* 0: C0 */
48 },{ /* 1: C1 */
49 .latency = 1,
50 .power = 1000,
51 .resource = {
52 .addrl = 0x00, /* MWAIT State 0 */
53 .space_id = ACPI_ADDRESS_SPACE_FIXED,
54 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
55 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
56 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
57 }
58 },
59 { /* 2: C1E */
60 .latency = 1,
61 .power = 1000,
62 .resource = {
63 .addrl = 0x01, /* MWAIT State 0 Sub-state 1 */
64 .space_id = ACPI_ADDRESS_SPACE_FIXED,
65 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
66 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
67 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
68 }
69 },
70 { /* 3: C3 */
71 .latency = 63,
72 .power = 500,
73 .resource = {
74 .addrl = 0x10, /* MWAIT State 1 */
75 .space_id = ACPI_ADDRESS_SPACE_FIXED,
76 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
77 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
78 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
79 }
80 },
81 { /* 4: C6 */
82 .latency = 87,
83 .power = 350,
84 .resource = {
85 .addrl = 0x20, /* MWAIT State 2 */
86 .space_id = ACPI_ADDRESS_SPACE_FIXED,
87 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
88 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
89 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
90 }
91 },
92 { /* 5: C7 */
93 .latency = 90,
94 .power = 200,
95 .resource = {
96 .addrl = 0x30, /* MWAIT State 3 */
97 .space_id = ACPI_ADDRESS_SPACE_FIXED,
98 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
99 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
100 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
101 }
102 },
103 { /* 6: C7S */
104 .latency = 90,
105 .power = 200,
106 .resource = {
107 .addrl = 0x31, /* MWAIT State 3 Sub-state 1 */
108 .space_id = ACPI_ADDRESS_SPACE_FIXED,
109 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
110 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
111 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
112 }
113 },
114 { 0 }
115};
116
117static void enable_vmx(void)
118{
119 struct cpuid_result regs;
120 msr_t msr;
121 int enable = CONFIG_ENABLE_VMX;
122
123 regs = cpuid(1);
124 /* Check that the VMX is supported before reading or writing the MSR. */
125 if (!((regs.ecx & CPUID_VMX) || (regs.ecx & CPUID_SMX)))
126 return;
127
128 msr = rdmsr(IA32_FEATURE_CONTROL);
129
130 if (msr.lo & (1 << 0)) {
131 printk(BIOS_ERR, "VMX is locked, so %s will do nothing\n", __func__);
132 /* VMX locked. If we set it again we get an illegal
133 * instruction
134 */
135 return;
136 }
137
138 /* The IA32_FEATURE_CONTROL MSR may initialize with random values.
139 * It must be cleared regardless of VMX config setting.
140 */
141 msr.hi = msr.lo = 0;
142
143 printk(BIOS_DEBUG, "%s VMX\n", enable ? "Enabling" : "Disabling");
144
145 /* Even though the Intel manual says you must set the lock bit in addition
146 * to the VMX bit in order for VMX to work, it is incorrect. Thus we leave
147 * it unlocked for the OS to manage things itself. This is good for a few
148 * reasons:
149 * - No need to reflash the bios just to toggle the lock bit.
150 * - The VMX bits really really should match each other across cores, so
151 * hard locking it on one while another has the opposite setting can
152 * easily lead to crashes as code using VMX migrates between them.
153 * - Vendors that want to "upsell" from a bios that disables+locks to
154 * one that doesn't is sleazy.
155 * By leaving this to the OS (e.g. Linux), people can do exactly what they
156 * want on the fly, and do it correctly (e.g. across multiple cores).
157 */
158 if (enable) {
159 msr.lo |= (1 << 2);
160 if (regs.ecx & CPUID_SMX)
161 msr.lo |= (1 << 1);
162 }
163
164 wrmsr(IA32_FEATURE_CONTROL, msr);
165}
166
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200167
168int cpu_config_tdp_levels(void)
169{
170 msr_t platform_info;
171
172 /* Minimum CPU revision */
173 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
174 return 0;
175
176 /* Bits 34:33 indicate how many levels supported */
177 platform_info = rdmsr(MSR_PLATFORM_INFO);
178 return (platform_info.hi >> 1) & 3;
179}
180
181
182static void configure_thermal_target(void)
183{
184 struct cpu_intel_model_2065x_config *conf;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100185 struct device *lapic;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200186 msr_t msr;
187
188 /* Find pointer to CPU configuration */
189 lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
190 if (!lapic || !lapic->chip_info)
191 return;
192 conf = lapic->chip_info;
193
Martin Roth4c3ab732013-07-08 16:23:54 -0600194 /* Set TCC activation offset if supported */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200195 msr = rdmsr(MSR_PLATFORM_INFO);
196 if ((msr.lo & (1 << 30)) && conf->tcc_offset) {
197 msr = rdmsr(MSR_TEMPERATURE_TARGET);
198 msr.lo &= ~(0xf << 24); /* Bits 27:24 */
199 msr.lo |= (conf->tcc_offset & 0xf) << 24;
200 wrmsr(MSR_TEMPERATURE_TARGET, msr);
201 }
202}
203
204static void configure_misc(void)
205{
206 msr_t msr;
207
208 msr = rdmsr(IA32_MISC_ENABLE);
209 msr.lo |= (1 << 0); /* Fast String enable */
210 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
211 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
212 wrmsr(IA32_MISC_ENABLE, msr);
213
214 /* Disable Thermal interrupts */
215 msr.lo = 0;
216 msr.hi = 0;
217 wrmsr(IA32_THERM_INTERRUPT, msr);
218
219#ifdef DISABLED
220 /* Enable package critical interrupt only */
221 msr.lo = 1 << 4;
222 msr.hi = 0;
223 wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
224#endif
225}
226
227static void enable_lapic_tpr(void)
228{
229 msr_t msr;
230
231 msr = rdmsr(MSR_PIC_MSG_CONTROL);
232 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
233 wrmsr(MSR_PIC_MSG_CONTROL, msr);
234}
235
236
237static void set_max_ratio(void)
238{
239 msr_t msr, perf_ctl;
240
241 perf_ctl.hi = 0;
242
243 /* Check for configurable TDP option */
244 if (cpu_config_tdp_levels()) {
245 /* Set to nominal TDP ratio */
246 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
247 perf_ctl.lo = (msr.lo & 0xff) << 8;
248 } else {
249 /* Platform Info bits 15:8 give max ratio */
250 msr = rdmsr(MSR_PLATFORM_INFO);
251 perf_ctl.lo = msr.lo & 0xff00;
252 }
253 wrmsr(IA32_PERF_CTL, perf_ctl);
254
255 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
Vladimir Serbinenko71f35eb2013-11-12 23:32:52 +0100256 ((perf_ctl.lo >> 8) & 0xff) * NEHALEM_BCLK);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200257}
258
259static void set_energy_perf_bias(u8 policy)
260{
261#ifdef DISABLED
262 msr_t msr;
263
264 /* Energy Policy is bits 3:0 */
265 msr = rdmsr(IA32_ENERGY_PERFORMANCE_BIAS);
266 msr.lo &= ~0xf;
267 msr.lo |= policy & 0xf;
268 wrmsr(IA32_ENERGY_PERFORMANCE_BIAS, msr);
269
270 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
271 policy);
272#endif
273}
274
275static void configure_mca(void)
276{
277 msr_t msr;
278 int i;
279
280 msr.lo = msr.hi = 0;
281 /* This should only be done on a cold boot */
282 for (i = 0; i < 7; i++)
283 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
284}
285
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200286/*
287 * Initialize any extra cores/threads in this package.
288 */
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100289static void intel_cores_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200290{
291 struct cpuid_result result;
292 unsigned threads_per_package, threads_per_core, i;
293
294 /* Logical processors (threads) per core */
295 result = cpuid_ext(0xb, 0);
296 threads_per_core = result.ebx & 0xffff;
297
298 /* Logical processors (threads) per package */
299 result = cpuid_ext(0xb, 1);
300 threads_per_package = result.ebx & 0xffff;
301
302 /* Only initialize extra cores from BSP */
303 if (cpu->path.apic.apic_id)
304 return;
305
306 printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
307 cpu->path.apic.apic_id, threads_per_package/threads_per_core,
308 threads_per_core);
309
310 for (i = 1; i < threads_per_package; ++i) {
311 struct device_path cpu_path;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100312 struct device *new;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200313
314 /* Build the cpu device path */
315 cpu_path.type = DEVICE_PATH_APIC;
316 cpu_path.apic.apic_id =
Vladimir Serbinenko10b39742014-02-19 22:00:00 +0100317 cpu->path.apic.apic_id + (i % threads_per_core)
318 + ((i / threads_per_core) << 2);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200319
320 /* Allocate the new cpu device structure */
321 new = alloc_dev(cpu->bus, &cpu_path);
322 if (!new)
323 continue;
324
325 printk(BIOS_DEBUG, "CPU: %u has core %u\n",
326 cpu->path.apic.apic_id,
327 new->path.apic.apic_id);
328
329#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
330 /* Start the new cpu */
331 if (!start_cpu(new)) {
332 /* Record the error in cpu? */
333 printk(BIOS_ERR, "CPU %u would not start!\n",
334 new->path.apic.apic_id);
335 }
336#endif
337 }
338}
339
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100340static void model_2065x_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200341{
342 char processor_name[49];
343 struct cpuid_result cpuid_regs;
344
345 /* Turn on caching if we haven't already */
346 x86_enable_cache();
347
348 intel_update_microcode_from_cbfs();
349
350 /* Clear out pending MCEs */
351 configure_mca();
352
353 /* Print processor name */
354 fill_processor_name(processor_name);
355 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
356 printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid (), boot_cpu ());
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200357
358 /* Setup MTRRs based on physical address size */
359 cpuid_regs = cpuid(0x80000008);
360 x86_setup_fixed_mtrrs();
361 x86_setup_var_mtrrs(cpuid_regs.eax & 0xff, 2);
362 x86_mtrr_check();
363
364 /* Setup Page Attribute Tables (PAT) */
365 // TODO set up PAT
366
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200367 /* Enable the local cpu apics */
368 enable_lapic_tpr();
369 setup_lapic();
370
371 /* Enable virtualization if enabled in CMOS */
372 enable_vmx();
373
374 /* Configure Enhanced SpeedStep and Thermal Sensors */
375 configure_misc();
376
377 /* Thermal throttle activation offset */
378 configure_thermal_target();
379
380 /* Set energy policy */
381 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
382
383 /* Set Max Ratio */
384 set_max_ratio();
385
386 /* Enable Turbo */
387 enable_turbo();
388
389 /* Start up extra cores */
390 intel_cores_init(cpu);
391}
392
393static struct device_operations cpu_dev_ops = {
394 .init = model_2065x_init,
395};
396
397static struct cpu_device_id cpu_table[] = {
Vladimir Serbinenko5ef42202014-02-01 16:24:22 +0100398 { X86_VENDOR_INTEL, 0x20652 }, /* Intel Nehalem */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200399 { X86_VENDOR_INTEL, 0x20655 }, /* Intel Nehalem */
400 { 0, 0 },
401};
402
403static const struct cpu_driver driver __cpu_driver = {
404 .ops = &cpu_dev_ops,
405 .id_table = cpu_table,
406 .cstates = cstate_map,
407};