#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)
return 0;
}
-static void tsc_timer_ensure_setup(void)
+static void tsc_timer_ensure_setup(bool early)
{
if (gd->arch.tsc_base)
return;
gd->arch.tsc_base = rdtsc();
- /*
- * If there is no clock frequency specified in the device tree,
- * calibrate it by ourselves.
- */
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;
if (fast_calibrate)
goto done;
- panic("TSC frequency is ZERO");
+ if (early)
+ fast_calibrate = CONFIG_X86_TSC_TIMER_EARLY_FREQ;
+ else
+ return;
done:
gd->arch.clock_rate = fast_calibrate * 1000000;
{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- tsc_timer_ensure_setup();
- uc_priv->clock_rate = gd->arch.clock_rate;
+ /* Try hardware calibration first */
+ tsc_timer_ensure_setup(false);
+ if (!gd->arch.clock_rate) {
+ /*
+ * Use the clock frequency specified in the
+ * device tree as last resort
+ */
+ if (!uc_priv->clock_rate)
+ panic("TSC frequency is ZERO");
+ } else {
+ uc_priv->clock_rate = gd->arch.clock_rate;
+ }
return 0;
}
unsigned long notrace timer_early_get_rate(void)
{
- tsc_timer_ensure_setup();
+ /*
+ * When TSC timer is used as the early timer, be warned that the timer
+ * clock rate can only be calibrated via some hardware ways. Specifying
+ * it in the device tree won't work for the early timer.
+ */
+ tsc_timer_ensure_setup(true);
return gd->arch.clock_rate;
}
.of_match = tsc_timer_ids,
.probe = tsc_timer_probe,
.ops = &tsc_timer_ops,
- .flags = DM_FLAG_PRE_RELOC,
};