summaryrefslogtreecommitdiff
path: root/drivers/timer
diff options
context:
space:
mode:
authorBernhard Messerklinger <bernhard.messerklinger@br-automation.com>2019-01-07 12:14:40 +0100
committerBin Meng <bmeng.cn@gmail.com>2019-02-12 14:37:16 +0800
commitca7db866fead1d01ecf018343a99e3cd0d095d51 (patch)
treee299ce7fc070030228b0ea21317def7da7d07224 /drivers/timer
parent2436396a11a0b74742f3df330b4056b6a112bf01 (diff)
downloadu-boot-ca7db866fead1d01ecf018343a99e3cd0d095d51.tar.gz
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.c55
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;