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