cpu/intel/model_2065x: Add model 20652
[coreboot.git] / src / cpu / intel / model_2065x / model_2065x_init.c
blob6df45a45e86405dafa7b8ca1fcbf7a9270c309a7
1 /*
2 * This file is part of the coreboot project.
4 * Copyright (C) 2007-2009 coresystems GmbH
5 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
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.
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.
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
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>
38 #include "model_2065x.h"
39 #include "chip.h"
42 * List of supported C-states in this processor
44 * Latencies are typical worst-case package exit time in uS
45 * taken from the SandyBridge BIOS specification.
47 static 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,
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,
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,
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,
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,
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,
115 { 0 }
118 static void enable_vmx(void)
120 struct cpuid_result regs;
121 msr_t msr;
122 int enable = CONFIG_ENABLE_VMX;
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;
129 msr = rdmsr(IA32_FEATURE_CONTROL);
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
136 return;
139 /* The IA32_FEATURE_CONTROL MSR may initialize with random values.
140 * It must be cleared regardless of VMX config setting.
142 msr.hi = msr.lo = 0;
144 printk(BIOS_DEBUG, "%s VMX\n", enable ? "Enabling" : "Disabling");
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).
159 if (enable) {
160 msr.lo |= (1 << 2);
161 if (regs.ecx & CPUID_SMX)
162 msr.lo |= (1 << 1);
165 wrmsr(IA32_FEATURE_CONTROL, msr);
168 /* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
169 static 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,
197 /* Convert POWER_LIMIT_1_TIME MSR value to seconds */
198 static 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,
226 int cpu_config_tdp_levels(void)
228 msr_t platform_info;
230 /* Minimum CPU revision */
231 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
232 return 0;
234 /* Bits 34:33 indicate how many levels supported */
235 platform_info = rdmsr(MSR_PLATFORM_INFO);
236 return (platform_info.hi >> 1) & 3;
240 static void configure_thermal_target(void)
242 struct cpu_intel_model_2065x_config *conf;
243 device_t lapic;
244 msr_t msr;
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;
252 /* Set TCC activation offset if supported */
253 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);
262 static void configure_misc(void)
264 msr_t msr;
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);
272 /* Disable Thermal interrupts */
273 msr.lo = 0;
274 msr.hi = 0;
275 wrmsr(IA32_THERM_INTERRUPT, msr);
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
285 static void enable_lapic_tpr(void)
287 msr_t msr;
289 msr = rdmsr(MSR_PIC_MSG_CONTROL);
290 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
291 wrmsr(MSR_PIC_MSG_CONTROL, msr);
295 static void set_max_ratio(void)
297 msr_t msr, perf_ctl;
299 perf_ctl.hi = 0;
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;
311 wrmsr(IA32_PERF_CTL, perf_ctl);
313 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
314 ((perf_ctl.lo >> 8) & 0xff) * NEHALEM_BCLK);
317 static void set_energy_perf_bias(u8 policy)
319 #ifdef DISABLED
320 msr_t msr;
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);
328 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
329 policy);
330 #endif
333 static void configure_mca(void)
335 msr_t msr;
336 int i;
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);
345 * Initialize any extra cores/threads in this package.
347 static void intel_cores_init(device_t cpu)
349 struct cpuid_result result;
350 unsigned threads_per_package, threads_per_core, i;
352 /* Logical processors (threads) per core */
353 result = cpuid_ext(0xb, 0);
354 threads_per_core = result.ebx & 0xffff;
356 /* Logical processors (threads) per package */
357 result = cpuid_ext(0xb, 1);
358 threads_per_package = result.ebx & 0xffff;
360 /* Only initialize extra cores from BSP */
361 if (cpu->path.apic.apic_id)
362 return;
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);
368 for (i = 1; i < threads_per_package; ++i) {
369 struct device_path cpu_path;
370 device_t new;
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);
377 /* Update APIC ID if no hyperthreading */
378 if (threads_per_core == 1)
379 cpu_path.apic.apic_id <<= 1;
381 /* Allocate the new cpu device structure */
382 new = alloc_dev(cpu->bus, &cpu_path);
383 if (!new)
384 continue;
386 printk(BIOS_DEBUG, "CPU: %u has core %u\n",
387 cpu->path.apic.apic_id,
388 new->path.apic.apic_id);
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);
397 #endif
401 static void model_2065x_init(device_t cpu)
403 char processor_name[49];
404 struct cpuid_result cpuid_regs;
406 /* Turn on caching if we haven't already */
407 x86_enable_cache();
409 intel_update_microcode_from_cbfs();
411 /* Clear out pending MCEs */
412 configure_mca();
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 ());
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();
425 /* Setup Page Attribute Tables (PAT) */
426 // TODO set up PAT
428 /* Enable the local cpu apics */
429 enable_lapic_tpr();
430 setup_lapic();
432 /* Enable virtualization if enabled in CMOS */
433 enable_vmx();
435 /* Configure Enhanced SpeedStep and Thermal Sensors */
436 configure_misc();
438 /* Thermal throttle activation offset */
439 configure_thermal_target();
441 /* Set energy policy */
442 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
444 /* Set Max Ratio */
445 set_max_ratio();
447 /* Enable Turbo */
448 enable_turbo();
450 /* Start up extra cores */
451 intel_cores_init(cpu);
454 static struct device_operations cpu_dev_ops = {
455 .init = model_2065x_init,
458 static struct cpu_device_id cpu_table[] = {
459 { X86_VENDOR_INTEL, 0x20652 }, /* Intel Nehalem */
460 { X86_VENDOR_INTEL, 0x20655 }, /* Intel Nehalem */
461 { 0, 0 },
464 static const struct cpu_driver driver __cpu_driver = {
465 .ops = &cpu_dev_ops,
466 .id_table = cpu_table,
467 .cstates = cstate_map,