]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
50dd3da0 | 2 | /* |
a2752090 | 3 | * Copyright (C) 2014 Google Inc. |
50dd3da0 | 4 | * Copyright (c) 2016 Google, Inc |
a2752090 SG |
5 | * Copyright (C) 2015-2018 Intel Corporation. |
6 | * Copyright (C) 2018 Siemens AG | |
7 | * Some code taken from coreboot cpulib.c | |
50dd3da0 SG |
8 | */ |
9 | ||
d678a59d | 10 | #include <common.h> |
d3abc5d1 | 11 | #include <cpu.h> |
50dd3da0 SG |
12 | #include <dm.h> |
13 | #include <errno.h> | |
f7ae49fc | 14 | #include <log.h> |
6c0da2da | 15 | #include <acpi/acpigen.h> |
a2752090 | 16 | #include <asm/cpu.h> |
50dd3da0 | 17 | #include <asm/cpu_common.h> |
401d1c4f | 18 | #include <asm/global_data.h> |
50dd3da0 SG |
19 | #include <asm/intel_regs.h> |
20 | #include <asm/lapic.h> | |
21 | #include <asm/lpc_common.h> | |
22 | #include <asm/msr.h> | |
23 | #include <asm/mtrr.h> | |
24 | #include <asm/post.h> | |
25 | #include <asm/microcode.h> | |
26 | ||
27 | DECLARE_GLOBAL_DATA_PTR; | |
28 | ||
29 | static int report_bist_failure(void) | |
30 | { | |
31 | if (gd->arch.bist != 0) { | |
32 | post_code(POST_BIST_FAILURE); | |
33 | printf("BIST failed: %08x\n", gd->arch.bist); | |
34 | return -EFAULT; | |
35 | } | |
36 | ||
37 | return 0; | |
38 | } | |
39 | ||
40 | int cpu_common_init(void) | |
41 | { | |
42 | struct udevice *dev, *lpc; | |
43 | int ret; | |
44 | ||
45 | /* Halt if there was a built in self test failure */ | |
46 | ret = report_bist_failure(); | |
47 | if (ret) | |
48 | return ret; | |
49 | ||
50 | enable_lapic(); | |
51 | ||
52 | ret = microcode_update_intel(); | |
fda4fa81 SG |
53 | if (ret && ret != -EEXIST) { |
54 | debug("%s: Microcode update failure (err=%d)\n", __func__, ret); | |
50dd3da0 | 55 | return ret; |
fda4fa81 | 56 | } |
50dd3da0 SG |
57 | |
58 | /* Enable upper 128bytes of CMOS */ | |
59 | writel(1 << 2, RCB_REG(RC)); | |
60 | ||
61 | /* Early chipset init required before RAM init can work */ | |
62 | uclass_first_device(UCLASS_NORTHBRIDGE, &dev); | |
63 | ||
c726fc01 | 64 | ret = uclass_first_device_err(UCLASS_LPC, &lpc); |
50dd3da0 SG |
65 | if (ret) |
66 | return ret; | |
50dd3da0 SG |
67 | |
68 | /* Cause the SATA device to do its early init */ | |
a219639d | 69 | uclass_first_device(UCLASS_AHCI, &dev); |
50dd3da0 SG |
70 | |
71 | return 0; | |
72 | } | |
73 | ||
74 | int cpu_set_flex_ratio_to_tdp_nominal(void) | |
75 | { | |
76 | msr_t flex_ratio, msr; | |
77 | u8 nominal_ratio; | |
78 | ||
79 | /* Check for Flex Ratio support */ | |
80 | flex_ratio = msr_read(MSR_FLEX_RATIO); | |
81 | if (!(flex_ratio.lo & FLEX_RATIO_EN)) | |
82 | return -EINVAL; | |
83 | ||
84 | /* Check for >0 configurable TDPs */ | |
85 | msr = msr_read(MSR_PLATFORM_INFO); | |
86 | if (((msr.hi >> 1) & 3) == 0) | |
87 | return -EINVAL; | |
88 | ||
89 | /* Use nominal TDP ratio for flex ratio */ | |
90 | msr = msr_read(MSR_CONFIG_TDP_NOMINAL); | |
91 | nominal_ratio = msr.lo & 0xff; | |
92 | ||
93 | /* See if flex ratio is already set to nominal TDP ratio */ | |
94 | if (((flex_ratio.lo >> 8) & 0xff) == nominal_ratio) | |
95 | return 0; | |
96 | ||
97 | /* Set flex ratio to nominal TDP ratio */ | |
98 | flex_ratio.lo &= ~0xff00; | |
99 | flex_ratio.lo |= nominal_ratio << 8; | |
100 | flex_ratio.lo |= FLEX_RATIO_LOCK; | |
101 | msr_write(MSR_FLEX_RATIO, flex_ratio); | |
102 | ||
103 | /* Set flex ratio in soft reset data register bits 11:6 */ | |
104 | clrsetbits_le32(RCB_REG(SOFT_RESET_DATA), 0x3f << 6, | |
105 | (nominal_ratio & 0x3f) << 6); | |
106 | ||
107 | debug("CPU: Soft reset to set up flex ratio\n"); | |
108 | ||
109 | /* Set soft reset control to use register value */ | |
110 | setbits_le32(RCB_REG(SOFT_RESET_CTRL), 1); | |
111 | ||
112 | /* Issue warm reset, will be "CPU only" due to soft reset data */ | |
2a605d4d SG |
113 | outb(0x0, IO_PORT_RESET); |
114 | outb(SYS_RST | RST_CPU, IO_PORT_RESET); | |
50dd3da0 SG |
115 | cpu_hlt(); |
116 | ||
117 | /* Not reached */ | |
118 | return -EINVAL; | |
119 | } | |
d3abc5d1 SG |
120 | |
121 | int cpu_intel_get_info(struct cpu_info *info, int bclk) | |
122 | { | |
123 | msr_t msr; | |
124 | ||
e2493a7f | 125 | msr = msr_read(MSR_IA32_PERF_CTL); |
d3abc5d1 SG |
126 | info->cpu_freq = ((msr.lo >> 8) & 0xff) * bclk * 1000000; |
127 | info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | | |
128 | 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; | |
aec7c1c5 | 129 | info->address_width = cpu_phys_address_size(); |
d3abc5d1 SG |
130 | |
131 | return 0; | |
132 | } | |
246ac08b SG |
133 | |
134 | int cpu_configure_thermal_target(struct udevice *dev) | |
135 | { | |
136 | u32 tcc_offset; | |
137 | msr_t msr; | |
138 | int ret; | |
139 | ||
140 | ret = dev_read_u32(dev, "tcc-offset", &tcc_offset); | |
141 | if (!ret) | |
142 | return -ENOENT; | |
143 | ||
144 | /* Set TCC activaiton offset if supported */ | |
145 | msr = msr_read(MSR_PLATFORM_INFO); | |
146 | if (msr.lo & (1 << 30)) { | |
147 | msr = msr_read(MSR_TEMPERATURE_TARGET); | |
148 | msr.lo &= ~(0xf << 24); /* Bits 27:24 */ | |
149 | msr.lo |= (tcc_offset & 0xf) << 24; | |
150 | msr_write(MSR_TEMPERATURE_TARGET, msr); | |
151 | } | |
152 | ||
153 | return 0; | |
154 | } | |
2f0c2f03 SG |
155 | |
156 | void cpu_set_perf_control(uint clk_ratio) | |
157 | { | |
158 | msr_t perf_ctl; | |
159 | ||
160 | perf_ctl.lo = (clk_ratio & 0xff) << 8; | |
161 | perf_ctl.hi = 0; | |
162 | msr_write(MSR_IA32_PERF_CTL, perf_ctl); | |
163 | debug("CPU: frequency set to %d MHz\n", clk_ratio * INTEL_BCLK_MHZ); | |
164 | } | |
165 | ||
166 | bool cpu_config_tdp_levels(void) | |
167 | { | |
168 | msr_t platform_info; | |
169 | ||
170 | /* Bits 34:33 indicate how many levels supported */ | |
171 | platform_info = msr_read(MSR_PLATFORM_INFO); | |
172 | ||
173 | return ((platform_info.hi >> 1) & 3) != 0; | |
174 | } | |
a2752090 SG |
175 | |
176 | void cpu_set_p_state_to_turbo_ratio(void) | |
177 | { | |
178 | msr_t msr; | |
179 | ||
180 | msr = msr_read(MSR_TURBO_RATIO_LIMIT); | |
181 | cpu_set_perf_control(msr.lo); | |
182 | } | |
183 | ||
184 | enum burst_mode_t cpu_get_burst_mode_state(void) | |
185 | { | |
186 | enum burst_mode_t state; | |
187 | int burst_en, burst_cap; | |
188 | msr_t msr; | |
189 | uint eax; | |
190 | ||
191 | eax = cpuid_eax(0x6); | |
192 | burst_cap = eax & 0x2; | |
193 | msr = msr_read(MSR_IA32_MISC_ENABLE); | |
194 | burst_en = !(msr.hi & BURST_MODE_DISABLE); | |
195 | ||
196 | if (!burst_cap && burst_en) | |
197 | state = BURST_MODE_UNAVAILABLE; | |
198 | else if (burst_cap && !burst_en) | |
199 | state = BURST_MODE_DISABLED; | |
200 | else if (burst_cap && burst_en) | |
201 | state = BURST_MODE_ENABLED; | |
202 | else | |
203 | state = BURST_MODE_UNKNOWN; | |
204 | ||
205 | return state; | |
206 | } | |
207 | ||
208 | void cpu_set_burst_mode(bool burst_mode) | |
209 | { | |
210 | msr_t msr; | |
211 | ||
212 | msr = msr_read(MSR_IA32_MISC_ENABLE); | |
213 | if (burst_mode) | |
214 | msr.hi &= ~BURST_MODE_DISABLE; | |
215 | else | |
216 | msr.hi |= BURST_MODE_DISABLE; | |
217 | msr_write(MSR_IA32_MISC_ENABLE, msr); | |
218 | } | |
219 | ||
220 | void cpu_set_eist(bool eist_status) | |
221 | { | |
222 | msr_t msr; | |
223 | ||
224 | msr = msr_read(MSR_IA32_MISC_ENABLE); | |
225 | if (eist_status) | |
226 | msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP; | |
227 | else | |
228 | msr.lo &= ~MISC_ENABLE_ENHANCED_SPEEDSTEP; | |
229 | msr_write(MSR_IA32_MISC_ENABLE, msr); | |
230 | } | |
6c0da2da SG |
231 | |
232 | int cpu_get_coord_type(void) | |
233 | { | |
234 | return HW_ALL; | |
235 | } | |
236 | ||
237 | int cpu_get_min_ratio(void) | |
238 | { | |
239 | msr_t msr; | |
240 | ||
241 | /* Get bus ratio limits and calculate clock speeds */ | |
242 | msr = msr_read(MSR_PLATFORM_INFO); | |
243 | ||
244 | return (msr.hi >> 8) & 0xff; /* Max Efficiency Ratio */ | |
245 | } | |
246 | ||
247 | int cpu_get_max_ratio(void) | |
248 | { | |
249 | u32 ratio_max; | |
250 | msr_t msr; | |
251 | ||
252 | if (cpu_config_tdp_levels()) { | |
253 | /* Set max ratio to nominal TDP ratio */ | |
254 | msr = msr_read(MSR_CONFIG_TDP_NOMINAL); | |
255 | ratio_max = msr.lo & 0xff; | |
256 | } else { | |
257 | msr = msr_read(MSR_PLATFORM_INFO); | |
258 | /* Max Non-Turbo Ratio */ | |
259 | ratio_max = (msr.lo >> 8) & 0xff; | |
260 | } | |
261 | ||
262 | return ratio_max; | |
263 | } | |
264 | ||
265 | int cpu_get_bus_clock_khz(void) | |
266 | { | |
267 | /* | |
268 | * CPU bus clock is set by default here to 100MHz. This function returns | |
269 | * the bus clock in KHz. | |
270 | */ | |
271 | return INTEL_BCLK_MHZ * 1000; | |
272 | } | |
273 | ||
274 | int cpu_get_power_max(void) | |
275 | { | |
276 | int power_unit; | |
277 | msr_t msr; | |
278 | ||
279 | msr = msr_read(MSR_PKG_POWER_SKU_UNIT); | |
280 | power_unit = 2 << ((msr.lo & 0xf) - 1); | |
281 | msr = msr_read(MSR_PKG_POWER_SKU); | |
282 | ||
283 | return (msr.lo & 0x7fff) * 1000 / power_unit; | |
284 | } | |
285 | ||
286 | int cpu_get_max_turbo_ratio(void) | |
287 | { | |
288 | msr_t msr; | |
289 | ||
290 | msr = msr_read(MSR_TURBO_RATIO_LIMIT); | |
291 | ||
292 | return msr.lo & 0xff; | |
293 | } | |
9b3e6d4c SG |
294 | |
295 | int cpu_get_cores_per_package(void) | |
296 | { | |
297 | struct cpuid_result result; | |
298 | int cores = 1; | |
299 | ||
300 | if (gd->arch.x86_vendor != X86_VENDOR_INTEL) | |
301 | return 1; | |
302 | ||
303 | result = cpuid_ext(0xb, 1); | |
304 | cores = result.ebx & 0xff; | |
305 | ||
306 | return cores; | |
307 | } | |
6571d873 SG |
308 | |
309 | void cpu_mca_configure(void) | |
310 | { | |
311 | msr_t msr; | |
312 | int i; | |
313 | int num_banks; | |
314 | ||
315 | msr = msr_read(MSR_IA32_MCG_CAP); | |
316 | num_banks = msr.lo & 0xff; | |
317 | msr.lo = 0; | |
318 | msr.hi = 0; | |
319 | for (i = 0; i < num_banks; i++) { | |
320 | /* Clear the machine check status */ | |
321 | msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr); | |
322 | /* Initialise machine checks */ | |
323 | msr_write(MSR_IA32_MC0_CTL + i * 4, | |
324 | (msr_t) {.lo = 0xffffffff, .hi = 0xffffffff}); | |
325 | } | |
326 | } |