|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * TSC frequency enumeration via MSR | 
|  | * | 
|  | * Copyright (C) 2013, 2018 Intel Corporation | 
|  | * Author: Bin Gao <bin.gao@intel.com> | 
|  | */ | 
|  |  | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/thread_info.h> | 
|  |  | 
|  | #include <asm/apic.h> | 
|  | #include <asm/cpu_device_id.h> | 
|  | #include <asm/intel-family.h> | 
|  | #include <asm/msr.h> | 
|  | #include <asm/param.h> | 
|  | #include <asm/tsc.h> | 
|  |  | 
|  | #define MAX_NUM_FREQS	16 /* 4 bits to select the frequency */ | 
|  |  | 
|  | /* | 
|  | * 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; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be | 
|  | * 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 | 
|  | * field use_msr_plat does. | 
|  | */ | 
|  | struct freq_desc { | 
|  | bool use_msr_plat; | 
|  | 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. | 
|  | */ | 
|  | u32 freqs[MAX_NUM_FREQS]; | 
|  | u32 mask; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Penwell and Clovertrail use spread spectrum clock, | 
|  | * so the freq number is not exactly the same as reported | 
|  | * by MSR based on SDM. | 
|  | */ | 
|  | static const struct freq_desc freq_desc_pnw = { | 
|  | .use_msr_plat = false, | 
|  | .freqs = { 0, 0, 0, 0, 0, 99840, 0, 83200 }, | 
|  | .mask = 0x07, | 
|  | }; | 
|  |  | 
|  | static const struct freq_desc freq_desc_clv = { | 
|  | .use_msr_plat = false, | 
|  | .freqs = { 0, 133200, 0, 0, 0, 99840, 0, 83200 }, | 
|  | .mask = 0x07, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * 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 | 
|  | */ | 
|  | static const struct freq_desc freq_desc_byt = { | 
|  | .use_msr_plat = true, | 
|  | .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 7, 6 }, | 
|  | { 4, 5 } }, | 
|  | .mask = 0x07, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * 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 | 
|  | */ | 
|  | static const struct freq_desc freq_desc_cht = { | 
|  | .use_msr_plat = true, | 
|  | .muldiv = { { 5, 6 }, {  1,  1 }, { 4,  3 }, { 7, 6 }, | 
|  | { 4, 5 }, { 14, 15 }, { 9, 10 }, { 8, 9 }, | 
|  | { 7, 8 } }, | 
|  | .mask = 0x0f, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Merriefield SDM MSR_FSB_FREQ frequencies simplified PLL model: | 
|  | * 0001:   100 *  1 /  1  = 100.0000 MHz | 
|  | * 0010:   100 *  4 /  3  = 133.3333 MHz | 
|  | */ | 
|  | static const struct freq_desc freq_desc_tng = { | 
|  | .use_msr_plat = true, | 
|  | .muldiv = { { 0, 0 }, { 1, 1 }, { 4, 3 } }, | 
|  | .mask = 0x07, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * 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 | 
|  | */ | 
|  | static const struct freq_desc freq_desc_ann = { | 
|  | .use_msr_plat = true, | 
|  | .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 1, 1 } }, | 
|  | .mask = 0x0f, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * 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. | 
|  | */ | 
|  | static const struct freq_desc freq_desc_lgm = { | 
|  | .use_msr_plat = true, | 
|  | .freqs = { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000, | 
|  | 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 }, | 
|  | .mask = 0x0f, | 
|  | }; | 
|  |  | 
|  | static const struct x86_cpu_id tsc_msr_cpu_ids[] = { | 
|  | 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), | 
|  | {} | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * MSR-based CPU/TSC frequency discovery for certain CPUs. | 
|  | * | 
|  | * Set global "lapic_timer_period" to bus_clock_cycles/jiffy | 
|  | * Return processor base frequency in KHz, or 0 on failure. | 
|  | */ | 
|  | unsigned long cpu_khz_from_msr(void) | 
|  | { | 
|  | u32 lo, hi, ratio, freq, tscref; | 
|  | const struct freq_desc *freq_desc; | 
|  | const struct x86_cpu_id *id; | 
|  | const struct muldiv *md; | 
|  | unsigned long res; | 
|  | int index; | 
|  |  | 
|  | id = x86_match_cpu(tsc_msr_cpu_ids); | 
|  | if (!id) | 
|  | return 0; | 
|  |  | 
|  | freq_desc = (struct freq_desc *)id->driver_data; | 
|  | if (freq_desc->use_msr_plat) { | 
|  | rdmsr(MSR_PLATFORM_INFO, lo, hi); | 
|  | ratio = (lo >> 8) & 0xff; | 
|  | } else { | 
|  | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | 
|  | ratio = (hi >> 8) & 0x1f; | 
|  | } | 
|  |  | 
|  | /* Get FSB FREQ ID */ | 
|  | rdmsr(MSR_FSB_FREQ, lo, hi); | 
|  | index = lo & freq_desc->mask; | 
|  | md = &freq_desc->muldiv[index]; | 
|  |  | 
|  | /* | 
|  | * 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; | 
|  | } | 
|  |  | 
|  | if (freq == 0) | 
|  | pr_err("Error MSR_FSB_FREQ index %d is unknown\n", index); | 
|  |  | 
|  | #ifdef CONFIG_X86_LOCAL_APIC | 
|  | lapic_timer_period = (freq * 1000) / HZ; | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * 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); | 
|  |  | 
|  | return res; | 
|  | } |