soc/intel/common/timer: Make TSC frequency calculation dynamically

tsc_freq_mhz() had a static table of Intel CPU families and crystal
clock, but it is possible to calculate the crystal clock speed dynamically,
and this is preferred over hardcoded table.

On SKL/KBL/CML CPUID.15h.ecx = nominal core crystal clock = 0 Hz
hence we had to use static table to calculate crystal clock.

Recommendation is to make use of CPUID.16h where crystal clock frequency
was not reported by CPUID.15h to calculate the crystal clock.

BUG=b:139798422, b:129839774
TEST=Able to build and boot KBL/CML/ICL.

Change-Id: If660a4b8d12e54b39252bce62bcc0ffcc967f5da
Signed-off-by: Subrata Banik <subrata.banik@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/35148
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: V Sowmya <v.sowmya@intel.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Subrata Banik 2019-08-29 13:43:30 +05:30 committed by Patrick Georgi
parent c54dcf499b
commit 809b7513a2
2 changed files with 76 additions and 117 deletions

View File

@ -1,86 +0,0 @@
/*
* This file is part of the coreboot project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ARCH_INTEL_FAMILY_H
#define ARCH_INTEL_FAMILY_H
#define CPU_MODEL_INTEL_CORE_YONAH 0x0E
#define CPU_MODEL_INTEL_CORE2_MEROM 0x0F
#define CPU_MODEL_INTEL_CORE2_MEROM_L 0x16
#define CPU_MODEL_INTEL_CORE2_PENRYN 0x17
#define CPU_MODEL_INTEL_CORE2_DUNNINGTON 0x1D
#define CPU_MODEL_INTEL_NEHALEM 0x1E
/* Auburndale / Havendale */
#define CPU_MODEL_INTEL_NEHALEM_G 0x1F
#define CPU_MODEL_INTEL_NEHALEM_EP 0x1A
#define CPU_MODEL_INTEL_NEHALEM_EX 0x2E
#define CPU_MODEL_INTEL_WESTMERE 0x25
#define CPU_MODEL_INTEL_WESTMERE_EP 0x2C
#define CPU_MODEL_INTEL_WESTMERE_EX 0x2F
#define CPU_MODEL_INTEL_SANDYBRIDGE 0x2A
#define CPU_MODEL_INTEL_SANDYBRIDGE_X 0x2D
#define CPU_MODEL_INTEL_IVYBRIDGE 0x3A
#define CPU_MODEL_INTEL_IVYBRIDGE_X 0x3E
#define CPU_MODEL_INTEL_HASWELL_CORE 0x3C
#define CPU_MODEL_INTEL_HASWELL_X 0x3F
#define CPU_MODEL_INTEL_HASWELL_ULT 0x45
#define CPU_MODEL_INTEL_HASWELL_GT3E 0x46
#define CPU_MODEL_INTEL_BROADWELL_CORE 0x3D
#define CPU_MODEL_INTEL_BROADWELL_GT3E 0x47
#define CPU_MODEL_INTEL_BROADWELL_X 0x4F
#define CPU_MODEL_INTEL_BROADWELL_XEON_D 0x56
#define CPU_MODEL_INTEL_SKYLAKE_MOBILE 0x4E
#define CPU_MODEL_INTEL_SKYLAKE_DESKTOP 0x5E
#define CPU_MODEL_INTEL_SKYLAKE_X 0x55
#define CPU_MODEL_INTEL_KABYLAKE_MOBILE 0x8E
#define CPU_MODEL_INTEL_KABYLAKE_DESKTOP 0x9E
#define CPU_MODEL_INTEL_CANNONLAKE_MOBILE 0x66
#define CPU_MODEL_INTEL_ICELAKE_MOBILE 0x7E
/* "Small Core" Processors (Atom) */
#define CPU_MODEL_INTEL_ATOM_PINEVIEW 0x1C
#define CPU_MODEL_INTEL_ATOM_LINCROFT 0x26
#define CPU_MODEL_INTEL_ATOM_PENWELL 0x27
#define CPU_MODEL_INTEL_ATOM_CLOVERVIEW 0x35
#define CPU_MODEL_INTEL_ATOM_CEDARVIEW 0x36
/* BayTrail/BYT / Valleyview */
#define CPU_MODEL_INTEL_ATOM_SILVERMONT1 0x37
/* Avaton/Rangely */
#define CPU_MODEL_INTEL_ATOM_SILVERMONT2 0x4D
/* CherryTrail / Braswell */
#define CPU_MODEL_INTEL_ATOM_AIRMONT 0x4C
/* Tangier */
#define CPU_MODEL_INTEL_ATOM_MERRIFIELD 0x4A
/* Anniedale */
#define CPU_MODEL_INTEL_ATOM_MOOREFIELD 0x5A
#define CPU_MODEL_INTEL_ATOM_GOLDMONT 0x5C
/* Goldmont Microserver */
#define CPU_MODEL_INTEL_ATOM_DENVERTON 0x5F
#define CPU_MODEL_INTEL_ATOM_GEMINI_LAKE 0x7A
/* Xeon Phi */
/* Knights Landing */
#define CPU_MODEL_INTEL_XEON_PHI_KNL 0x57
/* Knights Mill */
#define CPU_MODEL_INTEL_XEON_PHI_KNM 0x85
#endif /* ARCH_INTEL_FAMILY_H */

