blob: 1d482064b2324c187e2611889022518a609a898e [file] [log] [blame]
Simon Glassede97092015-04-29 22:26:02 -06001/*
2 * Copyright (C) 2015 Google, Inc
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 *
6 * Based on code from coreboot
7 */
8
9#include <common.h>
10#include <cpu.h>
11#include <dm.h>
12#include <asm/cpu.h>
13#include <asm/lapic.h>
14#include <asm/mp.h>
15#include <asm/msr.h>
16#include <asm/turbo.h>
17
18#ifdef CONFIG_SMP
19static int enable_smis(struct udevice *cpu, void *unused)
20{
21 return 0;
22}
23
24static struct mp_flight_record mp_steps[] = {
25 MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
26 /* Wait for APs to finish initialization before proceeding. */
27 MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
28};
29
30static int detect_num_cpus(void)
31{
32 int ecx = 0;
33
34 /*
35 * Use the algorithm described in Intel 64 and IA-32 Architectures
36 * Software Developer's Manual Volume 3 (3A, 3B & 3C): System
37 * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
38 * of CPUID Extended Topology Leaf.
39 */
40 while (1) {
41 struct cpuid_result leaf_b;
42
43 leaf_b = cpuid_ext(0xb, ecx);
44
45 /*
46 * Bay Trail doesn't have hyperthreading so just determine the
47 * number of cores by from level type (ecx[15:8] == * 2)
48 */
49 if ((leaf_b.ecx & 0xff00) == 0x0200)
50 return leaf_b.ebx & 0xffff;
51 ecx++;
52 }
53}
54
55static int baytrail_init_cpus(void)
56{
57 struct mp_params mp_params;
58
59 lapic_setup();
60
61 mp_params.num_cpus = detect_num_cpus();
62 mp_params.parallel_microcode_load = 0,
63 mp_params.flight_plan = &mp_steps[0];
64 mp_params.num_records = ARRAY_SIZE(mp_steps);
65 mp_params.microcode_pointer = 0;
66
67 if (mp_init(&mp_params)) {
68 printf("Warning: MP init failure\n");
69 return -EIO;
70 }
71
72 return 0;
73}
74#endif
75
76int x86_init_cpus(void)
77{
78#ifdef CONFIG_SMP
79 debug("Init additional CPUs\n");
80 baytrail_init_cpus();
81#endif
82
83 return 0;
84}
85
86static void set_max_freq(void)
87{
88 msr_t perf_ctl;
89 msr_t msr;
90
91 /* Enable speed step */
92 msr = msr_read(MSR_IA32_MISC_ENABLES);
93 msr.lo |= (1 << 16);
94 msr_write(MSR_IA32_MISC_ENABLES, msr);
95
96 /*
97 * Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of
98 * the PERF_CTL
99 */
100 msr = msr_read(MSR_IACORE_RATIOS);
101 perf_ctl.lo = (msr.lo & 0x3f0000) >> 8;
102
103 /*
104 * Set guaranteed vid [21:16] from IACORE_VIDS to bits [7:0] of
105 * the PERF_CTL
106 */
107 msr = msr_read(MSR_IACORE_VIDS);
108 perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16;
109 perf_ctl.hi = 0;
110
111 msr_write(MSR_IA32_PERF_CTL, perf_ctl);
112}
113
114static int cpu_x86_baytrail_probe(struct udevice *dev)
115{
116 debug("Init BayTrail core\n");
117
118 /*
119 * On BayTrail the turbo disable bit is actually scoped at the
120 * building-block level, not package. For non-BSP cores that are
121 * within a building block, enable turbo. The cores within the BSP's
122 * building block will just see it already enabled and move on.
123 */
124 if (lapicid())
125 turbo_enable();
126
127 /* Dynamic L2 shrink enable and threshold */
128 msr_clrsetbits_64(MSR_PMG_CST_CONFIG_CONTROL, 0x3f000f, 0xe0008),
129
130 /* Disable C1E */
131 msr_clrsetbits_64(MSR_POWER_CTL, 2, 0);
132 msr_setbits_64(MSR_POWER_MISC, 0x44);
133
134 /* Set this core to max frequency ratio */
135 set_max_freq();
136
137 return 0;
138}
139
140static unsigned bus_freq(void)
141{
142 msr_t clk_info = msr_read(MSR_BSEL_CR_OVERCLOCK_CONTROL);
143 switch (clk_info.lo & 0x3) {
144 case 0:
145 return 83333333;
146 case 1:
147 return 100000000;
148 case 2:
149 return 133333333;
150 case 3:
151 return 116666666;
152 default:
153 return 0;
154 }
155}
156
157static unsigned long tsc_freq(void)
158{
159 msr_t platform_info;
160 ulong bclk = bus_freq();
161
162 if (!bclk)
163 return 0;
164
165 platform_info = msr_read(MSR_PLATFORM_INFO);
166
167 return bclk * ((platform_info.lo >> 8) & 0xff);
168}
169
170static int baytrail_get_info(struct udevice *dev, struct cpu_info *info)
171{
172 info->cpu_freq = tsc_freq();
173 info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU;
174
175 return 0;
176}
177
178static int cpu_x86_baytrail_bind(struct udevice *dev)
179{
180 struct cpu_platdata *plat = dev_get_parent_platdata(dev);
181
182 plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
183 "intel,apic-id", -1);
184
185 return 0;
186}
187
188static const struct cpu_ops cpu_x86_baytrail_ops = {
189 .get_desc = x86_cpu_get_desc,
190 .get_info = baytrail_get_info,
191};
192
193static const struct udevice_id cpu_x86_baytrail_ids[] = {
194 { .compatible = "intel,baytrail-cpu" },
195 { }
196};
197
198U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
199 .name = "cpu_x86_baytrail",
200 .id = UCLASS_CPU,
201 .of_match = cpu_x86_baytrail_ids,
202 .bind = cpu_x86_baytrail_bind,
203 .probe = cpu_x86_baytrail_probe,
204 .ops = &cpu_x86_baytrail_ops,
205};