]>
Commit | Line | Data |
---|---|---|
2f3f477b SG |
1 | /* |
2 | * Copyright (c) 2016 Google, Inc | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0 | |
5 | * | |
6 | * Based on code from coreboot src/soc/intel/broadwell/cpu.c | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <dm.h> | |
11 | #include <cpu.h> | |
12 | #include <asm/cpu.h> | |
13 | #include <asm/cpu_x86.h> | |
14 | #include <asm/cpu_common.h> | |
15 | #include <asm/intel_regs.h> | |
16 | #include <asm/msr.h> | |
17 | #include <asm/post.h> | |
18 | #include <asm/turbo.h> | |
19 | #include <asm/arch/cpu.h> | |
20 | #include <asm/arch/pch.h> | |
21 | #include <asm/arch/rcb.h> | |
22 | ||
23 | struct cpu_broadwell_priv { | |
24 | bool ht_disabled; | |
25 | }; | |
26 | ||
27 | /* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */ | |
28 | static const u8 power_limit_time_sec_to_msr[] = { | |
29 | [0] = 0x00, | |
30 | [1] = 0x0a, | |
31 | [2] = 0x0b, | |
32 | [3] = 0x4b, | |
33 | [4] = 0x0c, | |
34 | [5] = 0x2c, | |
35 | [6] = 0x4c, | |
36 | [7] = 0x6c, | |
37 | [8] = 0x0d, | |
38 | [10] = 0x2d, | |
39 | [12] = 0x4d, | |
40 | [14] = 0x6d, | |
41 | [16] = 0x0e, | |
42 | [20] = 0x2e, | |
43 | [24] = 0x4e, | |
44 | [28] = 0x6e, | |
45 | [32] = 0x0f, | |
46 | [40] = 0x2f, | |
47 | [48] = 0x4f, | |
48 | [56] = 0x6f, | |
49 | [64] = 0x10, | |
50 | [80] = 0x30, | |
51 | [96] = 0x50, | |
52 | [112] = 0x70, | |
53 | [128] = 0x11, | |
54 | }; | |
55 | ||
56 | /* Convert POWER_LIMIT_1_TIME MSR value to seconds */ | |
57 | static const u8 power_limit_time_msr_to_sec[] = { | |
58 | [0x00] = 0, | |
59 | [0x0a] = 1, | |
60 | [0x0b] = 2, | |
61 | [0x4b] = 3, | |
62 | [0x0c] = 4, | |
63 | [0x2c] = 5, | |
64 | [0x4c] = 6, | |
65 | [0x6c] = 7, | |
66 | [0x0d] = 8, | |
67 | [0x2d] = 10, | |
68 | [0x4d] = 12, | |
69 | [0x6d] = 14, | |
70 | [0x0e] = 16, | |
71 | [0x2e] = 20, | |
72 | [0x4e] = 24, | |
73 | [0x6e] = 28, | |
74 | [0x0f] = 32, | |
75 | [0x2f] = 40, | |
76 | [0x4f] = 48, | |
77 | [0x6f] = 56, | |
78 | [0x10] = 64, | |
79 | [0x30] = 80, | |
80 | [0x50] = 96, | |
81 | [0x70] = 112, | |
82 | [0x11] = 128, | |
83 | }; | |
84 | ||
85 | int arch_cpu_init_dm(void) | |
86 | { | |
87 | struct udevice *dev; | |
88 | int ret; | |
89 | ||
90 | /* Start up the LPC so we have serial */ | |
91 | ret = uclass_first_device(UCLASS_LPC, &dev); | |
92 | if (ret) | |
93 | return ret; | |
94 | if (!dev) | |
95 | return -ENODEV; | |
96 | ret = cpu_set_flex_ratio_to_tdp_nominal(); | |
97 | if (ret) | |
98 | return ret; | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | void set_max_freq(void) | |
104 | { | |
105 | msr_t msr, perf_ctl, platform_info; | |
106 | ||
107 | /* Check for configurable TDP option */ | |
108 | platform_info = msr_read(MSR_PLATFORM_INFO); | |
109 | ||
110 | if ((platform_info.hi >> 1) & 3) { | |
111 | /* Set to nominal TDP ratio */ | |
112 | msr = msr_read(MSR_CONFIG_TDP_NOMINAL); | |
113 | perf_ctl.lo = (msr.lo & 0xff) << 8; | |
114 | } else { | |
115 | /* Platform Info bits 15:8 give max ratio */ | |
116 | msr = msr_read(MSR_PLATFORM_INFO); | |
117 | perf_ctl.lo = msr.lo & 0xff00; | |
118 | } | |
119 | ||
120 | perf_ctl.hi = 0; | |
121 | msr_write(IA32_PERF_CTL, perf_ctl); | |
122 | ||
123 | debug("CPU: frequency set to %d MHz\n", | |
124 | ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); | |
125 | } | |
126 | ||
127 | int arch_cpu_init(void) | |
128 | { | |
129 | post_code(POST_CPU_INIT); | |
130 | ||
131 | return x86_cpu_init_f(); | |
132 | } | |
133 | ||
134 | int print_cpuinfo(void) | |
135 | { | |
136 | char processor_name[CPU_MAX_NAME_LEN]; | |
137 | const char *name; | |
138 | int ret; | |
139 | ||
140 | set_max_freq(); | |
141 | ||
142 | ret = cpu_common_init(); | |
143 | if (ret) | |
144 | return ret; | |
145 | gd->arch.pei_boot_mode = PEI_BOOT_NONE; | |
146 | ||
147 | /* Print processor name */ | |
148 | name = cpu_get_name(processor_name); | |
149 | printf("CPU: %s\n", name); | |
150 | ||
151 | return 0; | |
152 | } | |
153 | ||
154 | /* | |
155 | * The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate | |
156 | * the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly | |
157 | * when a core is woken up | |
158 | */ | |
159 | static int pcode_ready(void) | |
160 | { | |
161 | int wait_count; | |
162 | const int delay_step = 10; | |
163 | ||
164 | wait_count = 0; | |
165 | do { | |
166 | if (!(readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & | |
167 | MAILBOX_RUN_BUSY)) | |
168 | return 0; | |
169 | wait_count += delay_step; | |
170 | udelay(delay_step); | |
171 | } while (wait_count < 1000); | |
172 | ||
173 | return -ETIMEDOUT; | |
174 | } | |
175 | ||
176 | static u32 pcode_mailbox_read(u32 command) | |
177 | { | |
178 | int ret; | |
179 | ||
180 | ret = pcode_ready(); | |
181 | if (ret) { | |
182 | debug("PCODE: mailbox timeout on wait ready\n"); | |
183 | return ret; | |
184 | } | |
185 | ||
186 | /* Send command and start transaction */ | |
187 | writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); | |
188 | ||
189 | ret = pcode_ready(); | |
190 | if (ret) { | |
191 | debug("PCODE: mailbox timeout on completion\n"); | |
192 | return ret; | |
193 | } | |
194 | ||
195 | /* Read mailbox */ | |
196 | return readl(MCHBAR_REG(BIOS_MAILBOX_DATA)); | |
197 | } | |
198 | ||
199 | static int pcode_mailbox_write(u32 command, u32 data) | |
200 | { | |
201 | int ret; | |
202 | ||
203 | ret = pcode_ready(); | |
204 | if (ret) { | |
205 | debug("PCODE: mailbox timeout on wait ready\n"); | |
206 | return ret; | |
207 | } | |
208 | ||
209 | writel(data, MCHBAR_REG(BIOS_MAILBOX_DATA)); | |
210 | ||
211 | /* Send command and start transaction */ | |
212 | writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); | |
213 | ||
214 | ret = pcode_ready(); | |
215 | if (ret) { | |
216 | debug("PCODE: mailbox timeout on completion\n"); | |
217 | return ret; | |
218 | } | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | /* @dev is the CPU device */ | |
224 | static void initialize_vr_config(struct udevice *dev) | |
225 | { | |
226 | int ramp, min_vid; | |
227 | msr_t msr; | |
228 | ||
229 | debug("Initializing VR config\n"); | |
230 | ||
231 | /* Configure VR_CURRENT_CONFIG */ | |
232 | msr = msr_read(MSR_VR_CURRENT_CONFIG); | |
233 | /* | |
234 | * Preserve bits 63 and 62. Bit 62 is PSI4 enable, but it is only valid | |
235 | * on ULT systems | |
236 | */ | |
237 | msr.hi &= 0xc0000000; | |
238 | msr.hi |= (0x01 << (52 - 32)); /* PSI3 threshold - 1A */ | |
239 | msr.hi |= (0x05 << (42 - 32)); /* PSI2 threshold - 5A */ | |
240 | msr.hi |= (0x14 << (32 - 32)); /* PSI1 threshold - 20A */ | |
241 | msr.hi |= (1 << (62 - 32)); /* Enable PSI4 */ | |
242 | /* Leave the max instantaneous current limit (12:0) to default */ | |
243 | msr_write(MSR_VR_CURRENT_CONFIG, msr); | |
244 | ||
245 | /* Configure VR_MISC_CONFIG MSR */ | |
246 | msr = msr_read(MSR_VR_MISC_CONFIG); | |
247 | /* Set the IOUT_SLOPE scalar applied to dIout in U10.1.9 format */ | |
248 | msr.hi &= ~(0x3ff << (40 - 32)); | |
249 | msr.hi |= (0x200 << (40 - 32)); /* 1.0 */ | |
250 | /* Set IOUT_OFFSET to 0 */ | |
251 | msr.hi &= ~0xff; | |
252 | /* Set entry ramp rate to slow */ | |
253 | msr.hi &= ~(1 << (51 - 32)); | |
254 | /* Enable decay mode on C-state entry */ | |
255 | msr.hi |= (1 << (52 - 32)); | |
256 | /* Set the slow ramp rate */ | |
257 | msr.hi &= ~(0x3 << (53 - 32)); | |
258 | /* Configure the C-state exit ramp rate */ | |
e160f7d4 SG |
259 | ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), |
260 | "intel,slow-ramp", -1); | |
2f3f477b SG |
261 | if (ramp != -1) { |
262 | /* Configured slow ramp rate */ | |
263 | msr.hi |= ((ramp & 0x3) << (53 - 32)); | |
264 | /* Set exit ramp rate to slow */ | |
265 | msr.hi &= ~(1 << (50 - 32)); | |
266 | } else { | |
267 | /* Fast ramp rate / 4 */ | |
268 | msr.hi |= (0x01 << (53 - 32)); | |
269 | /* Set exit ramp rate to fast */ | |
270 | msr.hi |= (1 << (50 - 32)); | |
271 | } | |
272 | /* Set MIN_VID (31:24) to allow CPU to have full control */ | |
273 | msr.lo &= ~0xff000000; | |
e160f7d4 SG |
274 | min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), |
275 | "intel,min-vid", 0); | |
2f3f477b SG |
276 | msr.lo |= (min_vid & 0xff) << 24; |
277 | msr_write(MSR_VR_MISC_CONFIG, msr); | |
278 | ||
279 | /* Configure VR_MISC_CONFIG2 MSR */ | |
280 | msr = msr_read(MSR_VR_MISC_CONFIG2); | |
281 | msr.lo &= ~0xffff; | |
282 | /* | |
283 | * Allow CPU to control minimum voltage completely (15:8) and | |
284 | * set the fast ramp voltage in 10mV steps | |
285 | */ | |
286 | if (cpu_get_family_model() == BROADWELL_FAMILY_ULT) | |
287 | msr.lo |= 0x006a; /* 1.56V */ | |
288 | else | |
289 | msr.lo |= 0x006f; /* 1.60V */ | |
290 | msr_write(MSR_VR_MISC_CONFIG2, msr); | |
291 | ||
292 | /* Set C9/C10 VCC Min */ | |
293 | pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE, 0x1f1f); | |
294 | } | |
295 | ||
296 | static int calibrate_24mhz_bclk(void) | |
297 | { | |
298 | int err_code; | |
299 | int ret; | |
300 | ||
301 | ret = pcode_ready(); | |
302 | if (ret) | |
303 | return ret; | |
304 | ||
305 | /* A non-zero value initiates the PCODE calibration */ | |
306 | writel(~0, MCHBAR_REG(BIOS_MAILBOX_DATA)); | |
307 | writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL, | |
308 | MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); | |
309 | ||
310 | ret = pcode_ready(); | |
311 | if (ret) | |
312 | return ret; | |
313 | ||
314 | err_code = readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & 0xff; | |
315 | ||
316 | debug("PCODE: 24MHz BLCK calibration response: %d\n", err_code); | |
317 | ||
318 | /* Read the calibrated value */ | |
319 | writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_READ_CALIBRATION, | |
320 | MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); | |
321 | ||
322 | ret = pcode_ready(); | |
323 | if (ret) | |
324 | return ret; | |
325 | ||
326 | debug("PCODE: 24MHz BLCK calibration value: 0x%08x\n", | |
327 | readl(MCHBAR_REG(BIOS_MAILBOX_DATA))); | |
328 | ||
329 | return 0; | |
330 | } | |
331 | ||
332 | static void configure_pch_power_sharing(void) | |
333 | { | |
334 | u32 pch_power, pch_power_ext, pmsync, pmsync2; | |
335 | int i; | |
336 | ||
337 | /* Read PCH Power levels from PCODE */ | |
338 | pch_power = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER); | |
339 | pch_power_ext = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT); | |
340 | ||
341 | debug("PCH Power: PCODE Levels 0x%08x 0x%08x\n", pch_power, | |
342 | pch_power_ext); | |
343 | ||
344 | pmsync = readl(RCB_REG(PMSYNC_CONFIG)); | |
345 | pmsync2 = readl(RCB_REG(PMSYNC_CONFIG2)); | |
346 | ||
347 | /* | |
348 | * Program PMSYNC_TPR_CONFIG PCH power limit values | |
349 | * pmsync[0:4] = mailbox[0:5] | |
350 | * pmsync[8:12] = mailbox[6:11] | |
351 | * pmsync[16:20] = mailbox[12:17] | |
352 | */ | |
353 | for (i = 0; i < 3; i++) { | |
354 | u32 level = pch_power & 0x3f; | |
355 | pch_power >>= 6; | |
356 | pmsync &= ~(0x1f << (i * 8)); | |
357 | pmsync |= (level & 0x1f) << (i * 8); | |
358 | } | |
359 | writel(pmsync, RCB_REG(PMSYNC_CONFIG)); | |
360 | ||
361 | /* | |
362 | * Program PMSYNC_TPR_CONFIG2 Extended PCH power limit values | |
363 | * pmsync2[0:4] = mailbox[23:18] | |
364 | * pmsync2[8:12] = mailbox_ext[6:11] | |
365 | * pmsync2[16:20] = mailbox_ext[12:17] | |
366 | * pmsync2[24:28] = mailbox_ext[18:22] | |
367 | */ | |
368 | pmsync2 &= ~0x1f; | |
369 | pmsync2 |= pch_power & 0x1f; | |
370 | ||
371 | for (i = 1; i < 4; i++) { | |
372 | u32 level = pch_power_ext & 0x3f; | |
373 | pch_power_ext >>= 6; | |
374 | pmsync2 &= ~(0x1f << (i * 8)); | |
375 | pmsync2 |= (level & 0x1f) << (i * 8); | |
376 | } | |
377 | writel(pmsync2, RCB_REG(PMSYNC_CONFIG2)); | |
378 | } | |
379 | ||
380 | static int bsp_init_before_ap_bringup(struct udevice *dev) | |
381 | { | |
382 | int ret; | |
383 | ||
384 | initialize_vr_config(dev); | |
385 | ret = calibrate_24mhz_bclk(); | |
386 | if (ret) | |
387 | return ret; | |
388 | configure_pch_power_sharing(); | |
389 | ||
390 | return 0; | |
391 | } | |
392 | ||
393 | int cpu_config_tdp_levels(void) | |
394 | { | |
395 | msr_t platform_info; | |
396 | ||
397 | /* Bits 34:33 indicate how many levels supported */ | |
398 | platform_info = msr_read(MSR_PLATFORM_INFO); | |
399 | return (platform_info.hi >> 1) & 3; | |
400 | } | |
401 | ||
402 | static void set_max_ratio(void) | |
403 | { | |
404 | msr_t msr, perf_ctl; | |
405 | ||
406 | perf_ctl.hi = 0; | |
407 | ||
408 | /* Check for configurable TDP option */ | |
409 | if (turbo_get_state() == TURBO_ENABLED) { | |
410 | msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT); | |
411 | perf_ctl.lo = (msr.lo & 0xff) << 8; | |
412 | } else if (cpu_config_tdp_levels()) { | |
413 | /* Set to nominal TDP ratio */ | |
414 | msr = msr_read(MSR_CONFIG_TDP_NOMINAL); | |
415 | perf_ctl.lo = (msr.lo & 0xff) << 8; | |
416 | } else { | |
417 | /* Platform Info bits 15:8 give max ratio */ | |
418 | msr = msr_read(MSR_PLATFORM_INFO); | |
419 | perf_ctl.lo = msr.lo & 0xff00; | |
420 | } | |
421 | msr_write(IA32_PERF_CTL, perf_ctl); | |
422 | ||
423 | debug("cpu: frequency set to %d\n", | |
424 | ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); | |
425 | } | |
426 | ||
427 | int broadwell_init(struct udevice *dev) | |
428 | { | |
429 | struct cpu_broadwell_priv *priv = dev_get_priv(dev); | |
430 | int num_threads; | |
431 | int num_cores; | |
432 | msr_t msr; | |
433 | int ret; | |
434 | ||
435 | msr = msr_read(CORE_THREAD_COUNT_MSR); | |
436 | num_threads = (msr.lo >> 0) & 0xffff; | |
437 | num_cores = (msr.lo >> 16) & 0xffff; | |
438 | debug("CPU has %u cores, %u threads enabled\n", num_cores, | |
439 | num_threads); | |
440 | ||
441 | priv->ht_disabled = num_threads == num_cores; | |
442 | ||
443 | ret = bsp_init_before_ap_bringup(dev); | |
444 | if (ret) | |
445 | return ret; | |
446 | ||
447 | set_max_ratio(); | |
448 | ||
449 | return ret; | |
450 | } | |
451 | ||
452 | static void configure_mca(void) | |
453 | { | |
454 | msr_t msr; | |
455 | const unsigned int mcg_cap_msr = 0x179; | |
456 | int i; | |
457 | int num_banks; | |
458 | ||
459 | msr = msr_read(mcg_cap_msr); | |
460 | num_banks = msr.lo & 0xff; | |
461 | msr.lo = 0; | |
462 | msr.hi = 0; | |
463 | /* | |
464 | * TODO(adurbin): This should only be done on a cold boot. Also, some | |
465 | * of these banks are core vs package scope. For now every CPU clears | |
466 | * every bank | |
467 | */ | |
468 | for (i = 0; i < num_banks; i++) | |
469 | msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr); | |
470 | } | |
471 | ||
472 | static void enable_lapic_tpr(void) | |
473 | { | |
474 | msr_t msr; | |
475 | ||
476 | msr = msr_read(MSR_PIC_MSG_CONTROL); | |
477 | msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */ | |
478 | msr_write(MSR_PIC_MSG_CONTROL, msr); | |
479 | } | |
480 | ||
481 | ||
482 | static void configure_c_states(void) | |
483 | { | |
484 | msr_t msr; | |
485 | ||
486 | msr = msr_read(MSR_PMG_CST_CONFIG_CONTROL); | |
487 | msr.lo |= (1 << 31); /* Timed MWAIT Enable */ | |
488 | msr.lo |= (1 << 30); /* Package c-state Undemotion Enable */ | |
489 | msr.lo |= (1 << 29); /* Package c-state Demotion Enable */ | |
490 | msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */ | |
491 | msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */ | |
492 | msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */ | |
493 | msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */ | |
494 | msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */ | |
495 | /* The deepest package c-state defaults to factory-configured value */ | |
496 | msr_write(MSR_PMG_CST_CONFIG_CONTROL, msr); | |
497 | ||
498 | msr = msr_read(MSR_MISC_PWR_MGMT); | |
499 | msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */ | |
500 | msr_write(MSR_MISC_PWR_MGMT, msr); | |
501 | ||
502 | msr = msr_read(MSR_POWER_CTL); | |
503 | msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */ | |
504 | msr.lo |= (1 << 1); /* C1E Enable */ | |
505 | msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */ | |
506 | msr_write(MSR_POWER_CTL, msr); | |
507 | ||
508 | /* C-state Interrupt Response Latency Control 0 - package C3 latency */ | |
509 | msr.hi = 0; | |
510 | msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_0_LIMIT; | |
511 | msr_write(MSR_C_STATE_LATENCY_CONTROL_0, msr); | |
512 | ||
513 | /* C-state Interrupt Response Latency Control 1 */ | |
514 | msr.hi = 0; | |
515 | msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_1_LIMIT; | |
516 | msr_write(MSR_C_STATE_LATENCY_CONTROL_1, msr); | |
517 | ||
518 | /* C-state Interrupt Response Latency Control 2 - package C6/C7 short */ | |
519 | msr.hi = 0; | |
520 | msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_2_LIMIT; | |
521 | msr_write(MSR_C_STATE_LATENCY_CONTROL_2, msr); | |
522 | ||
523 | /* C-state Interrupt Response Latency Control 3 - package C8 */ | |
524 | msr.hi = 0; | |
525 | msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_3_LIMIT; | |
526 | msr_write(MSR_C_STATE_LATENCY_CONTROL_3, msr); | |
527 | ||
528 | /* C-state Interrupt Response Latency Control 4 - package C9 */ | |
529 | msr.hi = 0; | |
530 | msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_4_LIMIT; | |
531 | msr_write(MSR_C_STATE_LATENCY_CONTROL_4, msr); | |
532 | ||
533 | /* C-state Interrupt Response Latency Control 5 - package C10 */ | |
534 | msr.hi = 0; | |
535 | msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_5_LIMIT; | |
536 | msr_write(MSR_C_STATE_LATENCY_CONTROL_5, msr); | |
537 | } | |
538 | ||
539 | static void configure_misc(void) | |
540 | { | |
541 | msr_t msr; | |
542 | ||
543 | msr = msr_read(MSR_IA32_MISC_ENABLE); | |
544 | msr.lo |= (1 << 0); /* Fast String enable */ | |
545 | msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ | |
546 | msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */ | |
547 | msr_write(MSR_IA32_MISC_ENABLE, msr); | |
548 | ||
549 | /* Disable thermal interrupts */ | |
550 | msr.lo = 0; | |
551 | msr.hi = 0; | |
552 | msr_write(MSR_IA32_THERM_INTERRUPT, msr); | |
553 | ||
554 | /* Enable package critical interrupt only */ | |
555 | msr.lo = 1 << 4; | |
556 | msr.hi = 0; | |
557 | msr_write(MSR_IA32_PACKAGE_THERM_INTERRUPT, msr); | |
558 | } | |
559 | ||
560 | static void configure_thermal_target(struct udevice *dev) | |
561 | { | |
562 | int tcc_offset; | |
563 | msr_t msr; | |
564 | ||
e160f7d4 | 565 | tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), |
2f3f477b SG |
566 | "intel,tcc-offset", 0); |
567 | ||
568 | /* Set TCC activaiton offset if supported */ | |
569 | msr = msr_read(MSR_PLATFORM_INFO); | |
570 | if ((msr.lo & (1 << 30)) && tcc_offset) { | |
571 | msr = msr_read(MSR_TEMPERATURE_TARGET); | |
572 | msr.lo &= ~(0xf << 24); /* Bits 27:24 */ | |
573 | msr.lo |= (tcc_offset & 0xf) << 24; | |
574 | msr_write(MSR_TEMPERATURE_TARGET, msr); | |
575 | } | |
576 | } | |
577 | ||
578 | static void configure_dca_cap(void) | |
579 | { | |
580 | struct cpuid_result cpuid_regs; | |
581 | msr_t msr; | |
582 | ||
583 | /* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */ | |
584 | cpuid_regs = cpuid(1); | |
585 | if (cpuid_regs.ecx & (1 << 18)) { | |
586 | msr = msr_read(MSR_IA32_PLATFORM_DCA_CAP); | |
587 | msr.lo |= 1; | |
588 | msr_write(MSR_IA32_PLATFORM_DCA_CAP, msr); | |
589 | } | |
590 | } | |
591 | ||
592 | static void set_energy_perf_bias(u8 policy) | |
593 | { | |
594 | msr_t msr; | |
595 | int ecx; | |
596 | ||
597 | /* Determine if energy efficient policy is supported */ | |
598 | ecx = cpuid_ecx(0x6); | |
599 | if (!(ecx & (1 << 3))) | |
600 | return; | |
601 | ||
602 | /* Energy Policy is bits 3:0 */ | |
603 | msr = msr_read(MSR_IA32_ENERGY_PERFORMANCE_BIAS); | |
604 | msr.lo &= ~0xf; | |
605 | msr.lo |= policy & 0xf; | |
606 | msr_write(MSR_IA32_ENERGY_PERFORMANCE_BIAS, msr); | |
607 | ||
608 | debug("cpu: energy policy set to %u\n", policy); | |
609 | } | |
610 | ||
611 | /* All CPUs including BSP will run the following function */ | |
612 | static void cpu_core_init(struct udevice *dev) | |
613 | { | |
614 | /* Clear out pending MCEs */ | |
615 | configure_mca(); | |
616 | ||
617 | /* Enable the local cpu apics */ | |
618 | enable_lapic_tpr(); | |
619 | ||
620 | /* Configure C States */ | |
621 | configure_c_states(); | |
622 | ||
623 | /* Configure Enhanced SpeedStep and Thermal Sensors */ | |
624 | configure_misc(); | |
625 | ||
626 | /* Thermal throttle activation offset */ | |
627 | configure_thermal_target(dev); | |
628 | ||
629 | /* Enable Direct Cache Access */ | |
630 | configure_dca_cap(); | |
631 | ||
632 | /* Set energy policy */ | |
633 | set_energy_perf_bias(ENERGY_POLICY_NORMAL); | |
634 | ||
635 | /* Enable Turbo */ | |
636 | turbo_enable(); | |
637 | } | |
638 | ||
639 | /* | |
640 | * Configure processor power limits if possible | |
641 | * This must be done AFTER set of BIOS_RESET_CPL | |
642 | */ | |
643 | void cpu_set_power_limits(int power_limit_1_time) | |
644 | { | |
645 | msr_t msr; | |
646 | msr_t limit; | |
647 | unsigned power_unit; | |
648 | unsigned tdp, min_power, max_power, max_time; | |
649 | u8 power_limit_1_val; | |
650 | ||
651 | msr = msr_read(MSR_PLATFORM_INFO); | |
652 | if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr)) | |
653 | power_limit_1_time = 28; | |
654 | ||
655 | if (!(msr.lo & PLATFORM_INFO_SET_TDP)) | |
656 | return; | |
657 | ||
658 | /* Get units */ | |
659 | msr = msr_read(MSR_PKG_POWER_SKU_UNIT); | |
660 | power_unit = 2 << ((msr.lo & 0xf) - 1); | |
661 | ||
662 | /* Get power defaults for this SKU */ | |
663 | msr = msr_read(MSR_PKG_POWER_SKU); | |
664 | tdp = msr.lo & 0x7fff; | |
665 | min_power = (msr.lo >> 16) & 0x7fff; | |
666 | max_power = msr.hi & 0x7fff; | |
667 | max_time = (msr.hi >> 16) & 0x7f; | |
668 | ||
669 | debug("CPU TDP: %u Watts\n", tdp / power_unit); | |
670 | ||
671 | if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time) | |
672 | power_limit_1_time = power_limit_time_msr_to_sec[max_time]; | |
673 | ||
674 | if (min_power > 0 && tdp < min_power) | |
675 | tdp = min_power; | |
676 | ||
677 | if (max_power > 0 && tdp > max_power) | |
678 | tdp = max_power; | |
679 | ||
680 | power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time]; | |
681 | ||
682 | /* Set long term power limit to TDP */ | |
683 | limit.lo = 0; | |
684 | limit.lo |= tdp & PKG_POWER_LIMIT_MASK; | |
685 | limit.lo |= PKG_POWER_LIMIT_EN; | |
686 | limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) << | |
687 | PKG_POWER_LIMIT_TIME_SHIFT; | |
688 | ||
689 | /* Set short term power limit to 1.25 * TDP */ | |
690 | limit.hi = 0; | |
691 | limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK; | |
692 | limit.hi |= PKG_POWER_LIMIT_EN; | |
693 | /* Power limit 2 time is only programmable on server SKU */ | |
694 | ||
695 | msr_write(MSR_PKG_POWER_LIMIT, limit); | |
696 | ||
697 | /* Set power limit values in MCHBAR as well */ | |
698 | writel(limit.lo, MCHBAR_REG(MCH_PKG_POWER_LIMIT_LO)); | |
699 | writel(limit.hi, MCHBAR_REG(MCH_PKG_POWER_LIMIT_HI)); | |
700 | ||
701 | /* Set DDR RAPL power limit by copying from MMIO to MSR */ | |
702 | msr.lo = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_LO)); | |
703 | msr.hi = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_HI)); | |
704 | msr_write(MSR_DDR_RAPL_LIMIT, msr); | |
705 | ||
706 | /* Use nominal TDP values for CPUs with configurable TDP */ | |
707 | if (cpu_config_tdp_levels()) { | |
708 | msr = msr_read(MSR_CONFIG_TDP_NOMINAL); | |
709 | limit.hi = 0; | |
710 | limit.lo = msr.lo & 0xff; | |
711 | msr_write(MSR_TURBO_ACTIVATION_RATIO, limit); | |
712 | } | |
713 | } | |
714 | ||
715 | static int broadwell_get_info(struct udevice *dev, struct cpu_info *info) | |
716 | { | |
717 | msr_t msr; | |
718 | ||
719 | msr = msr_read(IA32_PERF_CTL); | |
720 | info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000; | |
721 | info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | | |
722 | 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; | |
723 | ||
724 | return 0; | |
725 | } | |
726 | ||
727 | static int broadwell_get_count(struct udevice *dev) | |
728 | { | |
729 | return 4; | |
730 | } | |
731 | ||
732 | static int cpu_x86_broadwell_probe(struct udevice *dev) | |
733 | { | |
734 | if (dev->seq == 0) { | |
735 | cpu_core_init(dev); | |
736 | return broadwell_init(dev); | |
737 | } | |
738 | ||
739 | return 0; | |
740 | } | |
741 | ||
742 | static const struct cpu_ops cpu_x86_broadwell_ops = { | |
743 | .get_desc = cpu_x86_get_desc, | |
744 | .get_info = broadwell_get_info, | |
745 | .get_count = broadwell_get_count, | |
94eaa79c | 746 | .get_vendor = cpu_x86_get_vendor, |
2f3f477b SG |
747 | }; |
748 | ||
749 | static const struct udevice_id cpu_x86_broadwell_ids[] = { | |
750 | { .compatible = "intel,core-i3-gen5" }, | |
751 | { } | |
752 | }; | |
753 | ||
754 | U_BOOT_DRIVER(cpu_x86_broadwell_drv) = { | |
755 | .name = "cpu_x86_broadwell", | |
756 | .id = UCLASS_CPU, | |
757 | .of_match = cpu_x86_broadwell_ids, | |
758 | .bind = cpu_x86_bind, | |
759 | .probe = cpu_x86_broadwell_probe, | |
760 | .ops = &cpu_x86_broadwell_ops, | |
761 | .priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv), | |
762 | }; |