Commit ca7db866fead1d01ecf018343a99e3cd0d095d51
Committed by
Bin Meng
1 parent
2436396a11
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
x86: tsc: Add support for native calibration of TSC freq
Add native tsc calibration function. Calibrate the tsc timer the same way as linux does in arch/x86/kernel/tsc.c. Fixes booting for Apollo Lake processors. Signed-off-by: Bernhard Messerklinger <bernhard.messerklinger@br-automation.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Showing 1 changed file with 55 additions and 0 deletions Side-by-side Diff
drivers/timer/tsc_timer.c
... | ... | @@ -19,8 +19,59 @@ |
19 | 19 | |
20 | 20 | #define MAX_NUM_FREQS 9 |
21 | 21 | |
22 | +#define INTEL_FAM6_SKYLAKE_MOBILE 0x4E | |
23 | +#define INTEL_FAM6_ATOM_GOLDMONT 0x5C /* Apollo Lake */ | |
24 | +#define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E | |
25 | +#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F /* Denverton */ | |
26 | +#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E | |
27 | +#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E | |
28 | + | |
22 | 29 | DECLARE_GLOBAL_DATA_PTR; |
23 | 30 | |
31 | +/* | |
32 | + * native_calibrate_tsc | |
33 | + * Determine TSC frequency via CPUID, else return 0. | |
34 | + */ | |
35 | +static unsigned long native_calibrate_tsc(void) | |
36 | +{ | |
37 | + struct cpuid_result tsc_info; | |
38 | + unsigned int crystal_freq; | |
39 | + | |
40 | + if (gd->arch.x86_vendor != X86_VENDOR_INTEL) | |
41 | + return 0; | |
42 | + | |
43 | + if (cpuid_eax(0) < 0x15) | |
44 | + return 0; | |
45 | + | |
46 | + tsc_info = cpuid(0x15); | |
47 | + | |
48 | + if (tsc_info.ebx == 0 || tsc_info.eax == 0) | |
49 | + return 0; | |
50 | + | |
51 | + crystal_freq = tsc_info.ecx / 1000; | |
52 | + | |
53 | + if (!crystal_freq) { | |
54 | + switch (gd->arch.x86_model) { | |
55 | + case INTEL_FAM6_SKYLAKE_MOBILE: | |
56 | + case INTEL_FAM6_SKYLAKE_DESKTOP: | |
57 | + case INTEL_FAM6_KABYLAKE_MOBILE: | |
58 | + case INTEL_FAM6_KABYLAKE_DESKTOP: | |
59 | + crystal_freq = 24000; /* 24.0 MHz */ | |
60 | + break; | |
61 | + case INTEL_FAM6_ATOM_GOLDMONT_X: | |
62 | + crystal_freq = 25000; /* 25.0 MHz */ | |
63 | + break; | |
64 | + case INTEL_FAM6_ATOM_GOLDMONT: | |
65 | + crystal_freq = 19200; /* 19.2 MHz */ | |
66 | + break; | |
67 | + default: | |
68 | + return 0; | |
69 | + } | |
70 | + } | |
71 | + | |
72 | + return (crystal_freq * tsc_info.ebx / tsc_info.eax) / 1000; | |
73 | +} | |
74 | + | |
24 | 75 | static unsigned long cpu_mhz_from_cpuid(void) |
25 | 76 | { |
26 | 77 | if (gd->arch.x86_vendor != X86_VENDOR_INTEL) |
... | ... | @@ -349,6 +400,10 @@ |
349 | 400 | |
350 | 401 | if (!gd->arch.clock_rate) { |
351 | 402 | unsigned long fast_calibrate; |
403 | + | |
404 | + fast_calibrate = native_calibrate_tsc(); | |
405 | + if (fast_calibrate) | |
406 | + goto done; | |
352 | 407 | |
353 | 408 | fast_calibrate = cpu_mhz_from_cpuid(); |
354 | 409 | if (fast_calibrate) |