blob: ce2b9e552ffcad1a0abf43dedcd66f78e8a79788 [file] [log] [blame]
Thomas Jourdan1a692d82009-07-01 17:01:17 +00001/*
2 * This file is part of the coreboot project.
Stefan Reinauer14e22772010-04-27 06:56:47 +00003 *
Thomas Jourdan1a692d82009-07-01 17:01:17 +00004 * Copyright (C) 2007-2009 coresystems GmbH
Nico Huber68d7c7a2012-10-02 11:46:11 +02005 * 2012 secunet Security Networks AG
Thomas Jourdan1a692d82009-07-01 17:01:17 +00006 *
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.
Thomas Jourdan1a692d82009-07-01 17:01:17 +000016 */
17
18#include <console/console.h>
19#include <device/device.h>
Thomas Jourdan1a692d82009-07-01 17:01:17 +000020#include <cpu/cpu.h>
Thomas Jourdan1a692d82009-07-01 17:01:17 +000021#include <cpu/x86/msr.h>
Arthur Heymans6336d4c2018-01-25 21:38:25 +010022#include <cpu/x86/mp.h>
Thomas Jourdan1a692d82009-07-01 17:01:17 +000023#include <cpu/x86/lapic.h>
Stefan Reinauer2a27b202010-12-11 22:14:44 +000024#include <cpu/intel/speedstep.h>
Thomas Jourdan1a692d82009-07-01 17:01:17 +000025#include <cpu/x86/cache.h>
Uwe Hermannaac8f662010-09-29 09:54:16 +000026#include <cpu/x86/name.h>
Kyösti Mälkkif091f4d2019-08-14 03:49:21 +030027#include <cpu/intel/smm_reloc.h>
Matt DeVilliered6fe2f2016-12-14 16:12:43 -060028#include <cpu/intel/common/common.h>
Nico Huber68d7c7a2012-10-02 11:46:11 +020029#include "chip.h"
30
Thomas Jourdan1a692d82009-07-01 17:01:17 +000031static void init_timer(void)
32{
Elyes HAOUASd6e96862016-08-21 10:12:15 +020033 /* Set the APIC timer to no interrupts and periodic mode */
Lee Leahy9d62e7e2017-03-15 17:40:50 -070034 lapic_write(LAPIC_LVTT, (1 << 17) | (1 << 16) | (0 << 12) | (0 << 0));
Thomas Jourdan1a692d82009-07-01 17:01:17 +000035
36 /* Set the divider to 1, no divider */
37 lapic_write(LAPIC_TDCR, LAPIC_TDR_DIV_1);
38
39 /* Set the initial counter to 0xffffffff */
40 lapic_write(LAPIC_TMICT, 0xffffffff);
41}
42
Nico Huber68d7c7a2012-10-02 11:46:11 +020043#define MSR_BBL_CR_CTL3 0x11e
Thomas Jourdan1a692d82009-07-01 17:01:17 +000044
Nico Huber68d7c7a2012-10-02 11:46:11 +020045static void configure_c_states(const int quad)
Thomas Jourdan1a692d82009-07-01 17:01:17 +000046{
47 msr_t msr;
48
Nico Huber68d7c7a2012-10-02 11:46:11 +020049 /* Find pointer to CPU configuration. */
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110050 const struct device *lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
Nico Huber68d7c7a2012-10-02 11:46:11 +020051 const struct cpu_intel_model_1067x_config *const conf =
52 (lapic && lapic->chip_info) ? lapic->chip_info : NULL;
53
54 /* Is C5 requested and supported? */
55 const int c5 = conf && conf->c5 &&
56 (rdmsr(MSR_BBL_CR_CTL3).lo & (3 << 30)) &&
57 !(rdmsr(MSR_FSB_FREQ).lo & (1 << 31));
58 /* Is C6 requested and supported? */
59 const int c6 = conf && conf->c6 &&
60 ((cpuid_edx(5) >> (6 * 4)) & 0xf) && c5;
61
62 const int cst_range = (c6 ? 6 : (c5 ? 5 : 4)) - 2; /* zero means lvl2 */
63
Elyes HAOUAS4e6b7902018-10-02 08:44:47 +020064 msr = rdmsr(MSR_PKG_CST_CONFIG_CONTROL);
Thomas Jourdan1a692d82009-07-01 17:01:17 +000065 msr.lo &= ~(1 << 9); // Issue a single stop grant cycle upon stpclk
Nico Huber68d7c7a2012-10-02 11:46:11 +020066 msr.lo |= (1 << 8);
Lee Leahy26eeb0f2017-03-15 18:08:50 -070067 if (quad)
Nico Huber68d7c7a2012-10-02 11:46:11 +020068 msr.lo = (msr.lo & ~(7 << 0)) | (4 << 0);
Nico Huber68d7c7a2012-10-02 11:46:11 +020069 if (c5) {
70 msr.lo &= ~(1 << 13);
71 msr.lo &= ~(7 << 0);
72 msr.lo |= (1 << 3); /* Enable dynamic L2. */
73 msr.lo |= (1 << 14); /* Enable deeper sleep */
74 }
75 /* Next two fields seem to be mutually exclusive: */
76 msr.lo &= ~(7 << 4);
77 msr.lo |= (1 << 10); /* Enable IO MWAIT redirection. */
78 if (c6)
79 msr.lo |= (1 << 25);
Elyes HAOUAS4e6b7902018-10-02 08:44:47 +020080 wrmsr(MSR_PKG_CST_CONFIG_CONTROL, msr);
Thomas Jourdan1a692d82009-07-01 17:01:17 +000081
82 /* Set Processor MWAIT IO BASE */
83 msr.hi = 0;
Lee Leahycdc50482017-03-15 18:26:18 -070084 msr.lo = ((PMB0_BASE + 4) & 0xffff) | (((PMB1_BASE + 9) & 0xffff)
85 << 16);
Patrick Georgi644e83b2013-02-09 15:35:30 +010086 wrmsr(MSR_PMG_IO_BASE_ADDR, msr);
Thomas Jourdan1a692d82009-07-01 17:01:17 +000087
88 /* Set IO Capture Address */
89 msr.hi = 0;
Nico Huber68d7c7a2012-10-02 11:46:11 +020090 msr.lo = ((PMB0_BASE + 4) & 0xffff) | ((cst_range & 0xffff) << 16);
Patrick Georgi644e83b2013-02-09 15:35:30 +010091 wrmsr(MSR_PMG_IO_CAPTURE_ADDR, msr);
Nico Huber68d7c7a2012-10-02 11:46:11 +020092
93 if (c5) {
94 msr = rdmsr(MSR_BBL_CR_CTL3);
95 msr.lo &= ~(7 << 25);
96 msr.lo |= (2 << 25);
97 msr.lo &= ~(3 << 30);
98 msr.lo |= (1 << 30);
99 wrmsr(MSR_BBL_CR_CTL3, msr);
100 }
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000101}
102
Nico Huber68d7c7a2012-10-02 11:46:11 +0200103static void configure_p_states(const char stepping, const char cores)
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000104{
105 msr_t msr;
106
Nico Huber68d7c7a2012-10-02 11:46:11 +0200107 /* Find pointer to CPU configuration. */
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100108 const struct device *lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
Nico Huber68d7c7a2012-10-02 11:46:11 +0200109 struct cpu_intel_model_1067x_config *const conf =
110 (lapic && lapic->chip_info) ? lapic->chip_info : NULL;
111
112 msr = rdmsr(MSR_EXTENDED_CONFIG);
Patrick Georgif17c58b2014-08-09 20:48:12 +0200113 /* Super LFM supported? */
114 if (conf && conf->slfm && (msr.lo & (1 << 27)))
Nico Huber68d7c7a2012-10-02 11:46:11 +0200115 msr.lo |= (1 << 28); /* Enable Super LFM. */
116 wrmsr(MSR_EXTENDED_CONFIG, msr);
117
118 if (rdmsr(MSR_FSB_CLOCK_VCC).hi & (1 << (63 - 32))) {
119 /* Turbo supported? */
120 if ((stepping == 0xa) && (cores < 4)) {
121 msr = rdmsr(MSR_FSB_FREQ);
122 msr.lo |= (1 << 3); /* Enable hysteresis. */
123 wrmsr(MSR_FSB_FREQ, msr);
124 }
125 msr = rdmsr(IA32_PERF_CTL);
126 msr.hi &= ~(1 << (32 - 32)); /* Clear turbo disable. */
127 wrmsr(IA32_PERF_CTL, msr);
128 }
129
Elyes HAOUAS4e6b7902018-10-02 08:44:47 +0200130 msr = rdmsr(MSR_PKG_CST_CONFIG_CONTROL);
Nico Huber68d7c7a2012-10-02 11:46:11 +0200131 msr.lo &= ~(1 << 11); /* Enable hw coordination. */
132 msr.lo |= (1 << 15); /* Lock config until next reset. */
Elyes HAOUAS4e6b7902018-10-02 08:44:47 +0200133 wrmsr(MSR_PKG_CST_CONFIG_CONTROL, msr);
Nico Huber68d7c7a2012-10-02 11:46:11 +0200134}
135
136#define MSR_EMTTM_CR_TABLE(x) (0xa8 + (x))
137#define MSR_EMTTM_TABLE_NUM 6
138static void configure_emttm_tables(void)
139{
140 int i;
141 int num_states, pstate_idx;
142 msr_t msr;
143 sst_table_t pstates;
144
145 /* Gather p-state information. */
146 speedstep_gen_pstates(&pstates);
147
148 /* Never turbo mode or Super LFM. */
149 num_states = pstates.num_states;
150 if (pstates.states[0].is_turbo)
151 --num_states;
152 if (pstates.states[pstates.num_states - 1].is_slfm)
153 --num_states;
154 /* Repeat lowest p-state if we haven't enough states. */
155 const int num_lowest_pstate =
156 (num_states < MSR_EMTTM_TABLE_NUM)
157 ? (MSR_EMTTM_TABLE_NUM - num_states) + 1
158 : 1;
159 /* Start from the lowest entry but skip Super LFM. */
160 if (pstates.states[pstates.num_states - 1].is_slfm)
161 pstate_idx = pstates.num_states - 2;
162 else
163 pstate_idx = pstates.num_states - 1;
164 for (i = 0; i < MSR_EMTTM_TABLE_NUM; ++i) {
165 if (i >= num_lowest_pstate)
166 --pstate_idx;
167 const sst_state_t *const pstate = &pstates.states[pstate_idx];
168 printk(BIOS_DEBUG, "writing P-State %d: %d, %d, "
169 "%2d, 0x%02x, %d; encoded: 0x%04x\n",
170 pstate_idx, pstate->dynfsb, pstate->nonint,
171 pstate->ratio, pstate->vid, pstate->power,
172 SPEEDSTEP_ENCODE_STATE(*pstate));
173 msr.hi = 0;
174 msr.lo = SPEEDSTEP_ENCODE_STATE(pstates.states[pstate_idx]) &
175 /* Don't set half ratios. */
176 ~SPEEDSTEP_RATIO_NONINT;
177 wrmsr(MSR_EMTTM_CR_TABLE(i), msr);
178 }
179
180 msr = rdmsr(MSR_EMTTM_CR_TABLE(5));
181 msr.lo |= (1 << 31); /* lock tables */
182 wrmsr(MSR_EMTTM_CR_TABLE(5), msr);
183}
184
185static void configure_misc(const int eist, const int tm2, const int emttm)
186{
187 msr_t msr;
188
189 const u32 sub_cstates = cpuid_edx(5);
190
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200191 msr = rdmsr(IA32_MISC_ENABLE);
Nico Huber68d7c7a2012-10-02 11:46:11 +0200192 msr.lo |= (1 << 3); /* TM1 enable */
193 if (tm2)
194 msr.lo |= (1 << 13); /* TM2 enable */
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000195 msr.lo |= (1 << 17); /* Bidirectional PROCHOT# */
Nico Huber68d7c7a2012-10-02 11:46:11 +0200196 msr.lo |= (1 << 18); /* MONITOR/MWAIT enable */
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000197
198 msr.lo |= (1 << 10); /* FERR# multiplexing */
199
Nico Huber68d7c7a2012-10-02 11:46:11 +0200200 if (eist)
201 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000202
203 /* Enable C2E */
Lee Leahy26eeb0f2017-03-15 18:08:50 -0700204 if (((sub_cstates >> (2 * 4)) & 0xf) >= 2)
Nico Huber68d7c7a2012-10-02 11:46:11 +0200205 msr.lo |= (1 << 26);
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000206
207 /* Enable C4E */
Nico Huber68d7c7a2012-10-02 11:46:11 +0200208 if (((sub_cstates >> (4 * 4)) & 0xf) >= 2) {
209 msr.hi |= (1 << (32 - 32)); // C4E
210 msr.hi |= (1 << (33 - 32)); // Hard C4E
211 }
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000212
Nico Huber68d7c7a2012-10-02 11:46:11 +0200213 /* Enable EMTTM */
214 if (emttm)
215 msr.hi |= (1 << (36 - 32));
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000216
Nico Huber68d7c7a2012-10-02 11:46:11 +0200217 /* Enable turbo mode */
218 if (rdmsr(MSR_FSB_CLOCK_VCC).hi & (1 << (63 - 32)))
219 msr.hi &= ~(1 << (38 - 32));
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000220
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200221 wrmsr(IA32_MISC_ENABLE, msr);
Nico Huber68d7c7a2012-10-02 11:46:11 +0200222
223 if (eist) {
224 msr.lo |= (1 << 20); /* Lock Enhanced SpeedStep Enable */
Elyes HAOUAS419bfbc2018-10-01 08:47:51 +0200225 wrmsr(IA32_MISC_ENABLE, msr);
Nico Huber68d7c7a2012-10-02 11:46:11 +0200226 }
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000227}
228
229#define PIC_SENS_CFG 0x1aa
Nico Huber68d7c7a2012-10-02 11:46:11 +0200230static void configure_pic_thermal_sensors(const int tm2, const int quad)
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000231{
232 msr_t msr;
233
234 msr = rdmsr(PIC_SENS_CFG);
235
Nico Huber68d7c7a2012-10-02 11:46:11 +0200236 if (quad)
237 msr.lo |= (1 << 31);
238 else
239 msr.lo &= ~(1 << 31);
240 if (tm2)
241 msr.lo |= (1 << 20); /* Enable TM1 if TM2 fails. */
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000242 msr.lo |= (1 << 21); // inter-core lock TM1
Nico Huber68d7c7a2012-10-02 11:46:11 +0200243 msr.lo |= (1 << 4); // Enable bypass filter /* What does it do? */
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000244
245 wrmsr(PIC_SENS_CFG, msr);
246}
247
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100248static void model_1067x_init(struct device *cpu)
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000249{
250 char processor_name[49];
251
Nico Huber68d7c7a2012-10-02 11:46:11 +0200252
253 /* Gather some information: */
254
255 const struct cpuid_result cpuid1 = cpuid(1);
256
257 /* Read stepping. */
258 const char stepping = cpuid1.eax & 0xf;
259 /* Read number of cores. */
260 const char cores = (cpuid1.ebx >> 16) & 0xf;
261 /* Is this a quad core? */
262 const char quad = cores > 2;
263 /* Is this even a multiprocessor? */
264 const char mp = cores > 1;
265
266 /* Enable EMTTM on uni- and on multi-processors if it's not disabled. */
267 const char emttm = !mp || !(rdmsr(MSR_EXTENDED_CONFIG).lo & 4);
268
269 /* Is enhanced speedstep supported? */
270 const char eist = (cpuid1.ecx & (1 << 7)) &&
271 !(rdmsr(IA32_PLATFORM_ID).lo & (1 << 17));
272 /* Test for TM2 only if EIST is available. */
273 const char tm2 = eist && (cpuid1.ecx & (1 << 8));
274
275
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000276 /* Turn on caching if we haven't already */
277 x86_enable_cache();
278
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000279 /* Print processor name */
280 fill_processor_name(processor_name);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000281 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000282
Elyes HAOUASd6e96862016-08-21 10:12:15 +0200283 /* Enable the local CPU APICs */
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000284 setup_lapic();
285
286 /* Initialize the APIC timer */
287 init_timer();
288
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000289 /* Configure C States */
Nico Huber68d7c7a2012-10-02 11:46:11 +0200290 configure_c_states(quad);
291
292 /* Configure P States */
293 configure_p_states(stepping, cores);
294
295 /* EMTTM */
296 if (emttm)
297 configure_emttm_tables();
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000298
299 /* Configure Enhanced SpeedStep and Thermal Sensors */
Nico Huber68d7c7a2012-10-02 11:46:11 +0200300 configure_misc(eist, tm2, emttm);
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000301
302 /* PIC thermal sensor control */
Nico Huber68d7c7a2012-10-02 11:46:11 +0200303 configure_pic_thermal_sensors(tm2, quad);
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000304}
305
306static struct device_operations cpu_dev_ops = {
307 .init = model_1067x_init,
308};
309
Jonathan Neuschäfer8f06ce32017-11-20 01:56:44 +0100310static const struct cpu_device_id cpu_table[] = {
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000311 { X86_VENDOR_INTEL, 0x10676 }, /* Intel Core 2 Solo/Core Duo */
Stefan Reinauerc104cb02010-10-18 00:21:39 +0000312 { X86_VENDOR_INTEL, 0x10677 },
313 { X86_VENDOR_INTEL, 0x1067A },
Thomas Jourdan1a692d82009-07-01 17:01:17 +0000314 { 0, 0 },
315};
316
317static const struct cpu_driver driver __cpu_driver = {
318 .ops = &cpu_dev_ops,
319 .id_table = cpu_table,
320};
321
Nico Huber68d7c7a2012-10-02 11:46:11 +0200322struct chip_operations cpu_intel_model_1067x_ops = {
323 CHIP_NAME("Intel Penryn CPU")
324};