diff options
Diffstat (limited to 'arch/x86/platform/intel-mid/intel-mid.c')
-rw-r--r-- | arch/x86/platform/intel-mid/intel-mid.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c new file mode 100644 index 000000000000..f90e290f689f --- /dev/null +++ b/arch/x86/platform/intel-mid/intel-mid.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * intel-mid.c: Intel MID platform setup code | ||
3 | * | ||
4 | * (C) Copyright 2008, 2012 Intel Corporation | ||
5 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
6 | * Author: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; version 2 | ||
11 | * of the License. | ||
12 | */ | ||
13 | |||
14 | #define pr_fmt(fmt) "intel_mid: " fmt | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include <linux/sfi.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/notifier.h> | ||
24 | |||
25 | #include <asm/setup.h> | ||
26 | #include <asm/mpspec_def.h> | ||
27 | #include <asm/hw_irq.h> | ||
28 | #include <asm/apic.h> | ||
29 | #include <asm/io_apic.h> | ||
30 | #include <asm/intel-mid.h> | ||
31 | #include <asm/intel_mid_vrtc.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/i8259.h> | ||
34 | #include <asm/intel_scu_ipc.h> | ||
35 | #include <asm/apb_timer.h> | ||
36 | #include <asm/reboot.h> | ||
37 | |||
38 | /* | ||
39 | * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, | ||
40 | * cmdline option x86_intel_mid_timer can be used to override the configuration | ||
41 | * to prefer one or the other. | ||
42 | * at runtime, there are basically three timer configurations: | ||
43 | * 1. per cpu apbt clock only | ||
44 | * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only | ||
45 | * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast. | ||
46 | * | ||
47 | * by default (without cmdline option), platform code first detects cpu type | ||
48 | * to see if we are on lincroft or penwell, then set up both lapic or apbt | ||
49 | * clocks accordingly. | ||
50 | * i.e. by default, medfield uses configuration #2, moorestown uses #1. | ||
51 | * config #3 is supported but not recommended on medfield. | ||
52 | * | ||
53 | * rating and feature summary: | ||
54 | * lapic (with C3STOP) --------- 100 | ||
55 | * apbt (always-on) ------------ 110 | ||
56 | * lapic (always-on,ARAT) ------ 150 | ||
57 | */ | ||
58 | |||
59 | enum intel_mid_timer_options intel_mid_timer_options; | ||
60 | |||
61 | enum intel_mid_cpu_type __intel_mid_cpu_chip; | ||
62 | EXPORT_SYMBOL_GPL(__intel_mid_cpu_chip); | ||
63 | |||
64 | static void intel_mid_power_off(void) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | static void intel_mid_reboot(void) | ||
69 | { | ||
70 | intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); | ||
71 | } | ||
72 | |||
73 | static unsigned long __init intel_mid_calibrate_tsc(void) | ||
74 | { | ||
75 | unsigned long fast_calibrate; | ||
76 | u32 lo, hi, ratio, fsb; | ||
77 | |||
78 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | ||
79 | pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi); | ||
80 | ratio = (hi >> 8) & 0x1f; | ||
81 | pr_debug("ratio is %d\n", ratio); | ||
82 | if (!ratio) { | ||
83 | pr_err("read a zero ratio, should be incorrect!\n"); | ||
84 | pr_err("force tsc ratio to 16 ...\n"); | ||
85 | ratio = 16; | ||
86 | } | ||
87 | rdmsr(MSR_FSB_FREQ, lo, hi); | ||
88 | if ((lo & 0x7) == 0x7) | ||
89 | fsb = PENWELL_FSB_FREQ_83SKU; | ||
90 | else | ||
91 | fsb = PENWELL_FSB_FREQ_100SKU; | ||
92 | fast_calibrate = ratio * fsb; | ||
93 | pr_debug("read penwell tsc %lu khz\n", fast_calibrate); | ||
94 | lapic_timer_frequency = fsb * 1000 / HZ; | ||
95 | /* mark tsc clocksource as reliable */ | ||
96 | set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); | ||
97 | |||
98 | if (fast_calibrate) | ||
99 | return fast_calibrate; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void __init intel_mid_time_init(void) | ||
105 | { | ||
106 | sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); | ||
107 | switch (intel_mid_timer_options) { | ||
108 | case INTEL_MID_TIMER_APBT_ONLY: | ||
109 | break; | ||
110 | case INTEL_MID_TIMER_LAPIC_APBT: | ||
111 | x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | ||
112 | x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | ||
113 | break; | ||
114 | default: | ||
115 | if (!boot_cpu_has(X86_FEATURE_ARAT)) | ||
116 | break; | ||
117 | x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | ||
118 | x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | ||
119 | return; | ||
120 | } | ||
121 | /* we need at least one APB timer */ | ||
122 | pre_init_apic_IRQ0(); | ||
123 | apbt_time_init(); | ||
124 | } | ||
125 | |||
126 | static void intel_mid_arch_setup(void) | ||
127 | { | ||
128 | if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) | ||
129 | __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_PENWELL; | ||
130 | else { | ||
131 | pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n", | ||
132 | boot_cpu_data.x86, boot_cpu_data.x86_model); | ||
133 | __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_PENWELL; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* MID systems don't have i8042 controller */ | ||
138 | static int intel_mid_i8042_detect(void) | ||
139 | { | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Moorestown does not have external NMI source nor port 0x61 to report | ||
145 | * NMI status. The possible NMI sources are from pmu as a result of NMI | ||
146 | * watchdog or lock debug. Reading io port 0x61 results in 0xff which | ||
147 | * misled NMI handler. | ||
148 | */ | ||
149 | static unsigned char intel_mid_get_nmi_reason(void) | ||
150 | { | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Moorestown specific x86_init function overrides and early setup | ||
156 | * calls. | ||
157 | */ | ||
158 | void __init x86_intel_mid_early_setup(void) | ||
159 | { | ||
160 | x86_init.resources.probe_roms = x86_init_noop; | ||
161 | x86_init.resources.reserve_resources = x86_init_noop; | ||
162 | |||
163 | x86_init.timers.timer_init = intel_mid_time_init; | ||
164 | x86_init.timers.setup_percpu_clockev = x86_init_noop; | ||
165 | |||
166 | x86_init.irqs.pre_vector_init = x86_init_noop; | ||
167 | |||
168 | x86_init.oem.arch_setup = intel_mid_arch_setup; | ||
169 | |||
170 | x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock; | ||
171 | |||
172 | x86_platform.calibrate_tsc = intel_mid_calibrate_tsc; | ||
173 | x86_platform.i8042_detect = intel_mid_i8042_detect; | ||
174 | x86_init.timers.wallclock_init = intel_mid_rtc_init; | ||
175 | x86_platform.get_nmi_reason = intel_mid_get_nmi_reason; | ||
176 | |||
177 | x86_init.pci.init = intel_mid_pci_init; | ||
178 | x86_init.pci.fixup_irqs = x86_init_noop; | ||
179 | |||
180 | legacy_pic = &null_legacy_pic; | ||
181 | |||
182 | pm_power_off = intel_mid_power_off; | ||
183 | machine_ops.emergency_restart = intel_mid_reboot; | ||
184 | |||
185 | /* Avoid searching for BIOS MP tables */ | ||
186 | x86_init.mpparse.find_smp_config = x86_init_noop; | ||
187 | x86_init.mpparse.get_smp_config = x86_init_uint_noop; | ||
188 | set_bit(MP_BUS_ISA, mp_bus_not_pci); | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * if user does not want to use per CPU apb timer, just give it a lower rating | ||
193 | * than local apic timer and skip the late per cpu timer init. | ||
194 | */ | ||
195 | static inline int __init setup_x86_intel_mid_timer(char *arg) | ||
196 | { | ||
197 | if (!arg) | ||
198 | return -EINVAL; | ||
199 | |||
200 | if (strcmp("apbt_only", arg) == 0) | ||
201 | intel_mid_timer_options = INTEL_MID_TIMER_APBT_ONLY; | ||
202 | else if (strcmp("lapic_and_apbt", arg) == 0) | ||
203 | intel_mid_timer_options = INTEL_MID_TIMER_LAPIC_APBT; | ||
204 | else { | ||
205 | pr_warn("X86 INTEL_MID timer option %s not recognised" | ||
206 | " use x86_intel_mid_timer=apbt_only or lapic_and_apbt\n", | ||
207 | arg); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | __setup("x86_intel_mid_timer=", setup_x86_intel_mid_timer); | ||
213 | |||