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