2018-06-29 22:31:11 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-10-21 09:16:33 -07:00
/*
2018-06-29 22:31:11 +03:00
* TSC frequency enumeration via MSR
2013-10-21 09:16:33 -07:00
*
2018-06-29 22:31:11 +03:00
* Copyright ( C ) 2013 , 2018 Intel Corporation
2013-10-21 09:16:33 -07:00
* Author : Bin Gao < bin . gao @ intel . com >
*/
# include <linux/kernel.h>
2020-08-06 14:35:11 +02:00
# include <linux/thread_info.h>
2018-06-29 22:31:09 +03:00
2013-10-21 09:16:33 -07:00
# include <asm/apic.h>
2018-06-29 22:31:09 +03:00
# include <asm/cpu_device_id.h>
# include <asm/intel-family.h>
# include <asm/msr.h>
2013-10-21 09:16:33 -07:00
# include <asm/param.h>
2018-06-29 22:31:10 +03:00
# include <asm/tsc.h>
2013-10-21 09:16:33 -07:00
2020-02-23 15:06:09 +01:00
# define MAX_NUM_FREQS 16 /* 4 bits to select the frequency */
2013-10-21 09:16:33 -07:00
2020-02-23 15:06:10 +01:00
/*
* The frequency numbers in the SDM are e . g . 83.3 MHz , which does not contain a
* lot of accuracy which leads to clock drift . As far as we know Bay Trail SoCs
* use a 25 MHz crystal and Cherry Trail uses a 19.2 MHz crystal , the crystal
* is the source clk for a root PLL which outputs 1600 and 100 MHz . It is
* unclear if the root PLL outputs are used directly by the CPU clock PLL or
* if there is another PLL in between .
* This does not matter though , we can model the chain of PLLs as a single PLL
* with a quotient equal to the quotients of all PLLs in the chain multiplied .
* So we can create a simplified model of the CPU clock setup using a reference
* clock of 100 MHz plus a quotient which gets us as close to the frequency
* from the SDM as possible .
* For the 83.3 MHz example from above this would give us 100 MHz * 5 / 6 =
* 83 and 1 / 3 MHz , which matches exactly what has been measured on actual hw .
*/
# define TSC_REFERENCE_KHZ 100000
struct muldiv {
u32 multiplier ;
u32 divider ;
} ;
2013-10-21 09:16:33 -07:00
/*
2016-06-17 01:22:46 -04:00
* If MSR_PERF_STAT [ 31 ] is set , the maximum resolved bus ratio can be
2013-10-21 09:16:33 -07:00
* read in MSR_PLATFORM_ID [ 12 : 8 ] , otherwise in MSR_PERF_STAT [ 44 : 40 ] .
* Unfortunately some Intel Atom SoCs aren ' t quite compliant to this ,
* so we need manually differentiate SoC families . This is what the
2020-02-23 15:06:08 +01:00
* field use_msr_plat does .
2013-10-21 09:16:33 -07:00
*/
struct freq_desc {
2020-02-23 15:06:08 +01:00
bool use_msr_plat ;
2020-02-23 15:06:10 +01:00
struct muldiv muldiv [ MAX_NUM_FREQS ] ;
/*
* Some CPU frequencies in the SDM do not map to known PLL freqs , in
* that case the muldiv array is empty and the freqs array is used .
*/
2013-10-21 09:16:33 -07:00
u32 freqs [ MAX_NUM_FREQS ] ;
2020-02-23 15:06:09 +01:00
u32 mask ;
2013-10-21 09:16:33 -07:00
} ;
2018-06-29 22:31:12 +03:00
/*
* Penwell and Clovertrail use spread spectrum clock ,
* so the freq number is not exactly the same as reported
* by MSR based on SDM .
*/
2018-06-29 22:31:09 +03:00
static const struct freq_desc freq_desc_pnw = {
2020-02-23 15:06:08 +01:00
. use_msr_plat = false ,
. freqs = { 0 , 0 , 0 , 0 , 0 , 99840 , 0 , 83200 } ,
2020-02-23 15:06:09 +01:00
. mask = 0x07 ,
2013-10-21 09:16:33 -07:00
} ;
2018-06-29 22:31:09 +03:00
static const struct freq_desc freq_desc_clv = {
2020-02-23 15:06:08 +01:00
. use_msr_plat = false ,
. freqs = { 0 , 133200 , 0 , 0 , 0 , 99840 , 0 , 83200 } ,
2020-02-23 15:06:09 +01:00
. mask = 0x07 ,
2018-06-29 22:31:09 +03:00
} ;
2013-10-21 09:16:33 -07:00
2020-02-23 15:06:10 +01:00
/*
* Bay Trail SDM MSR_FSB_FREQ frequencies simplified PLL model :
* 000 : 100 * 5 / 6 = 83.3333 MHz
* 001 : 100 * 1 / 1 = 100.0000 MHz
* 010 : 100 * 4 / 3 = 133.3333 MHz
* 011 : 100 * 7 / 6 = 116.6667 MHz
* 100 : 100 * 4 / 5 = 80.0000 MHz
*/
2018-06-29 22:31:09 +03:00
static const struct freq_desc freq_desc_byt = {
2020-02-23 15:06:08 +01:00
. use_msr_plat = true ,
2020-02-23 15:06:10 +01:00
. muldiv = { { 5 , 6 } , { 1 , 1 } , { 4 , 3 } , { 7 , 6 } ,
{ 4 , 5 } } ,
2020-02-23 15:06:09 +01:00
. mask = 0x07 ,
2018-06-29 22:31:09 +03:00
} ;
2013-10-21 09:16:33 -07:00
2020-02-23 15:06:10 +01:00
/*
* Cherry Trail SDM MSR_FSB_FREQ frequencies simplified PLL model :
* 0000 : 100 * 5 / 6 = 83.3333 MHz
* 0001 : 100 * 1 / 1 = 100.0000 MHz
* 0010 : 100 * 4 / 3 = 133.3333 MHz
* 0011 : 100 * 7 / 6 = 116.6667 MHz
* 0100 : 100 * 4 / 5 = 80.0000 MHz
* 0101 : 100 * 14 / 15 = 93.3333 MHz
* 0110 : 100 * 9 / 10 = 90.0000 MHz
* 0111 : 100 * 8 / 9 = 88.8889 MHz
* 1000 : 100 * 7 / 8 = 87.5000 MHz
*/
2018-06-29 22:31:09 +03:00
static const struct freq_desc freq_desc_cht = {
2020-02-23 15:06:08 +01:00
. use_msr_plat = true ,
2020-02-23 15:06:10 +01:00
. muldiv = { { 5 , 6 } , { 1 , 1 } , { 4 , 3 } , { 7 , 6 } ,
{ 4 , 5 } , { 14 , 15 } , { 9 , 10 } , { 8 , 9 } ,
{ 7 , 8 } } ,
2020-02-23 15:06:09 +01:00
. mask = 0x0f ,
2018-06-29 22:31:09 +03:00
} ;
2013-10-21 09:16:33 -07:00
2020-02-23 15:06:10 +01:00
/*
* Merriefield SDM MSR_FSB_FREQ frequencies simplified PLL model :
* 0001 : 100 * 1 / 1 = 100.0000 MHz
* 0010 : 100 * 4 / 3 = 133.3333 MHz
*/
2018-06-29 22:31:09 +03:00
static const struct freq_desc freq_desc_tng = {
2020-02-23 15:06:08 +01:00
. use_msr_plat = true ,
2020-02-23 15:06:10 +01:00
. muldiv = { { 0 , 0 } , { 1 , 1 } , { 4 , 3 } } ,
2020-02-23 15:06:09 +01:00
. mask = 0x07 ,
2018-06-29 22:31:09 +03:00
} ;
2020-02-23 15:06:10 +01:00
/*
* Moorefield SDM MSR_FSB_FREQ frequencies simplified PLL model :
* 0000 : 100 * 5 / 6 = 83.3333 MHz
* 0001 : 100 * 1 / 1 = 100.0000 MHz
* 0010 : 100 * 4 / 3 = 133.3333 MHz
* 0011 : 100 * 1 / 1 = 100.0000 MHz
*/
2018-06-29 22:31:09 +03:00
static const struct freq_desc freq_desc_ann = {
2020-02-23 15:06:08 +01:00
. use_msr_plat = true ,
2020-02-23 15:06:10 +01:00
. muldiv = { { 5 , 6 } , { 1 , 1 } , { 4 , 3 } , { 1 , 1 } } ,
2020-02-23 15:06:09 +01:00
. mask = 0x0f ,
2018-06-29 22:31:09 +03:00
} ;
2020-08-03 15:56:36 +08:00
/*
* 24 MHz crystal ? : 24 * 13 / 4 = 78 MHz
* Frequency step for Lightning Mountain SoC is fixed to 78 MHz ,
* so all the frequency entries are 78000.
*/
2019-09-05 12:30:20 -07:00
static const struct freq_desc freq_desc_lgm = {
2020-02-23 15:06:08 +01:00
. use_msr_plat = true ,
2020-08-03 15:56:36 +08:00
. freqs = { 78000 , 78000 , 78000 , 78000 , 78000 , 78000 , 78000 , 78000 ,
78000 , 78000 , 78000 , 78000 , 78000 , 78000 , 78000 , 78000 } ,
2020-02-23 15:06:09 +01:00
. mask = 0x0f ,
2019-09-05 12:30:20 -07:00
} ;
2018-06-29 22:31:09 +03:00
static const struct x86_cpu_id tsc_msr_cpu_ids [ ] = {
2020-03-20 14:13:51 +01:00
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_SALTWELL_MID , & freq_desc_pnw ) ,
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_SALTWELL_TABLET , & freq_desc_clv ) ,
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_SILVERMONT , & freq_desc_byt ) ,
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_SILVERMONT_MID , & freq_desc_tng ) ,
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_AIRMONT , & freq_desc_cht ) ,
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_AIRMONT_MID , & freq_desc_ann ) ,
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_AIRMONT_NP , & freq_desc_lgm ) ,
2018-06-29 22:31:09 +03:00
{ }
} ;
2013-10-21 09:16:33 -07:00
/*
2016-06-17 01:22:45 -04:00
* MSR - based CPU / TSC frequency discovery for certain CPUs .
2014-02-19 13:52:29 +02:00
*
2019-05-09 13:54:16 +08:00
* Set global " lapic_timer_period " to bus_clock_cycles / jiffy
2016-06-17 01:22:45 -04:00
* Return processor base frequency in KHz , or 0 on failure .
2013-10-21 09:16:33 -07:00
*/
2016-06-17 01:22:50 -04:00
unsigned long cpu_khz_from_msr ( void )
2013-10-21 09:16:33 -07:00
{
2020-02-23 15:06:10 +01:00
u32 lo , hi , ratio , freq , tscref ;
2018-06-29 22:31:09 +03:00
const struct freq_desc * freq_desc ;
const struct x86_cpu_id * id ;
2020-02-23 15:06:10 +01:00
const struct muldiv * md ;
2014-02-19 13:52:29 +02:00
unsigned long res ;
2020-02-23 15:06:09 +01:00
int index ;
2013-10-21 09:16:33 -07:00
2018-06-29 22:31:09 +03:00
id = x86_match_cpu ( tsc_msr_cpu_ids ) ;
if ( ! id )
2016-06-17 01:22:44 -04:00
return 0 ;
2018-06-29 22:31:09 +03:00
freq_desc = ( struct freq_desc * ) id - > driver_data ;
2020-02-23 15:06:08 +01:00
if ( freq_desc - > use_msr_plat ) {
2013-10-21 09:16:33 -07:00
rdmsr ( MSR_PLATFORM_INFO , lo , hi ) ;
2016-05-06 11:33:39 +08:00
ratio = ( lo > > 8 ) & 0xff ;
2013-10-21 09:16:33 -07:00
} else {
rdmsr ( MSR_IA32_PERF_STATUS , lo , hi ) ;
ratio = ( hi > > 8 ) & 0x1f ;
}
/* Get FSB FREQ ID */
rdmsr ( MSR_FSB_FREQ , lo , hi ) ;
2020-02-23 15:06:09 +01:00
index = lo & freq_desc - > mask ;
2020-02-23 15:06:10 +01:00
md = & freq_desc - > muldiv [ index ] ;
2018-06-29 22:31:09 +03:00
2020-02-23 15:06:10 +01:00
/*
* Note this also catches cases where the index points to an unpopulated
* part of muldiv , in that case the else will set freq and res to 0.
*/
if ( md - > divider ) {
tscref = TSC_REFERENCE_KHZ * md - > multiplier ;
freq = DIV_ROUND_CLOSEST ( tscref , md - > divider ) ;
/*
* Multiplying by ratio before the division has better
* accuracy than just calculating freq * ratio .
*/
res = DIV_ROUND_CLOSEST ( tscref * ratio , md - > divider ) ;
} else {
freq = freq_desc - > freqs [ index ] ;
res = freq * ratio ;
}
2013-10-21 09:16:33 -07:00
2020-02-23 15:06:09 +01:00
if ( freq = = 0 )
pr_err ( " Error MSR_FSB_FREQ index %d is unknown \n " , index ) ;
2013-10-21 09:16:33 -07:00
2014-01-16 13:00:21 -08:00
# ifdef CONFIG_X86_LOCAL_APIC
2019-05-09 13:54:16 +08:00
lapic_timer_period = ( freq * 1000 ) / HZ ;
2014-01-16 13:00:21 -08:00
# endif
2016-11-15 12:27:24 -08:00
/*
* TSC frequency determined by MSR is always considered " known "
* because it is reported by HW .
* Another fact is that on MSR capable platforms , PIT / HPET is
* generally not available so calibration won ' t work at all .
*/
setup_force_cpu_cap ( X86_FEATURE_TSC_KNOWN_FREQ ) ;
/*
* Unfortunately there is no way for hardware to tell whether the
* TSC is reliable . We were told by silicon design team that TSC
* on Atom SoCs are always " reliable " . TSC is also the only
* reliable clocksource on these SoCs ( HPET is either not present
* or not functional ) so mark TSC reliable which removes the
* requirement for a watchdog clocksource .
*/
setup_force_cpu_cap ( X86_FEATURE_TSC_RELIABLE ) ;
2014-02-19 13:52:29 +02:00
return res ;
2013-10-21 09:16:33 -07:00
}