[U-Boot] [PATCH v2] x86: tsc: Add support for native calibration of TSC freq

Bernhard Messerklinger bernhard.messerklinger at br-automation.com
Fri Dec 21 07:30:34 UTC 2018


Add native tsc calibration function. Calibrate the tsc timer the same
way as linux does arch/x86/kernel/tsc.c.
Fixes booting for Apollo Lake processors.

Signed-off-by: Bernhard Messerklinger <bernhard.messerklinger at br-automation.com>
---
I hope this patch won't break other x86 board.
I only can test it with APL board.

Changes in v1:
- Update to linux way of dealing with TSC calibration

 drivers/timer/tsc_timer.c | 52 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c
index ba940ebf1c..ec7f05db17 100644
--- a/drivers/timer/tsc_timer.c
+++ b/drivers/timer/tsc_timer.c
@@ -19,8 +19,56 @@
 
 #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_KABYLAKE_MOBILE	0x8E
+#define INTEL_FAM6_KABYLAKE_DESKTOP	0x9E
+#define INTEL_FAM6_ATOM_DENVERTON	0x5F /* Goldmont Microserver */
+
 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);
+
+	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_DENVERTON:
+			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 +398,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;
-- 
2.20.1




More information about the U-Boot mailing list