View File

@ -14,12 +14,14 @@
*/ */
#include <arch/cpu.h> #include <arch/cpu.h>
#include <arch/intel-family.h>
#include <cpu/cpu.h> #include <cpu/cpu.h>
#include <cpu/x86/msr.h> #include <cpu/x86/msr.h>
#include <cpu/x86/tsc.h> #include <cpu/x86/tsc.h>
#include <intelblocks/msr.h> #include <intelblocks/msr.h>
/* Goldmont Microserver */
#define CPU_MODEL_INTEL_ATOM_DENVERTON 0x5F
static int get_processor_model(void) static int get_processor_model(void)
{ {
struct cpuinfo_x86 c; struct cpuinfo_x86 c;
@ -29,8 +31,31 @@ static int get_processor_model(void)
return c.x86_model; return c.x86_model;
} }
static unsigned int get_max_cpuid_func(void)
{
return cpuid_eax(0);
}
static unsigned long get_hardcoded_crystal_freq(void)
{
unsigned int core_crystal_nominal_freq_khz;
/*
* Denverton SoCs don't report crystal clock, and also don't support
* CPUID.0x16, so hardcode the 25MHz crystal clock.
*/
switch (get_processor_model()) {
case CPU_MODEL_INTEL_ATOM_DENVERTON:
core_crystal_nominal_freq_khz = 25000;
break;
}
return core_crystal_nominal_freq_khz;
}
/* /*
* Nominal TSC frequency = "core crystal clock frequency" * EBX/EAX * Nominal TSC frequency = "core crystal clock frequency" *
* CPUID_15h.EBX/CPUID_15h.EAX
* *
* Time Stamp Counter * Time Stamp Counter
* CPUID Initial EAX value = 0x15 * CPUID Initial EAX value = 0x15
@ -42,41 +67,61 @@ static int get_processor_model(void)
* core crystal clock in Hz. * core crystal clock in Hz.
* EDX Bit 31-0 : Reserved = 0 * EDX Bit 31-0 : Reserved = 0
* *
* Refer to Intel SDM Jan 2019 Vol 3B Section 18.7.3
*/ */
unsigned long tsc_freq_mhz(void) static unsigned long calculate_tsc_freq_from_core_crystal(void)
{ {
unsigned int core_crystal_nominal_freq_khz; unsigned int core_crystal_nominal_freq_khz;
struct cpuid_result cpuidr; struct cpuid_result cpuidr_15h;
/* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ if (get_max_cpuid_func() < 0x15)
cpuidr = cpuid(0x15);
if (!cpuidr.ebx || !cpuidr.eax)
return 0; return 0;
core_crystal_nominal_freq_khz = cpuidr.ecx / 1000; /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */
cpuidr_15h = cpuid(0x15);
if (!core_crystal_nominal_freq_khz) { if (!cpuidr_15h.ebx || !cpuidr_15h.eax)
switch (get_processor_model()) { return 0;
case CPU_MODEL_INTEL_SKYLAKE_MOBILE:
case CPU_MODEL_INTEL_SKYLAKE_DESKTOP:
case CPU_MODEL_INTEL_KABYLAKE_MOBILE:
case CPU_MODEL_INTEL_KABYLAKE_DESKTOP:
case CPU_MODEL_INTEL_CANNONLAKE_MOBILE:
case CPU_MODEL_INTEL_ICELAKE_MOBILE:
core_crystal_nominal_freq_khz = 24000;
break;
case CPU_MODEL_INTEL_ATOM_DENVERTON:
core_crystal_nominal_freq_khz = 25000;
break;
case CPU_MODEL_INTEL_ATOM_GOLDMONT:
case CPU_MODEL_INTEL_ATOM_GEMINI_LAKE:
core_crystal_nominal_freq_khz = 19200;
break;
}
}
return (core_crystal_nominal_freq_khz * cpuidr.ebx / cpuidr.eax) / core_crystal_nominal_freq_khz = cpuidr_15h.ecx / 1000;
1000;
if (!core_crystal_nominal_freq_khz)
core_crystal_nominal_freq_khz = get_hardcoded_crystal_freq();
return (core_crystal_nominal_freq_khz * cpuidr_15h.ebx /
cpuidr_15h.eax) / 1000;
}
/*
* Processor Frequency Information
* CPUID Initial EAX value = 0x16
* EAX Bit 31-0 : An unsigned integer which has the processor base frequency
* information
* EBX Bit 31-0 : An unsigned integer which has maximum frequency information
* ECX Bit 31-0 : An unsigned integer which has bus frequency information
* EDX Bit 31-0 : Reserved = 0
*
* Refer to Intel SDM Jan 2019 Vol 3B Section 18.7.3
*/
static unsigned long get_freq_from_cpuid16h(void)
{
if (get_max_cpuid_func() < 0x16)
return 0;
return cpuid_eax(0x16);
}
unsigned long tsc_freq_mhz(void)
{
unsigned long tsc_freq;
tsc_freq = calculate_tsc_freq_from_core_crystal();
if (tsc_freq)
return tsc_freq;
/*
* Some Intel SoCs like Skylake, Kabylake and Cometlake don't report
* the crystal clock, in that case return bus frequency using CPUID.16h
*/
return get_freq_from_cpuid16h();
} }