David Cohen | bc20aa48 | 2013-12-16 12:07:38 -0800 | [diff] [blame] | 1 | /* |
Andy Shevchenko | 62d855d | 2016-06-18 18:51:34 +0300 | [diff] [blame] | 2 | * Intel Merrifield platform specific setup code |
David Cohen | bc20aa48 | 2013-12-16 12:07:38 -0800 | [diff] [blame] | 3 | * |
| 4 | * (C) Copyright 2013 Intel Corporation |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; version 2 |
| 9 | * of the License. |
| 10 | */ |
| 11 | |
| 12 | #include <linux/init.h> |
| 13 | |
| 14 | #include <asm/apic.h> |
| 15 | #include <asm/intel-mid.h> |
| 16 | |
| 17 | #include "intel_mid_weak_decls.h" |
| 18 | |
| 19 | static unsigned long __init tangier_calibrate_tsc(void) |
| 20 | { |
| 21 | unsigned long fast_calibrate; |
| 22 | u32 lo, hi, ratio, fsb, bus_freq; |
| 23 | |
| 24 | /* *********************** */ |
| 25 | /* Compute TSC:Ratio * FSB */ |
| 26 | /* *********************** */ |
| 27 | |
| 28 | /* Compute Ratio */ |
| 29 | rdmsr(MSR_PLATFORM_INFO, lo, hi); |
| 30 | pr_debug("IA32 PLATFORM_INFO is 0x%x : %x\n", hi, lo); |
| 31 | |
| 32 | ratio = (lo >> 8) & 0xFF; |
| 33 | pr_debug("ratio is %d\n", ratio); |
| 34 | if (!ratio) { |
| 35 | pr_err("Read a zero ratio, force tsc ratio to 4 ...\n"); |
| 36 | ratio = 4; |
| 37 | } |
| 38 | |
| 39 | /* Compute FSB */ |
| 40 | rdmsr(MSR_FSB_FREQ, lo, hi); |
| 41 | pr_debug("Actual FSB frequency detected by SOC 0x%x : %x\n", |
| 42 | hi, lo); |
| 43 | |
| 44 | bus_freq = lo & 0x7; |
| 45 | pr_debug("bus_freq = 0x%x\n", bus_freq); |
| 46 | |
| 47 | if (bus_freq == 0) |
| 48 | fsb = FSB_FREQ_100SKU; |
| 49 | else if (bus_freq == 1) |
| 50 | fsb = FSB_FREQ_100SKU; |
| 51 | else if (bus_freq == 2) |
| 52 | fsb = FSB_FREQ_133SKU; |
| 53 | else if (bus_freq == 3) |
| 54 | fsb = FSB_FREQ_167SKU; |
| 55 | else if (bus_freq == 4) |
| 56 | fsb = FSB_FREQ_83SKU; |
| 57 | else if (bus_freq == 5) |
| 58 | fsb = FSB_FREQ_400SKU; |
| 59 | else if (bus_freq == 6) |
| 60 | fsb = FSB_FREQ_267SKU; |
| 61 | else if (bus_freq == 7) |
| 62 | fsb = FSB_FREQ_333SKU; |
| 63 | else { |
| 64 | BUG(); |
| 65 | pr_err("Invalid bus_freq! Setting to minimal value!\n"); |
| 66 | fsb = FSB_FREQ_100SKU; |
| 67 | } |
| 68 | |
| 69 | /* TSC = FSB Freq * Resolved HFM Ratio */ |
| 70 | fast_calibrate = ratio * fsb; |
| 71 | pr_debug("calculate tangier tsc %lu KHz\n", fast_calibrate); |
| 72 | |
| 73 | /* ************************************ */ |
| 74 | /* Calculate Local APIC Timer Frequency */ |
| 75 | /* ************************************ */ |
| 76 | lapic_timer_frequency = (fsb * 1000) / HZ; |
| 77 | |
| 78 | pr_debug("Setting lapic_timer_frequency = %d\n", |
| 79 | lapic_timer_frequency); |
| 80 | |
Bin Gao | f3a02ec | 2016-11-15 12:27:24 -0800 | [diff] [blame] | 81 | /* |
| 82 | * TSC on Intel Atom SoCs is reliable and of known frequency. |
| 83 | * See tsc_msr.c for details. |
| 84 | */ |
| 85 | setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); |
| 86 | setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE); |
David Cohen | bc20aa48 | 2013-12-16 12:07:38 -0800 | [diff] [blame] | 87 | |
Alan | 8f8e2ae | 2016-02-17 14:10:15 +0000 | [diff] [blame] | 88 | return fast_calibrate; |
David Cohen | bc20aa48 | 2013-12-16 12:07:38 -0800 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | static void __init tangier_arch_setup(void) |
| 92 | { |
| 93 | x86_platform.calibrate_tsc = tangier_calibrate_tsc; |
| 94 | } |
| 95 | |
| 96 | /* tangier arch ops */ |
| 97 | static struct intel_mid_ops tangier_ops = { |
| 98 | .arch_setup = tangier_arch_setup, |
| 99 | }; |
| 100 | |
David Cohen | 48102ca | 2014-01-22 14:22:49 -0800 | [diff] [blame] | 101 | void *get_tangier_ops(void) |
David Cohen | bc20aa48 | 2013-12-16 12:07:38 -0800 | [diff] [blame] | 102 | { |
| 103 | return &tangier_ops; |
| 104 | } |