blob: 7994f0bb2c98120f08e945538b32f679e22d101d [file] [log] [blame]
Martin Roth58562402015-10-11 10:36:26 +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 * Copyright (C) 2014 Sage Electronic Engineering, LLC.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; version 2 of
11 * the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Martin Roth58562402015-10-11 10:36:26 +020017 */
18
19#include <console/console.h>
20#include <device/pci.h>
21#include <cpu/cpu.h>
22#include <cpu/x86/mtrr.h>
23#include <cpu/x86/msr.h>
24#include <cpu/x86/lapic.h>
David Guckiand35c2642015-11-14 16:01:33 +000025#include <cpu/intel/microcode.h>
Martin Roth58562402015-10-11 10:36:26 +020026#include <cpu/x86/cache.h>
27#include <cpu/x86/name.h>
Matt DeVilliered6fe2f2016-12-14 16:12:43 -060028#include <cpu/intel/common/common.h>
Martin Roth58562402015-10-11 10:36:26 +020029#include "model_406dx.h"
30#include "chip.h"
31
Martin Roth58562402015-10-11 10:36:26 +020032int cpu_config_tdp_levels(void)
33{
34 msr_t platform_info;
35
36 /* Minimum CPU revision */
37 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
38 return 0;
39
40 /* Bits 34:33 indicate how many levels supported */
41 platform_info = rdmsr(MSR_PLATFORM_INFO);
42 return (platform_info.hi >> 1) & 3;
43}
44
45static void configure_misc(void)
46{
47 msr_t msr;
48
49 msr = rdmsr(IA32_MISC_ENABLE);
50 msr.lo |= (1 << 0); /* Fast String enable */
51 msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
52 msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
53 wrmsr(IA32_MISC_ENABLE, msr);
54
55 /* Disable Thermal interrupts */
56 msr.lo = 0;
57 msr.hi = 0;
58 wrmsr(IA32_THERM_INTERRUPT, msr);
59}
60
61static void configure_mca(void)
62{
63 msr_t msr;
64 int i;
65
66 msr.lo = msr.hi = 0;
67 /* This should only be done on a cold boot */
68 for (i = 0; i < 6; i++)
69 wrmsr(IA32_MC0_STATUS + (i * 4), msr);
70}
71
72/*
73 * Initialize any extra cores/threads in this package.
74 */
75static void intel_cores_init(struct device *cpu)
76{
77 struct cpuid_result result;
Lee Leahy73a28942017-03-15 17:52:06 -070078 unsigned int threads_per_package, threads_per_core, i;
Martin Roth58562402015-10-11 10:36:26 +020079
80 /* Logical processors (threads) per core */
81 result = cpuid_ext(0xb, 0);
82 threads_per_core = result.ebx & 0xffff;
83
84 /* Logical processors (threads) per package */
85 result = cpuid_ext(0xb, 1);
86 threads_per_package = result.ebx & 0xffff;
87
88 /* Only initialize extra cores from BSP */
89 if (cpu->path.apic.apic_id)
90 return;
91
92 printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
93 cpu->path.apic.apic_id, threads_per_package/threads_per_core,
94 threads_per_core);
95
96 for (i = 1; i < threads_per_package; ++i) {
97 struct device_path cpu_path;
98 struct device *new;
99
Elyes HAOUASd82be922016-07-28 18:58:27 +0200100 /* Build the CPU device path */
Martin Roth58562402015-10-11 10:36:26 +0200101 cpu_path.type = DEVICE_PATH_APIC;
102 cpu_path.apic.apic_id =
103 cpu->path.apic.apic_id + i;
104
105 /* Update APIC ID if no hyperthreading */
106 if (threads_per_core == 1)
107 cpu_path.apic.apic_id <<= 1;
108
Elyes HAOUASd82be922016-07-28 18:58:27 +0200109 /* Allocate the new CPU device structure */
Martin Roth58562402015-10-11 10:36:26 +0200110 new = alloc_dev(cpu->bus, &cpu_path);
111 if (!new)
112 continue;
113
114 printk(BIOS_DEBUG, "CPU: %u has core %u\n",
115 cpu->path.apic.apic_id,
116 new->path.apic.apic_id);
117
Elyes HAOUASd82be922016-07-28 18:58:27 +0200118 /* Start the new CPU */
Kyösti Mälkki0cc2ce42017-08-18 11:46:32 +0300119 if (is_smp_boot() && !start_cpu(new)) {
Martin Roth58562402015-10-11 10:36:26 +0200120 /* Record the error in cpu? */
121 printk(BIOS_ERR, "CPU %u would not start!\n",
122 new->path.apic.apic_id);
123 }
Martin Roth58562402015-10-11 10:36:26 +0200124 }
125}
126
127static void model_406dx_init(struct device *cpu)
128{
129 char processor_name[49];
130
131 /* Turn on caching if we haven't already */
132 x86_enable_cache();
133
David Guckiand35c2642015-11-14 16:01:33 +0000134 /* Load microcode */
Martin Rothea7b6362015-11-05 09:00:20 -0700135 if (IS_ENABLED(CONFIG_SUPPORT_CPU_UCODE_IN_CBFS))
136 intel_update_microcode_from_cbfs();
David Guckiand35c2642015-11-14 16:01:33 +0000137
Martin Roth58562402015-10-11 10:36:26 +0200138 /* Clear out pending MCEs */
139 configure_mca();
140
141 /* Print processor name */
142 fill_processor_name(processor_name);
143 printk(BIOS_INFO, "CPU: %s.\n", processor_name);
144
145 x86_mtrr_check();
146
Elyes HAOUASd6e96862016-08-21 10:12:15 +0200147 /* Enable the local CPU APICs */
Martin Roth58562402015-10-11 10:36:26 +0200148 setup_lapic();
149
Matt DeVilliered6fe2f2016-12-14 16:12:43 -0600150 /* Set virtualization based on Kconfig option */
Matt DeVillierf9aed652018-12-15 15:57:33 -0600151 set_vmx_and_lock();
Martin Roth58562402015-10-11 10:36:26 +0200152
153 /* Configure Enhanced SpeedStep and Thermal Sensors */
154 configure_misc();
155
156 /* Start up extra cores */
157 intel_cores_init(cpu);
158}
159
160static struct device_operations cpu_dev_ops = {
161 .init = model_406dx_init,
162};
163
Jonathan Neuschäfer8f06ce32017-11-20 01:56:44 +0100164static const struct cpu_device_id cpu_table[] = {
Martin Roth58562402015-10-11 10:36:26 +0200165 { X86_VENDOR_INTEL, 0x406d0 }, /* Intel Avoton/Rangeley A1 */
166 { X86_VENDOR_INTEL, 0x406d8 }, /* Intel Avoton/Rangeley B0 */
167 { 0, 0 },
168};
169
170static const struct cpu_driver driver __cpu_driver = {
171 .ops = &cpu_dev_ops,
172 .id_table = cpu_table,
173};