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