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