blob: 991bab89e0b884dd8da200e059e3248d5a140306 [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
Patrick Georgib890a122015-03-26 15:17:45 +010019 * Foundation, Inc.
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020020 */
21
22#include <console/console.h>
23#include <device/device.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020024#include <string.h>
25#include <arch/acpi.h>
26#include <cpu/cpu.h>
27#include <cpu/x86/mtrr.h>
28#include <cpu/x86/msr.h>
29#include <cpu/x86/lapic.h>
30#include <cpu/intel/microcode.h>
31#include <cpu/intel/speedstep.h>
32#include <cpu/intel/turbo.h>
33#include <cpu/x86/cache.h>
34#include <cpu/x86/name.h>
35#include <pc80/mc146818rtc.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020036#include "model_2065x.h"
37#include "chip.h"
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +020038#include <cpu/intel/smm/gen1/smi.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020039
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
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +0200117int cpu_get_apic_id_map(int *apic_id_map)
118{
119 int i;
120 struct cpuid_result result;
121 unsigned threads_per_package, threads_per_core;
122
123 /* Logical processors (threads) per core */
124 result = cpuid_ext(0xb, 0);
125 threads_per_core = result.ebx & 0xffff;
126
127 /* Logical processors (threads) per package */
128 result = cpuid_ext(0xb, 1);
129 threads_per_package = result.ebx & 0xffff;
130
131 for (i = 0; i < threads_per_package && i < CONFIG_MAX_CPUS; ++i) {
132 apic_id_map[i] = (i % threads_per_core)
133 + ((i / threads_per_core) << 2);
134 }
135
136 return threads_per_package;
137}
138
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200139static void enable_vmx(void)
140{
141 struct cpuid_result regs;
142 msr_t msr;
143 int enable = CONFIG_ENABLE_VMX;
144
145 regs = cpuid(1);
146 /* Check that the VMX is supported before reading or writing the MSR. */
147 if (!((regs.ecx & CPUID_VMX) || (regs.ecx & CPUID_SMX)))
148 return;
149
150 msr = rdmsr(IA32_FEATURE_CONTROL);
151
152 if (msr.lo & (1 << 0)) {
153 printk(BIOS_ERR, "VMX is locked, so %s will do nothing\n", __func__);
154 /* VMX locked. If we set it again we get an illegal
155 * instruction
156 */
157 return;
158 }
159
160 /* The IA32_FEATURE_CONTROL MSR may initialize with random values.
161 * It must be cleared regardless of VMX config setting.
162 */
163 msr.hi = msr.lo = 0;
164
165 printk(BIOS_DEBUG, "%s VMX\n", enable ? "Enabling" : "Disabling");
166
167 /* Even though the Intel manual says you must set the lock bit in addition
168 * to the VMX bit in order for VMX to work, it is incorrect. Thus we leave
169 * it unlocked for the OS to manage things itself. This is good for a few
170 * reasons:
171 * - No need to reflash the bios just to toggle the lock bit.
172 * - The VMX bits really really should match each other across cores, so
173 * hard locking it on one while another has the opposite setting can
174 * easily lead to crashes as code using VMX migrates between them.
175 * - Vendors that want to "upsell" from a bios that disables+locks to
176 * one that doesn't is sleazy.
177 * By leaving this to the OS (e.g. Linux), people can do exactly what they
178 * want on the fly, and do it correctly (e.g. across multiple cores).
179 */
180 if (enable) {
181 msr.lo |= (1 << 2);
182 if (regs.ecx & CPUID_SMX)
183 msr.lo |= (1 << 1);
184 }
185
186 wrmsr(IA32_FEATURE_CONTROL, msr);
187}
188
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200189
190int cpu_config_tdp_levels(void)
191{
192 msr_t platform_info;
193
194 /* Minimum CPU revision */
195 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
196 return 0;
197
198 /* Bits 34:33 indicate how many levels supported */
199 platform_info = rdmsr(MSR_PLATFORM_INFO);
200 return (platform_info.hi >> 1) & 3;
201}
202
203
204static void configure_thermal_target(void)
205{
206 struct cpu_intel_model_2065x_config *conf;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100207 struct device *lapic;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200208 msr_t msr;
209
210 /* Find pointer to CPU configuration */
211 lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
212 if (!lapic || !lapic->chip_info)
213 return;
214 conf = lapic->chip_info;
215
Martin Roth4c3ab732013-07-08 16:23:54 -0600216 /* Set TCC activation offset if supported */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200217 msr = rdmsr(MSR_PLATFORM_INFO);
218 if ((msr.lo & (1 << 30)) && conf->tcc_offset) {
219 msr = rdmsr(MSR_TEMPERATURE_TARGET);
220 msr.lo &= ~(0xf << 24); /* Bits 27:24 */
221 msr.lo |= (conf->tcc_offset & 0xf) << 24;
222 wrmsr(MSR_TEMPERATURE_TARGET, msr);
223 }
224}
225
226static void configure_misc(void)
227{
228 msr_t msr;
229
230 msr = rdmsr(IA32_MISC_ENABLE);
231 msr.lo |= (1 << 0); /* Fast String enable */
232 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
233 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
234 wrmsr(IA32_MISC_ENABLE, msr);
235
236 /* Disable Thermal interrupts */
237 msr.lo = 0;
238 msr.hi = 0;
239 wrmsr(IA32_THERM_INTERRUPT, msr);
240
241#ifdef DISABLED
242 /* Enable package critical interrupt only */
243 msr.lo = 1 << 4;
244 msr.hi = 0;
245 wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
246#endif
247}
248
249static void enable_lapic_tpr(void)
250{
251 msr_t msr;
252
253 msr = rdmsr(MSR_PIC_MSG_CONTROL);
254 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
255 wrmsr(MSR_PIC_MSG_CONTROL, msr);
256}
257
258
259static void set_max_ratio(void)
260{
261 msr_t msr, perf_ctl;
262
263 perf_ctl.hi = 0;
264
265 /* Check for configurable TDP option */
266 if (cpu_config_tdp_levels()) {
267 /* Set to nominal TDP ratio */
268 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
269 perf_ctl.lo = (msr.lo & 0xff) << 8;
270 } else {
271 /* Platform Info bits 15:8 give max ratio */
272 msr = rdmsr(MSR_PLATFORM_INFO);
273 perf_ctl.lo = msr.lo & 0xff00;
274 }
275 wrmsr(IA32_PERF_CTL, perf_ctl);
276
277 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
Vladimir Serbinenko71f35eb2013-11-12 23:32:52 +0100278 ((perf_ctl.lo >> 8) & 0xff) * NEHALEM_BCLK);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200279}
280
281static void set_energy_perf_bias(u8 policy)
282{
283#ifdef DISABLED
284 msr_t msr;
285
286 /* Energy Policy is bits 3:0 */
287 msr = rdmsr(IA32_ENERGY_PERFORMANCE_BIAS);
288 msr.lo &= ~0xf;
289 msr.lo |= policy & 0xf;
290 wrmsr(IA32_ENERGY_PERFORMANCE_BIAS, msr);
291
292 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
293 policy);
294#endif
295}
296
297static void configure_mca(void)
298{
299 msr_t msr;
300 int i;
301
302 msr.lo = msr.hi = 0;
303 /* This should only be done on a cold boot */
304 for (i = 0; i < 7; i++)
305 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
306}
307
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200308/*
309 * Initialize any extra cores/threads in this package.
310 */
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100311static void intel_cores_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200312{
313 struct cpuid_result result;
314 unsigned threads_per_package, threads_per_core, i;
315
316 /* Logical processors (threads) per core */
317 result = cpuid_ext(0xb, 0);
318 threads_per_core = result.ebx & 0xffff;
319
320 /* Logical processors (threads) per package */
321 result = cpuid_ext(0xb, 1);
322 threads_per_package = result.ebx & 0xffff;
323
324 /* Only initialize extra cores from BSP */
325 if (cpu->path.apic.apic_id)
326 return;
327
328 printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
329 cpu->path.apic.apic_id, threads_per_package/threads_per_core,
330 threads_per_core);
331
332 for (i = 1; i < threads_per_package; ++i) {
333 struct device_path cpu_path;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100334 struct device *new;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200335
336 /* Build the cpu device path */
337 cpu_path.type = DEVICE_PATH_APIC;
338 cpu_path.apic.apic_id =
Vladimir Serbinenko10b39742014-02-19 22:00:00 +0100339 cpu->path.apic.apic_id + (i % threads_per_core)
340 + ((i / threads_per_core) << 2);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200341
342 /* Allocate the new cpu device structure */
343 new = alloc_dev(cpu->bus, &cpu_path);
344 if (!new)
345 continue;
346
347 printk(BIOS_DEBUG, "CPU: %u has core %u\n",
348 cpu->path.apic.apic_id,
349 new->path.apic.apic_id);
350
351#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
352 /* Start the new cpu */
353 if (!start_cpu(new)) {
354 /* Record the error in cpu? */
355 printk(BIOS_ERR, "CPU %u would not start!\n",
356 new->path.apic.apic_id);
357 }
358#endif
359 }
360}
361
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100362static void model_2065x_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200363{
364 char processor_name[49];
365 struct cpuid_result cpuid_regs;
366
367 /* Turn on caching if we haven't already */
368 x86_enable_cache();
369
370 intel_update_microcode_from_cbfs();
371
372 /* Clear out pending MCEs */
373 configure_mca();
374
375 /* Print processor name */
376 fill_processor_name(processor_name);
377 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
378 printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid (), boot_cpu ());
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200379
380 /* Setup MTRRs based on physical address size */
381 cpuid_regs = cpuid(0x80000008);
382 x86_setup_fixed_mtrrs();
383 x86_setup_var_mtrrs(cpuid_regs.eax & 0xff, 2);
384 x86_mtrr_check();
385
386 /* Setup Page Attribute Tables (PAT) */
387 // TODO set up PAT
388
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200389 /* Enable the local cpu apics */
390 enable_lapic_tpr();
391 setup_lapic();
392
393 /* Enable virtualization if enabled in CMOS */
394 enable_vmx();
395
396 /* Configure Enhanced SpeedStep and Thermal Sensors */
397 configure_misc();
398
399 /* Thermal throttle activation offset */
400 configure_thermal_target();
401
402 /* Set energy policy */
403 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
404
405 /* Set Max Ratio */
406 set_max_ratio();
407
408 /* Enable Turbo */
409 enable_turbo();
410
411 /* Start up extra cores */
412 intel_cores_init(cpu);
413}
414
415static struct device_operations cpu_dev_ops = {
416 .init = model_2065x_init,
417};
418
419static struct cpu_device_id cpu_table[] = {
Vladimir Serbinenko5ef42202014-02-01 16:24:22 +0100420 { X86_VENDOR_INTEL, 0x20652 }, /* Intel Nehalem */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200421 { X86_VENDOR_INTEL, 0x20655 }, /* Intel Nehalem */
422 { 0, 0 },
423};
424
425static const struct cpu_driver driver __cpu_driver = {
426 .ops = &cpu_dev_ops,
427 .id_table = cpu_table,
428 .cstates = cstate_map,
429};