blob: 8f1311ec9cd24bebae847007721fbffbd4fe83f3 [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>
31#include <pc80/mc146818rtc.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020032#include "model_2065x.h"
33#include "chip.h"
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +020034#include <cpu/intel/smm/gen1/smi.h>
Matt DeVilliered6fe2f2016-12-14 16:12:43 -060035#include <cpu/intel/common/common.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020036
37/*
Martin Roth4c3ab732013-07-08 16:23:54 -060038 * List of supported C-states in this processor
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020039 *
40 * Latencies are typical worst-case package exit time in uS
41 * taken from the SandyBridge BIOS specification.
42 */
43static acpi_cstate_t cstate_map[] = {
44 { /* 0: C0 */
45 },{ /* 1: C1 */
46 .latency = 1,
47 .power = 1000,
48 .resource = {
49 .addrl = 0x00, /* MWAIT State 0 */
50 .space_id = ACPI_ADDRESS_SPACE_FIXED,
51 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
52 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
53 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
54 }
55 },
56 { /* 2: C1E */
57 .latency = 1,
58 .power = 1000,
59 .resource = {
60 .addrl = 0x01, /* MWAIT State 0 Sub-state 1 */
61 .space_id = ACPI_ADDRESS_SPACE_FIXED,
62 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
63 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
64 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
65 }
66 },
67 { /* 3: C3 */
68 .latency = 63,
69 .power = 500,
70 .resource = {
71 .addrl = 0x10, /* MWAIT State 1 */
72 .space_id = ACPI_ADDRESS_SPACE_FIXED,
73 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
74 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
75 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
76 }
77 },
78 { /* 4: C6 */
79 .latency = 87,
80 .power = 350,
81 .resource = {
82 .addrl = 0x20, /* MWAIT State 2 */
83 .space_id = ACPI_ADDRESS_SPACE_FIXED,
84 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
85 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
86 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
87 }
88 },
89 { /* 5: C7 */
90 .latency = 90,
91 .power = 200,
92 .resource = {
93 .addrl = 0x30, /* MWAIT State 3 */
94 .space_id = ACPI_ADDRESS_SPACE_FIXED,
95 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
96 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
97 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
98 }
99 },
100 { /* 6: C7S */
101 .latency = 90,
102 .power = 200,
103 .resource = {
104 .addrl = 0x31, /* MWAIT State 3 Sub-state 1 */
105 .space_id = ACPI_ADDRESS_SPACE_FIXED,
106 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL,
107 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT,
108 .resv = ACPI_FFIXEDHW_FLAG_HW_COORD,
109 }
110 },
111 { 0 }
112};
113
Vladimir Serbinenko0f9aa1c2015-05-29 16:52:50 +0200114int cpu_get_apic_id_map(int *apic_id_map)
115{
116 int i;
117 struct cpuid_result result;
118 unsigned threads_per_package, threads_per_core;
119
120 /* Logical processors (threads) per core */
121 result = cpuid_ext(0xb, 0);
122 threads_per_core = result.ebx & 0xffff;
123
124 /* Logical processors (threads) per package */
125 result = cpuid_ext(0xb, 1);
126 threads_per_package = result.ebx & 0xffff;
127
128 for (i = 0; i < threads_per_package && i < CONFIG_MAX_CPUS; ++i) {
129 apic_id_map[i] = (i % threads_per_core)
130 + ((i / threads_per_core) << 2);
131 }
132
133 return threads_per_package;
134}
135
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200136
137int cpu_config_tdp_levels(void)
138{
139 msr_t platform_info;
140
141 /* Minimum CPU revision */
142 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
143 return 0;
144
145 /* Bits 34:33 indicate how many levels supported */
146 platform_info = rdmsr(MSR_PLATFORM_INFO);
147 return (platform_info.hi >> 1) & 3;
148}
149
150
151static void configure_thermal_target(void)
152{
153 struct cpu_intel_model_2065x_config *conf;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100154 struct device *lapic;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200155 msr_t msr;
156
157 /* Find pointer to CPU configuration */
158 lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
159 if (!lapic || !lapic->chip_info)
160 return;
161 conf = lapic->chip_info;
162
Martin Roth4c3ab732013-07-08 16:23:54 -0600163 /* Set TCC activation offset if supported */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200164 msr = rdmsr(MSR_PLATFORM_INFO);
165 if ((msr.lo & (1 << 30)) && conf->tcc_offset) {
166 msr = rdmsr(MSR_TEMPERATURE_TARGET);
167 msr.lo &= ~(0xf << 24); /* Bits 27:24 */
168 msr.lo |= (conf->tcc_offset & 0xf) << 24;
169 wrmsr(MSR_TEMPERATURE_TARGET, msr);
170 }
171}
172
173static void configure_misc(void)
174{
175 msr_t msr;
176
177 msr = rdmsr(IA32_MISC_ENABLE);
178 msr.lo |= (1 << 0); /* Fast String enable */
Lee Leahy7b5f12b92017-03-15 17:16:59 -0700179 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200180 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
181 wrmsr(IA32_MISC_ENABLE, msr);
182
183 /* Disable Thermal interrupts */
184 msr.lo = 0;
185 msr.hi = 0;
186 wrmsr(IA32_THERM_INTERRUPT, msr);
187
188#ifdef DISABLED
189 /* Enable package critical interrupt only */
190 msr.lo = 1 << 4;
191 msr.hi = 0;
192 wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
193#endif
194}
195
196static void enable_lapic_tpr(void)
197{
198 msr_t msr;
199
200 msr = rdmsr(MSR_PIC_MSG_CONTROL);
201 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
202 wrmsr(MSR_PIC_MSG_CONTROL, msr);
203}
204
205
206static void set_max_ratio(void)
207{
208 msr_t msr, perf_ctl;
209
210 perf_ctl.hi = 0;
211
212 /* Check for configurable TDP option */
213 if (cpu_config_tdp_levels()) {
214 /* Set to nominal TDP ratio */
215 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
216 perf_ctl.lo = (msr.lo & 0xff) << 8;
217 } else {
218 /* Platform Info bits 15:8 give max ratio */
219 msr = rdmsr(MSR_PLATFORM_INFO);
220 perf_ctl.lo = msr.lo & 0xff00;
221 }
222 wrmsr(IA32_PERF_CTL, perf_ctl);
223
224 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
Vladimir Serbinenko71f35eb2013-11-12 23:32:52 +0100225 ((perf_ctl.lo >> 8) & 0xff) * NEHALEM_BCLK);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200226}
227
228static void set_energy_perf_bias(u8 policy)
229{
230#ifdef DISABLED
231 msr_t msr;
232
233 /* Energy Policy is bits 3:0 */
234 msr = rdmsr(IA32_ENERGY_PERFORMANCE_BIAS);
235 msr.lo &= ~0xf;
236 msr.lo |= policy & 0xf;
237 wrmsr(IA32_ENERGY_PERFORMANCE_BIAS, msr);
238
239 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
240 policy);
241#endif
242}
243
244static void configure_mca(void)
245{
246 msr_t msr;
247 int i;
248
249 msr.lo = msr.hi = 0;
250 /* This should only be done on a cold boot */
251 for (i = 0; i < 7; i++)
252 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
253}
254
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200255/*
256 * Initialize any extra cores/threads in this package.
257 */
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100258static void intel_cores_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200259{
260 struct cpuid_result result;
261 unsigned threads_per_package, threads_per_core, i;
262
263 /* Logical processors (threads) per core */
264 result = cpuid_ext(0xb, 0);
265 threads_per_core = result.ebx & 0xffff;
266
267 /* Logical processors (threads) per package */
268 result = cpuid_ext(0xb, 1);
269 threads_per_package = result.ebx & 0xffff;
270
271 /* Only initialize extra cores from BSP */
272 if (cpu->path.apic.apic_id)
273 return;
274
275 printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
276 cpu->path.apic.apic_id, threads_per_package/threads_per_core,
277 threads_per_core);
278
279 for (i = 1; i < threads_per_package; ++i) {
280 struct device_path cpu_path;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100281 struct device *new;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200282
Elyes HAOUASd82be922016-07-28 18:58:27 +0200283 /* Build the CPU device path */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200284 cpu_path.type = DEVICE_PATH_APIC;
285 cpu_path.apic.apic_id =
Vladimir Serbinenko10b39742014-02-19 22:00:00 +0100286 cpu->path.apic.apic_id + (i % threads_per_core)
287 + ((i / threads_per_core) << 2);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200288
Elyes HAOUASd82be922016-07-28 18:58:27 +0200289 /* Allocate the new CPU device structure */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200290 new = alloc_dev(cpu->bus, &cpu_path);
291 if (!new)
292 continue;
293
294 printk(BIOS_DEBUG, "CPU: %u has core %u\n",
295 cpu->path.apic.apic_id,
296 new->path.apic.apic_id);
297
298#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
Elyes HAOUASd82be922016-07-28 18:58:27 +0200299 /* Start the new CPU */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200300 if (!start_cpu(new)) {
301 /* Record the error in cpu? */
302 printk(BIOS_ERR, "CPU %u would not start!\n",
303 new->path.apic.apic_id);
304 }
305#endif
306 }
307}
308
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100309static void model_2065x_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200310{
311 char processor_name[49];
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200312
313 /* Turn on caching if we haven't already */
314 x86_enable_cache();
315
316 intel_update_microcode_from_cbfs();
317
318 /* Clear out pending MCEs */
319 configure_mca();
320
321 /* Print processor name */
322 fill_processor_name(processor_name);
323 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
324 printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid (), boot_cpu ());
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200325
326 /* Setup MTRRs based on physical address size */
Aaron Durbin2a081372016-03-07 16:23:47 -0600327 x86_setup_mtrrs_with_detect();
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200328 x86_mtrr_check();
329
330 /* Setup Page Attribute Tables (PAT) */
331 // TODO set up PAT
332
Elyes HAOUASd6e96862016-08-21 10:12:15 +0200333 /* Enable the local CPU APICs */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200334 enable_lapic_tpr();
335 setup_lapic();
336
Matt DeVilliered6fe2f2016-12-14 16:12:43 -0600337 /* Set virtualization based on Kconfig option */
338 set_vmx();
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200339
340 /* Configure Enhanced SpeedStep and Thermal Sensors */
341 configure_misc();
342
343 /* Thermal throttle activation offset */
344 configure_thermal_target();
345
346 /* Set energy policy */
347 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
348
349 /* Set Max Ratio */
350 set_max_ratio();
351
352 /* Enable Turbo */
353 enable_turbo();
354
355 /* Start up extra cores */
356 intel_cores_init(cpu);
357}
358
359static struct device_operations cpu_dev_ops = {
360 .init = model_2065x_init,
361};
362
363static struct cpu_device_id cpu_table[] = {
Vladimir Serbinenko5ef42202014-02-01 16:24:22 +0100364 { X86_VENDOR_INTEL, 0x20652 }, /* Intel Nehalem */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200365 { X86_VENDOR_INTEL, 0x20655 }, /* Intel Nehalem */
366 { 0, 0 },
367};
368
369static const struct cpu_driver driver __cpu_driver = {
370 .ops = &cpu_dev_ops,
371 .id_table = cpu_table,
372 .cstates = cstate_map,
373};