From: Bernhard Messerklinger <bernhard.messerklinger@br-automation.com>
Date: Mon, 7 Jan 2019 11:14:40 +0000 (+0100)
Subject: x86: tsc: Add support for native calibration of TSC freq
X-Git-Tag: v2025.01-rc5-pxa1908~3127^2~4
X-Git-Url: http://git.dujemihanovic.xyz/html/static/gitweb.css?a=commitdiff_plain;h=ca7db866fead1d01ecf018343a99e3cd0d095d51;p=u-boot.git

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>
---

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;