blob: 289d4471e6851a45358ac35f343e9ca9f0df50ab [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
Arthur Heymansb66ee552018-05-15 16:35:45 +020018#include <assert.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020019#include <console/console.h>
20#include <device/device.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020021#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>
Arthur Heymansb66ee552018-05-15 16:35:45 +020026#include <cpu/x86/mp.h>
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020027#include <cpu/intel/microcode.h>
28#include <cpu/intel/speedstep.h>
29#include <cpu/intel/turbo.h>
30#include <cpu/x86/cache.h>
31#include <cpu/x86/name.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 */
Lee Leahy9d62e7e2017-03-15 17:40:50 -070045 }, { /* 1: C1 */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020046 .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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010053 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020054 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010064 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020065 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010075 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020076 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010086 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020087 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +010097 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +020098 }
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,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +0100108 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD,
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200109 }
110 },
111 { 0 }
112};
113
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200114int cpu_config_tdp_levels(void)
115{
116 msr_t platform_info;
117
118 /* Minimum CPU revision */
119 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
120 return 0;
121
122 /* Bits 34:33 indicate how many levels supported */
123 platform_info = rdmsr(MSR_PLATFORM_INFO);
124 return (platform_info.hi >> 1) & 3;
125}
126
127
128static void configure_thermal_target(void)
129{
130 struct cpu_intel_model_2065x_config *conf;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100131 struct device *lapic;
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200132 msr_t msr;
133
134 /* Find pointer to CPU configuration */
135 lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
136 if (!lapic || !lapic->chip_info)
137 return;
138 conf = lapic->chip_info;
139
Martin Roth4c3ab732013-07-08 16:23:54 -0600140 /* Set TCC activation offset if supported */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200141 msr = rdmsr(MSR_PLATFORM_INFO);
142 if ((msr.lo & (1 << 30)) && conf->tcc_offset) {
143 msr = rdmsr(MSR_TEMPERATURE_TARGET);
144 msr.lo &= ~(0xf << 24); /* Bits 27:24 */
145 msr.lo |= (conf->tcc_offset & 0xf) << 24;
146 wrmsr(MSR_TEMPERATURE_TARGET, msr);
147 }
148}
149
150static void configure_misc(void)
151{
152 msr_t msr;
153
154 msr = rdmsr(IA32_MISC_ENABLE);
155 msr.lo |= (1 << 0); /* Fast String enable */
Lee Leahy7b5f12b92017-03-15 17:16:59 -0700156 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200157 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
158 wrmsr(IA32_MISC_ENABLE, msr);
159
160 /* Disable Thermal interrupts */
161 msr.lo = 0;
162 msr.hi = 0;
163 wrmsr(IA32_THERM_INTERRUPT, msr);
164
165#ifdef DISABLED
166 /* Enable package critical interrupt only */
167 msr.lo = 1 << 4;
168 msr.hi = 0;
169 wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
170#endif
171}
172
173static void enable_lapic_tpr(void)
174{
175 msr_t msr;
176
177 msr = rdmsr(MSR_PIC_MSG_CONTROL);
178 msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
179 wrmsr(MSR_PIC_MSG_CONTROL, msr);
180}
181
182
183static void set_max_ratio(void)
184{
185 msr_t msr, perf_ctl;
186
187 perf_ctl.hi = 0;
188
189 /* Check for configurable TDP option */
190 if (cpu_config_tdp_levels()) {
191 /* Set to nominal TDP ratio */
192 msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
193 perf_ctl.lo = (msr.lo & 0xff) << 8;
194 } else {
195 /* Platform Info bits 15:8 give max ratio */
196 msr = rdmsr(MSR_PLATFORM_INFO);
197 perf_ctl.lo = msr.lo & 0xff00;
198 }
199 wrmsr(IA32_PERF_CTL, perf_ctl);
200
201 printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
Vladimir Serbinenko71f35eb2013-11-12 23:32:52 +0100202 ((perf_ctl.lo >> 8) & 0xff) * NEHALEM_BCLK);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200203}
204
205static void set_energy_perf_bias(u8 policy)
206{
207#ifdef DISABLED
208 msr_t msr;
209
210 /* Energy Policy is bits 3:0 */
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200211 msr = rdmsr(IA32_ENERGY_PERF_BIAS);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200212 msr.lo &= ~0xf;
213 msr.lo |= policy & 0xf;
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200214 wrmsr(IA32_ENERGY_PERF_BIAS, msr);
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200215
216 printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
217 policy);
218#endif
219}
220
221static void configure_mca(void)
222{
223 msr_t msr;
224 int i;
225
226 msr.lo = msr.hi = 0;
227 /* This should only be done on a cold boot */
228 for (i = 0; i < 7; i++)
229 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
230}
231
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100232static void model_2065x_init(struct device *cpu)
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200233{
234 char processor_name[49];
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200235
236 /* Turn on caching if we haven't already */
237 x86_enable_cache();
238
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200239 /* Clear out pending MCEs */
240 configure_mca();
241
242 /* Print processor name */
243 fill_processor_name(processor_name);
244 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
Lee Leahy9d62e7e2017-03-15 17:40:50 -0700245 printk(BIOS_INFO, "CPU:lapic=%ld, boot_cpu=%d\n", lapicid(),
246 boot_cpu());
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200247
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200248 /* Setup Page Attribute Tables (PAT) */
249 // TODO set up PAT
250
Elyes HAOUASd6e96862016-08-21 10:12:15 +0200251 /* Enable the local CPU APICs */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200252 enable_lapic_tpr();
253 setup_lapic();
254
Matt DeVilliered6fe2f2016-12-14 16:12:43 -0600255 /* Set virtualization based on Kconfig option */
Matt DeVillierf9aed652018-12-15 15:57:33 -0600256 set_vmx_and_lock();
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200257
258 /* Configure Enhanced SpeedStep and Thermal Sensors */
259 configure_misc();
260
261 /* Thermal throttle activation offset */
262 configure_thermal_target();
263
264 /* Set energy policy */
265 set_energy_perf_bias(ENERGY_POLICY_NORMAL);
266
267 /* Set Max Ratio */
268 set_max_ratio();
269
270 /* Enable Turbo */
271 enable_turbo();
Arthur Heymansb66ee552018-05-15 16:35:45 +0200272}
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200273
Arthur Heymansb66ee552018-05-15 16:35:45 +0200274/* MP initialization support. */
275static const void *microcode_patch;
276
277static void pre_mp_init(void)
278{
279 /* Setup MTRRs based on physical address size. */
280 x86_setup_mtrrs_with_detect();
281 x86_mtrr_check();
282}
283
284static int get_cpu_count(void)
285{
286 msr_t msr;
287 int num_threads;
288 int num_cores;
289
Elyes HAOUASa6a396d2019-05-26 13:25:30 +0200290 msr = rdmsr(MSR_CORE_THREAD_COUNT);
Arthur Heymansb66ee552018-05-15 16:35:45 +0200291 num_threads = (msr.lo >> 0) & 0xffff;
292 num_cores = (msr.lo >> 16) & 0xffff;
293 printk(BIOS_DEBUG, "CPU has %u cores, %u threads enabled.\n",
294 num_cores, num_threads);
295
296 return num_threads;
297}
298
299static void get_microcode_info(const void **microcode, int *parallel)
300{
301 microcode_patch = intel_microcode_find();
302 *microcode = microcode_patch;
303 *parallel = 1;
304}
305
306static void per_cpu_smm_trigger(void)
307{
308 /* Relocate the SMM handler. */
309 smm_relocate();
310
311 /* After SMM relocation a 2nd microcode load is required. */
312 intel_microcode_load_unlocked(microcode_patch);
313}
314
315static void post_mp_init(void)
316{
317 /* Now that all APs have been relocated as well as the BSP let SMIs
318 * start flowing. */
319 southbridge_smm_init();
320
321 /* Lock down the SMRAM space. */
322 smm_lock();
323}
324
325
326static const struct mp_ops mp_ops = {
327 .pre_mp_init = pre_mp_init,
328 .get_cpu_count = get_cpu_count,
329 .get_smm_info = smm_info,
330 .get_microcode_info = get_microcode_info,
331 .pre_mp_smm_init = smm_initialize,
332 .per_cpu_smm_trigger = per_cpu_smm_trigger,
333 .relocation_handler = smm_relocation_handler,
334 .post_mp_init = post_mp_init,
335};
336
337void bsp_init_and_start_aps(struct bus *cpu_bus)
338{
339 if (mp_init_with_smm(cpu_bus, &mp_ops))
340 printk(BIOS_ERR, "MP initialization failure.\n");
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200341}
342
343static struct device_operations cpu_dev_ops = {
344 .init = model_2065x_init,
345};
346
Jonathan Neuschäfer8f06ce32017-11-20 01:56:44 +0100347static const struct cpu_device_id cpu_table[] = {
Vladimir Serbinenko5ef42202014-02-01 16:24:22 +0100348 { X86_VENDOR_INTEL, 0x20652 }, /* Intel Nehalem */
Vladimir Serbinenko22dcdd92013-06-06 22:10:45 +0200349 { X86_VENDOR_INTEL, 0x20655 }, /* Intel Nehalem */
350 { 0, 0 },
351};
352
353static const struct cpu_driver driver __cpu_driver = {
354 .ops = &cpu_dev_ops,
355 .id_table = cpu_table,
356 .cstates = cstate_map,
357};