[coreboot-gerrit] Patch set updated for coreboot: libpayload: x86/timer: Implement constant TSC based calibration

Alexandru Gagniuc (mr.nuke.me@gmail.com) gerrit at coreboot.org
Tue Feb 2 22:31:40 CET 2016


Alexandru Gagniuc (mr.nuke.me at gmail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13391

-gerrit

commit a0db0015a3223863de7c078030e325e430725265
Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
Date:   Tue Nov 24 16:40:10 2015 -0800

    libpayload: x86/timer: Implement constant TSC based calibration
    
    On certain SOCs, such as Apollolake, the 8254 timer is not present or
    not operational. On such systems, attempting to calibrate the TSC
    against the 8254 will hang the payload. The next best approach is to
    identify processors with a constant TSC rate, and determine the actual
    speed by reading model-specific registers.
    
    With this patch, filo can now succesfully load the filo shell on
    Appololalke RVP2 board.
    
    Change-Id: I863acbc015cf072fa007584ab1d4f4531f0a6d4f
    Signed-off-by: Alexandru Gagniuc <alexandrux.gagniuc at intel.com>
    Signed-off-by: Andrey Petrov <andrey.petrov at intel.com>
---
 payloads/libpayload/arch/x86/timer.c | 99 ++++++++++++++++++++++++++++++++++--
 1 file changed, 95 insertions(+), 4 deletions(-)

diff --git a/payloads/libpayload/arch/x86/timer.c b/payloads/libpayload/arch/x86/timer.c
index bf0c30a..eb222b2 100644
--- a/payloads/libpayload/arch/x86/timer.c
+++ b/payloads/libpayload/arch/x86/timer.c
@@ -33,20 +33,93 @@
  */
 
 #include <libpayload.h>
+#include <arch/cpuid.h>
 #include <arch/rdtsc.h>
+#include <arch/msr.h>
 
+#define MSR_PLATFORM_INFO	0xce
 /**
  * @ingroup arch
  * Global variable containing the speed of the processor in KHz.
  */
 uint32_t cpu_khz;
 
-/**
- * Calculate the speed of the processor for use in delays.
+static const char intel_cpuid_mfg_string[] = "GenuineIntel";
+
+/*
+ * Certain Atom SOCs don't either don't have an 8254 timer (PIT), or coreboot
+ * disables the PIT. In these cases TSC calibration by PIT will hang.
  *
- * @return The CPU speed in kHz.
+ * NOTE: This table and its associated helper functions can be extended to
+ * support a larger range of CPUs and access methods. This only includes tested
+ * CPUs.
  */
-unsigned int get_cpu_speed(void)
+static const struct fsb_freq_descriptor {
+	uint8_t cpu_family;
+	uint8_t cpu_model;
+	unsigned int base_clock_khz;
+} intel_freq_table[] = {
+	{ 6, 0x5c, 100000 },		/* Apollolake (Broxton A0) */
+};
+
+static const struct fsb_freq_descriptor *get_cpu_freq_info(void)
+{
+	size_t i;
+	struct cpuid_fms fms = cpuid_get_fms();
+
+	for (i = 0; i < ARRAY_SIZE(intel_freq_table); i++) {
+		if ((intel_freq_table[i].cpu_family == fms.family) &&
+		    (intel_freq_table[i].cpu_model == fms.model)) {
+			return &intel_freq_table[i];
+		}
+	}
+
+	return NULL;
+}
+
+static int is_intel_cpu(void)
+{
+	char id_string[12];
+	struct cpuid_result res;
+
+	/* Get manufacturer's ID string */
+	res = cpuid(0);
+	memcpy(id_string + 0, &res.ebx, 4);
+	memcpy(id_string + 4, &res.edx, 4);
+	memcpy(id_string + 8, &res.ecx, 4);
+
+	return !memcmp(intel_cpuid_mfg_string, id_string, 12);
+}
+
+/*
+ * Get the speed of the processor's timestamp counter on supported CPUs
+ */
+static unsigned int get_cpu_speed_by_const_tsc(void)
+{
+	uint64_t msr;
+	uint32_t tsc_multiplier;
+	const struct fsb_freq_descriptor *freq_info;
+
+	if (!is_intel_cpu())
+		return 0;
+
+	freq_info = get_cpu_freq_info();
+	if (!freq_info)
+		return 0;
+
+	msr = _rdmsr(MSR_PLATFORM_INFO);
+	tsc_multiplier = (msr >> 8) & 0xff;
+
+	cpu_khz =  (freq_info->base_clock_khz * tsc_multiplier);
+	return cpu_khz;
+}
+
+/*
+ * Get the speed of the processor's timestamp counter by calibrating it
+ * against the 8254 programmable interval timer.
+ * This function waits 2 ms to get an accurate calibration.
+ */
+static unsigned int get_cpu_speed_by_8254_timer(void)
 {
 	unsigned long long start, end;
 	const uint32_t clock_rate = 1193182; // 1.193182 MHz
@@ -76,3 +149,21 @@ unsigned int get_cpu_speed(void)
 
 	return cpu_khz;
 }
+
+/**
+ * Calculate the speed of the processor for use in delays.
+ *
+ * @return The CPU speed in kHz.
+ */
+unsigned int get_cpu_speed(void)
+{
+	uint32_t tsc_rate_khz;
+
+	tsc_rate_khz = get_cpu_speed_by_const_tsc();
+	if (tsc_rate_khz)
+		return tsc_rate_khz;
+
+	tsc_rate_khz = get_cpu_speed_by_8254_timer();
+
+	return tsc_rate_khz;
+}



More information about the coreboot-gerrit mailing list