1
2
3
4
5
6
7
8
9#include <common.h>
10#include <bootstage.h>
11#include <dm.h>
12#include <log.h>
13#include <malloc.h>
14#include <time.h>
15#include <timer.h>
16#include <asm/cpu.h>
17#include <asm/global_data.h>
18#include <asm/io.h>
19#include <asm/i8254.h>
20#include <asm/ibmpc.h>
21#include <asm/msr.h>
22#include <asm/u-boot-x86.h>
23#include <linux/delay.h>
24
25#define MAX_NUM_FREQS 9
26
27#define INTEL_FAM6_SKYLAKE_MOBILE 0x4E
28#define INTEL_FAM6_ATOM_GOLDMONT 0x5C
29#define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E
30#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F
31#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E
32#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E
33
34DECLARE_GLOBAL_DATA_PTR;
35
36
37
38
39
40static unsigned long native_calibrate_tsc(void)
41{
42 struct cpuid_result tsc_info;
43 unsigned int crystal_freq;
44
45 if (gd->arch.x86_vendor != X86_VENDOR_INTEL)
46 return 0;
47
48 if (cpuid_eax(0) < 0x15)
49 return 0;
50
51 tsc_info = cpuid(0x15);
52
53 if (tsc_info.ebx == 0 || tsc_info.eax == 0)
54 return 0;
55
56 crystal_freq = tsc_info.ecx / 1000;
57 if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) {
58 switch (gd->arch.x86_model) {
59 case INTEL_FAM6_SKYLAKE_MOBILE:
60 case INTEL_FAM6_SKYLAKE_DESKTOP:
61 case INTEL_FAM6_KABYLAKE_MOBILE:
62 case INTEL_FAM6_KABYLAKE_DESKTOP:
63 crystal_freq = 24000;
64 break;
65 case INTEL_FAM6_ATOM_GOLDMONT_X:
66 crystal_freq = 25000;
67 break;
68 case INTEL_FAM6_ATOM_GOLDMONT:
69 crystal_freq = 19200;
70 break;
71 default:
72 return 0;
73 }
74 }
75
76 return (crystal_freq * tsc_info.ebx / tsc_info.eax) / 1000;
77}
78
79static unsigned long cpu_mhz_from_cpuid(void)
80{
81 if (gd->arch.x86_vendor != X86_VENDOR_INTEL)
82 return 0;
83
84 if (cpuid_eax(0) < 0x16)
85 return 0;
86
87 return cpuid_eax(0x16);
88}
89
90
91
92
93
94
95
96
97
98struct freq_desc {
99 u8 x86_family;
100 u8 x86_model;
101
102 u8 msr_plat;
103 u32 freqs[MAX_NUM_FREQS];
104};
105
106static struct freq_desc freq_desc_tables[] = {
107
108 { 6, 0x27, 0, { 0, 0, 0, 0, 0, 99840, 0, 83200, 0 } },
109
110 { 6, 0x35, 0, { 0, 133200, 0, 0, 0, 99840, 0, 83200, 0 } },
111
112 { 6, 0x4a, 1, { 0, 100000, 133300, 0, 0, 0, 0, 0, 0 } },
113
114 { 6, 0x37, 1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0, 0 } },
115
116 { 6, 0x5a, 1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0, 0 } },
117
118 { 6, 0x4c, 1, { 83300, 100000, 133300, 116700,
119 80000, 93300, 90000, 88900, 87500 } },
120
121 { 6, 0x3a, 2, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
122};
123
124static int match_cpu(u8 family, u8 model)
125{
126 int i;
127
128 for (i = 0; i < ARRAY_SIZE(freq_desc_tables); i++) {
129 if ((family == freq_desc_tables[i].x86_family) &&
130 (model == freq_desc_tables[i].x86_model))
131 return i;
132 }
133
134 return -1;
135}
136
137
138#define id_to_freq(cpu_index, freq_id) \
139 (freq_desc_tables[cpu_index].freqs[freq_id])
140
141
142
143
144
145
146
147
148
149
150
151static unsigned long __maybe_unused cpu_mhz_from_msr(void)
152{
153 u32 lo, hi, ratio, freq_id, freq;
154 unsigned long res;
155 int cpu_index;
156
157 if (gd->arch.x86_vendor != X86_VENDOR_INTEL)
158 return 0;
159
160 cpu_index = match_cpu(gd->arch.x86, gd->arch.x86_model);
161 if (cpu_index < 0)
162 return 0;
163
164 if (freq_desc_tables[cpu_index].msr_plat) {
165 rdmsr(MSR_PLATFORM_INFO, lo, hi);
166 ratio = (lo >> 8) & 0xff;
167 } else {
168 rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
169 ratio = (hi >> 8) & 0x1f;
170 }
171 debug("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
172
173 if (freq_desc_tables[cpu_index].msr_plat == 2) {
174
175 freq = 100000;
176 debug("Using frequency: %u KHz\n", freq);
177 } else {
178
179 rdmsr(MSR_FSB_FREQ, lo, hi);
180 freq_id = lo & 0x7;
181 freq = id_to_freq(cpu_index, freq_id);
182 debug("Resolved frequency ID: %u, frequency: %u KHz\n",
183 freq_id, freq);
184 }
185
186
187 res = freq * ratio / 1000;
188 debug("TSC runs at %lu MHz\n", res);
189
190 return res;
191}
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228static inline int pit_verify_msb(unsigned char val)
229{
230
231 inb(0x42);
232 return inb(0x42) == val;
233}
234
235static inline int pit_expect_msb(unsigned char val, u64 *tscp,
236 unsigned long *deltap)
237{
238 int count;
239 u64 tsc = 0, prev_tsc = 0;
240
241 for (count = 0; count < 50000; count++) {
242 if (!pit_verify_msb(val))
243 break;
244 prev_tsc = tsc;
245 tsc = rdtsc();
246 }
247 *deltap = rdtsc() - prev_tsc;
248 *tscp = tsc;
249
250
251
252
253
254 return count > 5;
255}
256
257
258
259
260
261
262
263#define MAX_QUICK_PIT_MS 50
264#define MAX_QUICK_PIT_ITERATIONS (MAX_QUICK_PIT_MS * PIT_TICK_RATE / 1000 / 256)
265
266static unsigned long __maybe_unused quick_pit_calibrate(void)
267{
268 int i;
269 u64 tsc, delta;
270 unsigned long d1, d2;
271
272
273 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
274
275
276
277
278
279
280
281
282
283
284 outb(0xb0, 0x43);
285
286
287 outb(0xff, 0x42);
288 outb(0xff, 0x42);
289
290
291
292
293
294
295
296 pit_verify_msb(0);
297
298 if (pit_expect_msb(0xff, &tsc, &d1)) {
299 for (i = 1; i <= MAX_QUICK_PIT_ITERATIONS; i++) {
300 if (!pit_expect_msb(0xff-i, &delta, &d2))
301 break;
302
303
304
305
306 delta -= tsc;
307 if (d1+d2 >= delta >> 11)
308 continue;
309
310
311
312
313
314
315
316
317 if (!pit_verify_msb(0xfe - i))
318 break;
319 goto success;
320 }
321 }
322 debug("Fast TSC calibration failed\n");
323 return 0;
324
325success:
326
327
328
329
330
331
332
333
334
335
336
337
338
339 delta *= PIT_TICK_RATE;
340 delta /= (i*256*1000);
341 debug("Fast TSC calibration using PIT\n");
342 return delta / 1000;
343}
344
345
346unsigned notrace long get_tbclk_mhz(void)
347{
348 return get_tbclk() / 1000000;
349}
350
351static ulong get_ms_timer(void)
352{
353 return (get_ticks() * 1000) / get_tbclk();
354}
355
356ulong get_timer(ulong base)
357{
358 return get_ms_timer() - base;
359}
360
361ulong notrace timer_get_us(void)
362{
363 return get_ticks() / get_tbclk_mhz();
364}
365
366ulong timer_get_boot_us(void)
367{
368 return timer_get_us();
369}
370
371void __udelay(unsigned long usec)
372{
373 u64 now = get_ticks();
374 u64 stop;
375
376 stop = now + (u64)usec * get_tbclk_mhz();
377
378 while ((int64_t)(stop - get_ticks()) > 0)
379#if defined(CONFIG_QEMU) && defined(CONFIG_SMP)
380
381
382
383
384 asm volatile("pause");
385#else
386 ;
387#endif
388}
389
390static u64 tsc_timer_get_count(struct udevice *dev)
391{
392 u64 now_tick = rdtsc();
393
394 return now_tick - gd->arch.tsc_base;
395}
396
397static void tsc_timer_ensure_setup(bool early)
398{
399 if (gd->arch.tsc_inited)
400 return;
401 if (IS_ENABLED(CONFIG_X86_TSC_READ_BASE))
402 gd->arch.tsc_base = rdtsc();
403
404 if (!gd->arch.clock_rate) {
405 unsigned long fast_calibrate;
406
407 fast_calibrate = native_calibrate_tsc();
408 if (fast_calibrate)
409 goto done;
410
411
412 if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
413 panic("no timer");
414
415 fast_calibrate = cpu_mhz_from_cpuid();
416 if (fast_calibrate)
417 goto done;
418
419 fast_calibrate = cpu_mhz_from_msr();
420 if (fast_calibrate)
421 goto done;
422
423 fast_calibrate = quick_pit_calibrate();
424 if (fast_calibrate)
425 goto done;
426
427 if (early)
428 fast_calibrate = CONFIG_X86_TSC_TIMER_EARLY_FREQ;
429 else
430 return;
431
432done:
433 gd->arch.clock_rate = fast_calibrate * 1000000;
434 }
435 gd->arch.tsc_inited = true;
436}
437
438static int tsc_timer_probe(struct udevice *dev)
439{
440 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
441
442
443 tsc_timer_ensure_setup(false);
444 if (!gd->arch.clock_rate) {
445
446
447
448
449 if (!uc_priv->clock_rate)
450 panic("TSC frequency is ZERO");
451 } else {
452 uc_priv->clock_rate = gd->arch.clock_rate;
453 }
454
455 return 0;
456}
457
458unsigned long notrace timer_early_get_rate(void)
459{
460
461
462
463
464
465 tsc_timer_ensure_setup(true);
466
467 return gd->arch.clock_rate;
468}
469
470u64 notrace timer_early_get_count(void)
471{
472 tsc_timer_ensure_setup(true);
473
474 return rdtsc() - gd->arch.tsc_base;
475}
476
477static const struct timer_ops tsc_timer_ops = {
478 .get_count = tsc_timer_get_count,
479};
480
481#if !CONFIG_IS_ENABLED(OF_PLATDATA)
482static const struct udevice_id tsc_timer_ids[] = {
483 { .compatible = "x86,tsc-timer", },
484 { }
485};
486#endif
487
488U_BOOT_DRIVER(x86_tsc_timer) = {
489 .name = "x86_tsc_timer",
490 .id = UCLASS_TIMER,
491 .of_match = of_match_ptr(tsc_timer_ids),
492 .probe = tsc_timer_probe,
493 .ops = &tsc_timer_ops,
494};
495