2 * mrst.c: Intel Moorestown platform specific setup code
4 * (C) Copyright 2008 Intel Corporation
5 * Author: Jacob Pan (jacob.jun.pan@intel.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; version 2
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/sfi.h>
15 #include <linux/irq.h>
16 #include <linux/module.h>
18 #include <asm/setup.h>
19 #include <asm/mpspec_def.h>
20 #include <asm/hw_irq.h>
22 #include <asm/io_apic.h>
25 #include <asm/i8259.h>
26 #include <asm/apb_timer.h>
29 * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
30 * cmdline option x86_mrst_timer can be used to override the configuration
31 * to prefer one or the other.
32 * at runtime, there are basically three timer configurations:
33 * 1. per cpu apbt clock only
34 * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
35 * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
37 * by default (without cmdline option), platform code first detects cpu type
38 * to see if we are on lincroft or penwell, then set up both lapic or apbt
40 * i.e. by default, medfield uses configuration #2, moorestown uses #1.
41 * config #3 is supported but not recommended on medfield.
43 * rating and feature summary:
44 * lapic (with C3STOP) --------- 100
45 * apbt (always-on) ------------ 110
46 * lapic (always-on,ARAT) ------ 150
49 __cpuinitdata
enum mrst_timer_options mrst_timer_options
;
51 static u32 sfi_mtimer_usage
[SFI_MTMR_MAX_NUM
];
52 static struct sfi_timer_table_entry sfi_mtimer_array
[SFI_MTMR_MAX_NUM
];
53 enum mrst_cpu_type __mrst_cpu_chip
;
54 EXPORT_SYMBOL_GPL(__mrst_cpu_chip
);
58 struct sfi_rtc_table_entry sfi_mrtc_array
[SFI_MRTC_MAX
];
59 EXPORT_SYMBOL_GPL(sfi_mrtc_array
);
62 static inline void assign_to_mp_irq(struct mpc_intsrc
*m
,
63 struct mpc_intsrc
*mp_irq
)
65 memcpy(mp_irq
, m
, sizeof(struct mpc_intsrc
));
68 static inline int mp_irq_cmp(struct mpc_intsrc
*mp_irq
,
71 return memcmp(mp_irq
, m
, sizeof(struct mpc_intsrc
));
74 static void save_mp_irq(struct mpc_intsrc
*m
)
78 for (i
= 0; i
< mp_irq_entries
; i
++) {
79 if (!mp_irq_cmp(&mp_irqs
[i
], m
))
83 assign_to_mp_irq(m
, &mp_irqs
[mp_irq_entries
]);
84 if (++mp_irq_entries
== MAX_IRQ_SOURCES
)
85 panic("Max # of irq sources exceeded!!\n");
88 /* parse all the mtimer info to a static mtimer array */
89 static int __init
sfi_parse_mtmr(struct sfi_table_header
*table
)
91 struct sfi_table_simple
*sb
;
92 struct sfi_timer_table_entry
*pentry
;
93 struct mpc_intsrc mp_irq
;
96 sb
= (struct sfi_table_simple
*)table
;
97 if (!sfi_mtimer_num
) {
98 sfi_mtimer_num
= SFI_GET_NUM_ENTRIES(sb
,
99 struct sfi_timer_table_entry
);
100 pentry
= (struct sfi_timer_table_entry
*) sb
->pentry
;
101 totallen
= sfi_mtimer_num
* sizeof(*pentry
);
102 memcpy(sfi_mtimer_array
, pentry
, totallen
);
105 printk(KERN_INFO
"SFI: MTIMER info (num = %d):\n", sfi_mtimer_num
);
106 pentry
= sfi_mtimer_array
;
107 for (totallen
= 0; totallen
< sfi_mtimer_num
; totallen
++, pentry
++) {
108 printk(KERN_INFO
"timer[%d]: paddr = 0x%08x, freq = %dHz,"
109 " irq = %d\n", totallen
, (u32
)pentry
->phys_addr
,
110 pentry
->freq_hz
, pentry
->irq
);
113 mp_irq
.type
= MP_IOAPIC
;
114 mp_irq
.irqtype
= mp_INT
;
115 /* triggering mode edge bit 2-3, active high polarity bit 0-1 */
118 mp_irq
.srcbusirq
= pentry
->irq
; /* IRQ */
119 mp_irq
.dstapic
= MP_APIC_ALL
;
120 mp_irq
.dstirq
= pentry
->irq
;
121 save_mp_irq(&mp_irq
);
127 struct sfi_timer_table_entry
*sfi_get_mtmr(int hint
)
130 if (hint
< sfi_mtimer_num
) {
131 if (!sfi_mtimer_usage
[hint
]) {
132 pr_debug("hint taken for timer %d irq %d\n",\
133 hint
, sfi_mtimer_array
[hint
].irq
);
134 sfi_mtimer_usage
[hint
] = 1;
135 return &sfi_mtimer_array
[hint
];
138 /* take the first timer available */
139 for (i
= 0; i
< sfi_mtimer_num
;) {
140 if (!sfi_mtimer_usage
[i
]) {
141 sfi_mtimer_usage
[i
] = 1;
142 return &sfi_mtimer_array
[i
];
149 void sfi_free_mtmr(struct sfi_timer_table_entry
*mtmr
)
152 for (i
= 0; i
< sfi_mtimer_num
;) {
153 if (mtmr
->irq
== sfi_mtimer_array
[i
].irq
) {
154 sfi_mtimer_usage
[i
] = 0;
161 /* parse all the mrtc info to a global mrtc array */
162 int __init
sfi_parse_mrtc(struct sfi_table_header
*table
)
164 struct sfi_table_simple
*sb
;
165 struct sfi_rtc_table_entry
*pentry
;
166 struct mpc_intsrc mp_irq
;
170 sb
= (struct sfi_table_simple
*)table
;
172 sfi_mrtc_num
= SFI_GET_NUM_ENTRIES(sb
,
173 struct sfi_rtc_table_entry
);
174 pentry
= (struct sfi_rtc_table_entry
*)sb
->pentry
;
175 totallen
= sfi_mrtc_num
* sizeof(*pentry
);
176 memcpy(sfi_mrtc_array
, pentry
, totallen
);
179 printk(KERN_INFO
"SFI: RTC info (num = %d):\n", sfi_mrtc_num
);
180 pentry
= sfi_mrtc_array
;
181 for (totallen
= 0; totallen
< sfi_mrtc_num
; totallen
++, pentry
++) {
182 printk(KERN_INFO
"RTC[%d]: paddr = 0x%08x, irq = %d\n",
183 totallen
, (u32
)pentry
->phys_addr
, pentry
->irq
);
184 mp_irq
.type
= MP_IOAPIC
;
185 mp_irq
.irqtype
= mp_INT
;
188 mp_irq
.srcbusirq
= pentry
->irq
; /* IRQ */
189 mp_irq
.dstapic
= MP_APIC_ALL
;
190 mp_irq
.dstirq
= pentry
->irq
;
191 save_mp_irq(&mp_irq
);
196 static unsigned long __init
mrst_calibrate_tsc(void)
198 unsigned long flags
, fast_calibrate
;
200 local_irq_save(flags
);
201 fast_calibrate
= apbt_quick_calibrate();
202 local_irq_restore(flags
);
205 return fast_calibrate
;
210 void __init
mrst_time_init(void)
212 switch (mrst_timer_options
) {
213 case MRST_TIMER_APBT_ONLY
:
215 case MRST_TIMER_LAPIC_APBT
:
216 x86_init
.timers
.setup_percpu_clockev
= setup_boot_APIC_clock
;
217 x86_cpuinit
.setup_percpu_clockev
= setup_secondary_APIC_clock
;
220 if (!boot_cpu_has(X86_FEATURE_ARAT
))
222 x86_init
.timers
.setup_percpu_clockev
= setup_boot_APIC_clock
;
223 x86_cpuinit
.setup_percpu_clockev
= setup_secondary_APIC_clock
;
226 /* we need at least one APB timer */
227 sfi_table_parse(SFI_SIG_MTMR
, NULL
, NULL
, sfi_parse_mtmr
);
228 pre_init_apic_IRQ0();
232 void __init
mrst_rtc_init(void)
234 sfi_table_parse(SFI_SIG_MRTC
, NULL
, NULL
, sfi_parse_mrtc
);
237 void __cpuinit
mrst_arch_setup(void)
239 if (boot_cpu_data
.x86
== 6 && boot_cpu_data
.x86_model
== 0x27)
240 __mrst_cpu_chip
= MRST_CPU_CHIP_PENWELL
;
241 else if (boot_cpu_data
.x86
== 6 && boot_cpu_data
.x86_model
== 0x26)
242 __mrst_cpu_chip
= MRST_CPU_CHIP_LINCROFT
;
244 pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n",
245 boot_cpu_data
.x86
, boot_cpu_data
.x86_model
);
246 __mrst_cpu_chip
= MRST_CPU_CHIP_LINCROFT
;
248 pr_debug("Moorestown CPU %s identified\n",
249 (__mrst_cpu_chip
== MRST_CPU_CHIP_LINCROFT
) ?
250 "Lincroft" : "Penwell");
253 /* MID systems don't have i8042 controller */
254 static int mrst_i8042_detect(void)
260 * Moorestown specific x86_init function overrides and early setup
263 void __init
x86_mrst_early_setup(void)
265 x86_init
.resources
.probe_roms
= x86_init_noop
;
266 x86_init
.resources
.reserve_resources
= x86_init_noop
;
268 x86_init
.timers
.timer_init
= mrst_time_init
;
269 x86_init
.timers
.setup_percpu_clockev
= x86_init_noop
;
271 x86_init
.irqs
.pre_vector_init
= x86_init_noop
;
273 x86_init
.oem
.arch_setup
= mrst_arch_setup
;
275 x86_cpuinit
.setup_percpu_clockev
= apbt_setup_secondary_clock
;
277 x86_platform
.calibrate_tsc
= mrst_calibrate_tsc
;
278 x86_platform
.i8042_detect
= mrst_i8042_detect
;
279 x86_init
.pci
.init
= pci_mrst_init
;
280 x86_init
.pci
.fixup_irqs
= x86_init_noop
;
282 legacy_pic
= &null_legacy_pic
;
284 /* Avoid searching for BIOS MP tables */
285 x86_init
.mpparse
.find_smp_config
= x86_init_noop
;
286 x86_init
.mpparse
.get_smp_config
= x86_init_uint_noop
;
291 * if user does not want to use per CPU apb timer, just give it a lower rating
292 * than local apic timer and skip the late per cpu timer init.
294 static inline int __init
setup_x86_mrst_timer(char *arg
)
299 if (strcmp("apbt_only", arg
) == 0)
300 mrst_timer_options
= MRST_TIMER_APBT_ONLY
;
301 else if (strcmp("lapic_and_apbt", arg
) == 0)
302 mrst_timer_options
= MRST_TIMER_LAPIC_APBT
;
304 pr_warning("X86 MRST timer option %s not recognised"
305 " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
311 __setup("x86_mrst_timer=", setup_x86_mrst_timer
);