diff options
author | Bernhard Messerklinger <bernhard.messerklinger@br-automation.com> | 2019-01-07 12:14:40 +0100 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2019-02-12 14:37:16 +0800 |
commit | ca7db866fead1d01ecf018343a99e3cd0d095d51 (patch) | |
tree | e299ce7fc070030228b0ea21317def7da7d07224 /drivers/timer | |
parent | 2436396a11a0b74742f3df330b4056b6a112bf01 (diff) | |
download | u-boot-ca7db866fead1d01ecf018343a99e3cd0d095d51.tar.gz u-boot-ca7db866fead1d01ecf018343a99e3cd0d095d51.tar.xz u-boot-ca7db866fead1d01ecf018343a99e3cd0d095d51.zip |
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>
Diffstat (limited to 'drivers/timer')
-rw-r--r-- | drivers/timer/tsc_timer.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index ba940ebf1c..919caba8a1 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -19,8 +19,59 @@ #define MAX_NUM_FREQS 9 +#define INTEL_FAM6_SKYLAKE_MOBILE 0x4E +#define INTEL_FAM6_ATOM_GOLDMONT 0x5C /* Apollo Lake */ +#define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E +#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F /* Denverton */ +#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E +#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E + DECLARE_GLOBAL_DATA_PTR; +/* + * native_calibrate_tsc + * Determine TSC frequency via CPUID, else return 0. + */ +static unsigned long native_calibrate_tsc(void) +{ + struct cpuid_result tsc_info; + unsigned int crystal_freq; + + if (gd->arch.x86_vendor != X86_VENDOR_INTEL) + return 0; + + if (cpuid_eax(0) < 0x15) + return 0; + + tsc_info = cpuid(0x15); + + if (tsc_info.ebx == 0 || tsc_info.eax == 0) + return 0; + + crystal_freq = tsc_info.ecx / 1000; + + if (!crystal_freq) { + switch (gd->arch.x86_model) { + case INTEL_FAM6_SKYLAKE_MOBILE: + case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_KABYLAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_DESKTOP: + crystal_freq = 24000; /* 24.0 MHz */ + break; + case INTEL_FAM6_ATOM_GOLDMONT_X: + crystal_freq = 25000; /* 25.0 MHz */ + break; + case INTEL_FAM6_ATOM_GOLDMONT: + crystal_freq = 19200; /* 19.2 MHz */ + break; + default: + return 0; + } + } + + return (crystal_freq * tsc_info.ebx / tsc_info.eax) / 1000; +} + static unsigned long cpu_mhz_from_cpuid(void) { if (gd->arch.x86_vendor != X86_VENDOR_INTEL) @@ -350,6 +401,10 @@ static void tsc_timer_ensure_setup(bool early) if (!gd->arch.clock_rate) { unsigned long fast_calibrate; + fast_calibrate = native_calibrate_tsc(); + if (fast_calibrate) + goto done; + fast_calibrate = cpu_mhz_from_cpuid(); if (fast_calibrate) goto done; |