Merge branch 'master' of git://git.denx.de/u-boot-arm
[oweals/u-boot.git] / arch / x86 / cpu / baytrail / cpu.c
1 /*
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
19 static int enable_smis(struct udevice *cpu, void *unused)
20 {
21         return 0;
22 }
23
24 static 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
30 static 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
55 static 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
76 int 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
86 static 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
114 static 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
140 static 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
157 static 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
170 static 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
178 static 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
188 static const struct cpu_ops cpu_x86_baytrail_ops = {
189         .get_desc       = x86_cpu_get_desc,
190         .get_info       = baytrail_get_info,
191 };
192
193 static const struct udevice_id cpu_x86_baytrail_ids[] = {
194         { .compatible = "intel,baytrail-cpu" },
195         { }
196 };
197
198 U_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 };