blob: fd34229688996a617c1c88f9eac5d66a34fc9520 [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>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020031#include "model_2065x.h"
32#include "chip.h"
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +020033#include <cpu/intel/smm/gen1/smi.h>
Matt DeVilliered6fe2f2016-12-14 16:12:43 -060034#include <cpu/intel/common/common.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 */
Lee Leahy9d62e7e2017-03-15 17:40:50 -070044 }, { /* 1: C1 */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020045 .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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010052 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020053 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010063 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020064 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010074 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020075 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010085 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020086 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010096 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020097 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +0100107 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200108 }
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;
Lee Leahy73a28942017-03-15 17:52:06 -0700117 unsigned int threads_per_package, threads_per_core;
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +0200118
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 +0200135
136int cpu_config_tdp_levels(void)
137{
138 msr_t platform_info;
139
140 /* Minimum CPU revision */
141 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
142 return 0;
143
144 /* Bits 34:33 indicate how many levels supported */
145 platform_info = rdmsr(MSR_PLATFORM_INFO);
146 return (platform_info.hi >> 1) & 3;
147}
148
149
150static void configure_thermal_target(void)
151{
152 struct cpu_intel_model_2065x_config *conf;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100153 struct device *lapic;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200154 msr_t msr;
155
156 /* Find pointer to CPU configuration */
157 lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
158 if (!lapic || !lapic->chip_info)
159 return;
160 conf = lapic->chip_info;
161
Martin Roth4c3ab732013-07-08 16:23:54 -0600162 /* Set TCC activation offset if supported */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200163 msr = rdmsr(MSR_PLATFORM_INFO);
164 if ((msr.lo & (1 << 30)) && conf->tcc_offset) {
165 msr = rdmsr(MSR_TEMPERATURE_TARGET);
166 msr.lo &= ~(0xf << 24); /* Bits 27:24 */
167 msr.lo |= (conf->tcc_offset & 0xf) << 24;
168 wrmsr(MSR_TEMPERATURE_TARGET, msr);
169 }
170}
171
172static void configure_misc(void)
173{
174 msr_t msr;
175
176 msr = rdmsr(IA32_MISC_ENABLE);
177 msr.lo |= (1 << 0); /* Fast String enable */
Lee Leahy7b5f12b92017-03-15 17:16:59 -0700178 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200179 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
180 wrmsr(IA32_MISC_ENABLE, msr);
181
182 /* Disable Thermal interrupts */
183 msr.lo = 0;
184 msr.hi = 0;
185 wrmsr(IA32_THERM_INTERRUPT, msr);
186
187#ifdef DISABLED
188 /* Enable package critical interrupt only */
189 msr.lo = 1 << 4;
190 msr.hi = 0;
191 wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
192#endif
193}
194
195static void enable_lapic_tpr(void)
196{
197 msr_t msr;
198
199 msr = rdmsr(MSR_PIC_MSG_CONTROL);
200 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
201 wrmsr(MSR_PIC_MSG_CONTROL, msr);
202}
203
204
205static void set_max_ratio(void)
206{
207 msr_t msr, perf_ctl;
208
209 perf_ctl.hi = 0;
210
211 /* Check for configurable TDP option */
212 if (cpu_config_tdp_levels()) {
213 /* Set to nominal TDP ratio */
214 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
215 perf_ctl.lo = (msr.lo & 0xff) << 8;
216 } else {
217 /* Platform Info bits 15:8 give max ratio */
218 msr = rdmsr(MSR_PLATFORM_INFO);
219 perf_ctl.lo = msr.lo & 0xff00;
220 }
221 wrmsr(IA32_PERF_CTL, perf_ctl);
222
223 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
Vladimir Serbinenko71f35eb2013-11-12 23:32:52 +0100224 ((perf_ctl.lo >> 8) & 0xff) * NEHALEM_BCLK);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200225}
226
227static void set_energy_perf_bias(u8 policy)
228{
229#ifdef DISABLED
230 msr_t msr;
231
232 /* Energy Policy is bits 3:0 */
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200233 msr = rdmsr(IA32_ENERGY_PERF_BIAS);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200234 msr.lo &= ~0xf;
235 msr.lo |= policy & 0xf;
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200236 wrmsr(IA32_ENERGY_PERF_BIAS, msr);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200237
238 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
239 policy);
240#endif
241}
242
243static void configure_mca(void)
244{
245 msr_t msr;
246 int i;
247
248 msr.lo = msr.hi = 0;
249 /* This should only be done on a cold boot */
250 for (i = 0; i < 7; i++)
251 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
252}
253
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200254/*
255 * Initialize any extra cores/threads in this package.
256 */
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100257static void intel_cores_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200258{
259 struct cpuid_result result;
Lee Leahy73a28942017-03-15 17:52:06 -0700260 unsigned int threads_per_package, threads_per_core, i;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200261
262 /* Logical processors (threads) per core */
263 result = cpuid_ext(0xb, 0);
264 threads_per_core = result.ebx & 0xffff;
265
266 /* Logical processors (threads) per package */
267 result = cpuid_ext(0xb, 1);
268 threads_per_package = result.ebx & 0xffff;
269
270 /* Only initialize extra cores from BSP */
271 if (cpu->path.apic.apic_id)
272 return;
273
274 printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
275 cpu->path.apic.apic_id, threads_per_package/threads_per_core,
276 threads_per_core);
277
278 for (i = 1; i < threads_per_package; ++i) {
279 struct device_path cpu_path;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100280 struct device *new;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200281
Elyes HAOUASd82be922016-07-28 18:58:27 +0200282 /* Build the CPU device path */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200283 cpu_path.type = DEVICE_PATH_APIC;
284 cpu_path.apic.apic_id =
Vladimir Serbinenko10b39742014-02-19 22:00:00 +0100285 cpu->path.apic.apic_id + (i % threads_per_core)
286 + ((i / threads_per_core) << 2);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200287
Elyes HAOUASd82be922016-07-28 18:58:27 +0200288 /* Allocate the new CPU device structure */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200289 new = alloc_dev(cpu->bus, &cpu_path);
290 if (!new)
291 continue;
292
293 printk(BIOS_DEBUG, "CPU: %u has core %u\n",
294 cpu->path.apic.apic_id,
295 new->path.apic.apic_id);
296
Elyes HAOUASd82be922016-07-28 18:58:27 +0200297 /* Start the new CPU */
Kyösti Mälkki0cc2ce42017-08-18 11:46:32 +0300298 if (is_smp_boot() && !start_cpu(new)) {
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200299 /* Record the error in cpu? */
300 printk(BIOS_ERR, "CPU %u would not start!\n",
301 new->path.apic.apic_id);
302 }
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200303 }
304}
305
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100306static void model_2065x_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200307{
308 char processor_name[49];
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200309
310 /* Turn on caching if we haven't already */
311 x86_enable_cache();
312
313 intel_update_microcode_from_cbfs();
314
315 /* Clear out pending MCEs */
316 configure_mca();
317
318 /* Print processor name */
319 fill_processor_name(processor_name);
320 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
Lee Leahy9d62e7e2017-03-15 17:40:50 -0700321 printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid(),
322 boot_cpu());
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200323
324 /* Setup MTRRs based on physical address size */
Aaron Durbin2a081372016-03-07 16:23:47 -0600325 x86_setup_mtrrs_with_detect();
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200326 x86_mtrr_check();
327
328 /* Setup Page Attribute Tables (PAT) */
329 // TODO set up PAT
330
Elyes HAOUASd6e96862016-08-21 10:12:15 +0200331 /* Enable the local CPU APICs */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200332 enable_lapic_tpr();
333 setup_lapic();
334
Matt DeVilliered6fe2f2016-12-14 16:12:43 -0600335 /* Set virtualization based on Kconfig option */
Matt DeVillierf9aed652018-12-15 15:57:33 -0600336 set_vmx_and_lock();
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200337
338 /* Configure Enhanced SpeedStep and Thermal Sensors */
339 configure_misc();
340
341 /* Thermal throttle activation offset */
342 configure_thermal_target();
343
344 /* Set energy policy */
345 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
346
347 /* Set Max Ratio */
348 set_max_ratio();
349
350 /* Enable Turbo */
351 enable_turbo();
352
353 /* Start up extra cores */
354 intel_cores_init(cpu);
355}
356
357static struct device_operations cpu_dev_ops = {
358 .init = model_2065x_init,
359};
360
Jonathan Neuschäfer8f06ce32017-11-20 01:56:44 +0100361static const struct cpu_device_id cpu_table[] = {
Vladimir Serbinenko5ef42202014-02-01 16:24:22 +0100362 { X86_VENDOR_INTEL, 0x20652 }, /* Intel Nehalem */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200363 { X86_VENDOR_INTEL, 0x20655 }, /* Intel Nehalem */
364 { 0, 0 },
365};
366
367static const struct cpu_driver driver __cpu_driver = {
368 .ops = &cpu_dev_ops,
369 .id_table = cpu_table,
370 .cstates = cstate_map,
371};