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>
28 static u32 sfi_mtimer_usage
[SFI_MTMR_MAX_NUM
];
29 static struct sfi_timer_table_entry sfi_mtimer_array
[SFI_MTMR_MAX_NUM
];
32 struct sfi_rtc_table_entry sfi_mrtc_array
[SFI_MRTC_MAX
];
33 EXPORT_SYMBOL_GPL(sfi_mrtc_array
);
36 static inline void assign_to_mp_irq(struct mpc_intsrc
*m
,
37 struct mpc_intsrc
*mp_irq
)
39 memcpy(mp_irq
, m
, sizeof(struct mpc_intsrc
));
42 static inline int mp_irq_cmp(struct mpc_intsrc
*mp_irq
,
45 return memcmp(mp_irq
, m
, sizeof(struct mpc_intsrc
));
48 static void save_mp_irq(struct mpc_intsrc
*m
)
52 for (i
= 0; i
< mp_irq_entries
; i
++) {
53 if (!mp_irq_cmp(&mp_irqs
[i
], m
))
57 assign_to_mp_irq(m
, &mp_irqs
[mp_irq_entries
]);
58 if (++mp_irq_entries
== MAX_IRQ_SOURCES
)
59 panic("Max # of irq sources exceeded!!\n");
62 /* parse all the mtimer info to a static mtimer array */
63 static int __init
sfi_parse_mtmr(struct sfi_table_header
*table
)
65 struct sfi_table_simple
*sb
;
66 struct sfi_timer_table_entry
*pentry
;
67 struct mpc_intsrc mp_irq
;
70 sb
= (struct sfi_table_simple
*)table
;
71 if (!sfi_mtimer_num
) {
72 sfi_mtimer_num
= SFI_GET_NUM_ENTRIES(sb
,
73 struct sfi_timer_table_entry
);
74 pentry
= (struct sfi_timer_table_entry
*) sb
->pentry
;
75 totallen
= sfi_mtimer_num
* sizeof(*pentry
);
76 memcpy(sfi_mtimer_array
, pentry
, totallen
);
79 printk(KERN_INFO
"SFI: MTIMER info (num = %d):\n", sfi_mtimer_num
);
80 pentry
= sfi_mtimer_array
;
81 for (totallen
= 0; totallen
< sfi_mtimer_num
; totallen
++, pentry
++) {
82 printk(KERN_INFO
"timer[%d]: paddr = 0x%08x, freq = %dHz,"
83 " irq = %d\n", totallen
, (u32
)pentry
->phys_addr
,
84 pentry
->freq_hz
, pentry
->irq
);
87 mp_irq
.type
= MP_IOAPIC
;
88 mp_irq
.irqtype
= mp_INT
;
89 /* triggering mode edge bit 2-3, active high polarity bit 0-1 */
92 mp_irq
.srcbusirq
= pentry
->irq
; /* IRQ */
93 mp_irq
.dstapic
= MP_APIC_ALL
;
94 mp_irq
.dstirq
= pentry
->irq
;
101 struct sfi_timer_table_entry
*sfi_get_mtmr(int hint
)
104 if (hint
< sfi_mtimer_num
) {
105 if (!sfi_mtimer_usage
[hint
]) {
106 pr_debug("hint taken for timer %d irq %d\n",\
107 hint
, sfi_mtimer_array
[hint
].irq
);
108 sfi_mtimer_usage
[hint
] = 1;
109 return &sfi_mtimer_array
[hint
];
112 /* take the first timer available */
113 for (i
= 0; i
< sfi_mtimer_num
;) {
114 if (!sfi_mtimer_usage
[i
]) {
115 sfi_mtimer_usage
[i
] = 1;
116 return &sfi_mtimer_array
[i
];
123 void sfi_free_mtmr(struct sfi_timer_table_entry
*mtmr
)
126 for (i
= 0; i
< sfi_mtimer_num
;) {
127 if (mtmr
->irq
== sfi_mtimer_array
[i
].irq
) {
128 sfi_mtimer_usage
[i
] = 0;
135 /* parse all the mrtc info to a global mrtc array */
136 int __init
sfi_parse_mrtc(struct sfi_table_header
*table
)
138 struct sfi_table_simple
*sb
;
139 struct sfi_rtc_table_entry
*pentry
;
140 struct mpc_intsrc mp_irq
;
144 sb
= (struct sfi_table_simple
*)table
;
146 sfi_mrtc_num
= SFI_GET_NUM_ENTRIES(sb
,
147 struct sfi_rtc_table_entry
);
148 pentry
= (struct sfi_rtc_table_entry
*)sb
->pentry
;
149 totallen
= sfi_mrtc_num
* sizeof(*pentry
);
150 memcpy(sfi_mrtc_array
, pentry
, totallen
);
153 printk(KERN_INFO
"SFI: RTC info (num = %d):\n", sfi_mrtc_num
);
154 pentry
= sfi_mrtc_array
;
155 for (totallen
= 0; totallen
< sfi_mrtc_num
; totallen
++, pentry
++) {
156 printk(KERN_INFO
"RTC[%d]: paddr = 0x%08x, irq = %d\n",
157 totallen
, (u32
)pentry
->phys_addr
, pentry
->irq
);
158 mp_irq
.type
= MP_IOAPIC
;
159 mp_irq
.irqtype
= mp_INT
;
162 mp_irq
.srcbusirq
= pentry
->irq
; /* IRQ */
163 mp_irq
.dstapic
= MP_APIC_ALL
;
164 mp_irq
.dstirq
= pentry
->irq
;
165 save_mp_irq(&mp_irq
);
171 * the secondary clock in Moorestown can be APBT or LAPIC clock, default to
172 * APBT but cmdline option can also override it.
174 static void __cpuinit
mrst_setup_secondary_clock(void)
176 /* restore default lapic clock if disabled by cmdline */
177 if (disable_apbt_percpu
)
178 return setup_secondary_APIC_clock();
179 apbt_setup_secondary_clock();
182 static unsigned long __init
mrst_calibrate_tsc(void)
184 unsigned long flags
, fast_calibrate
;
186 local_irq_save(flags
);
187 fast_calibrate
= apbt_quick_calibrate();
188 local_irq_restore(flags
);
191 return fast_calibrate
;
196 void __init
mrst_time_init(void)
198 sfi_table_parse(SFI_SIG_MTMR
, NULL
, NULL
, sfi_parse_mtmr
);
199 pre_init_apic_IRQ0();
203 void __init
mrst_rtc_init(void)
205 sfi_table_parse(SFI_SIG_MRTC
, NULL
, NULL
, sfi_parse_mrtc
);
209 * if we use per cpu apb timer, the bootclock already setup. if we use lapic
210 * timer and one apbt timer for broadcast, we need to set up lapic boot clock.
212 static void __init
mrst_setup_boot_clock(void)
214 pr_info("%s: per cpu apbt flag %d \n", __func__
, disable_apbt_percpu
);
215 if (disable_apbt_percpu
)
216 setup_boot_APIC_clock();
220 * Moorestown specific x86_init function overrides and early setup
223 void __init
x86_mrst_early_setup(void)
225 x86_init
.resources
.probe_roms
= x86_init_noop
;
226 x86_init
.resources
.reserve_resources
= x86_init_noop
;
228 x86_init
.timers
.timer_init
= mrst_time_init
;
229 x86_init
.timers
.setup_percpu_clockev
= mrst_setup_boot_clock
;
231 x86_init
.irqs
.pre_vector_init
= x86_init_noop
;
233 x86_cpuinit
.setup_percpu_clockev
= mrst_setup_secondary_clock
;
235 x86_platform
.calibrate_tsc
= mrst_calibrate_tsc
;
236 x86_init
.pci
.init
= pci_mrst_init
;
237 x86_init
.pci
.fixup_irqs
= x86_init_noop
;
239 legacy_pic
= &null_legacy_pic
;