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

Bernhard Messerklinger bernhard.messerklinger at br-automation.com
Mon Jan 7 11:14:40 UTC 2019


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 at br-automation.com>
---
I hope this patch won't break other x86 board.
I only can test it with APL board.

Changes in v4:
- Fix commit message
- Update macro names
- Order macro numbers
- Check cpuid eax and ebx return value

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

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




More information about the U-Boot mailing list