blob: 37735bfc3afda540f7bb56adae0cfc0dcd7d075e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Setting up the clock on the MIPS boards.
19 */
20
21#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/init.h>
23#include <linux/kernel_stat.h>
24#include <linux/sched.h>
25#include <linux/spinlock.h>
26#include <linux/interrupt.h>
27#include <linux/time.h>
28#include <linux/timex.h>
29#include <linux/mc146818rtc.h>
30
31#include <asm/mipsregs.h>
Ralf Baechle41c594a2006-04-05 09:45:45 +010032#include <asm/mipsmtregs.h>
Ralf Baechlee01402b2005-07-14 15:57:16 +000033#include <asm/hardirq.h>
34#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/div64.h>
36#include <asm/cpu.h>
37#include <asm/time.h>
38#include <asm/mc146818-time.h>
Ralf Baechlee01402b2005-07-14 15:57:16 +000039#include <asm/msc01_ic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41#include <asm/mips-boards/generic.h>
42#include <asm/mips-boards/prom.h>
Maciej W. Rozyckifc095a92006-09-12 19:12:18 +010043
44#ifdef CONFIG_MIPS_ATLAS
45#include <asm/mips-boards/atlasint.h>
46#endif
47#ifdef CONFIG_MIPS_MALTA
Ralf Baechlee01402b2005-07-14 15:57:16 +000048#include <asm/mips-boards/maltaint.h>
Maciej W. Rozyckifc095a92006-09-12 19:12:18 +010049#endif
Atsushi Nemotof75f3692007-01-08 01:27:40 +090050#ifdef CONFIG_MIPS_SEAD
51#include <asm/mips-boards/seadint.h>
52#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54unsigned long cpu_khz;
55
Ralf Baechle41c594a2006-04-05 09:45:45 +010056#define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR)
57
Ralf Baechlee01402b2005-07-14 15:57:16 +000058static int mips_cpu_timer_irq;
Ralf Baechle41c594a2006-04-05 09:45:45 +010059extern void smtc_timer_broadcast(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Ralf Baechle937a8012006-10-07 19:44:33 +010061static void mips_timer_dispatch(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062{
Ralf Baechle937a8012006-10-07 19:44:33 +010063 do_IRQ(mips_cpu_timer_irq);
Ralf Baechlee01402b2005-07-14 15:57:16 +000064}
65
Ralf Baechle41c594a2006-04-05 09:45:45 +010066/*
67 * Redeclare until I get around mopping the timer code insanity on MIPS.
68 */
Ralf Baechle937a8012006-10-07 19:44:33 +010069extern int null_perf_irq(void);
Ralf Baechleba339c02005-12-09 12:29:38 +000070
Ralf Baechle937a8012006-10-07 19:44:33 +010071extern int (*perf_irq)(void);
Ralf Baechleba339c02005-12-09 12:29:38 +000072
Ralf Baechle937a8012006-10-07 19:44:33 +010073irqreturn_t mips_timer_interrupt(int irq, void *dev_id)
Ralf Baechlee01402b2005-07-14 15:57:16 +000074{
Ralf Baechle340ee4b2005-08-17 17:44:08 +000075 int cpu = smp_processor_id();
76
Ralf Baechle41c594a2006-04-05 09:45:45 +010077#ifdef CONFIG_MIPS_MT_SMTC
Kevin D. Kissell846acaa2006-09-12 12:08:08 +020078 /*
Ralf Baechle41c594a2006-04-05 09:45:45 +010079 * In an SMTC system, one Count/Compare set exists per VPE.
80 * Which TC within a VPE gets the interrupt is essentially
81 * random - we only know that it shouldn't be one with
82 * IXMT set. Whichever TC gets the interrupt needs to
83 * send special interprocessor interrupts to the other
84 * TCs to make sure that they schedule, etc.
85 *
86 * That code is specific to the SMTC kernel, not to
87 * the a particular platform, so it's invoked from
88 * the general MIPS timer_interrupt routine.
89 */
90
Kevin D. Kissell846acaa2006-09-12 12:08:08 +020091 int vpflags;
92
Ralf Baechle41c594a2006-04-05 09:45:45 +010093 /*
Kevin D. Kissell846acaa2006-09-12 12:08:08 +020094 * We could be here due to timer interrupt,
95 * perf counter overflow, or both.
Ralf Baechle41c594a2006-04-05 09:45:45 +010096 */
Kevin D. Kissell846acaa2006-09-12 12:08:08 +020097 if (read_c0_cause() & (1 << 26))
Ralf Baechle937a8012006-10-07 19:44:33 +010098 perf_irq();
Ralf Baechle41c594a2006-04-05 09:45:45 +010099
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200100 if (read_c0_cause() & (1 << 30)) {
101 /* If timer interrupt, make it de-assert */
102 write_c0_compare (read_c0_count() - 1);
Ralf Baechle41c594a2006-04-05 09:45:45 +0100103 /*
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200104 * DVPE is necessary so long as cross-VPE interrupts
105 * are done via read-modify-write of Cause register.
Ralf Baechle41c594a2006-04-05 09:45:45 +0100106 */
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200107 vpflags = dvpe();
108 clear_c0_cause(CPUCTR_IMASKBIT);
109 evpe(vpflags);
110 /*
111 * There are things we only want to do once per tick
112 * in an "MP" system. One TC of each VPE will take
113 * the actual timer interrupt. The others will get
114 * timer broadcast IPIs. We use whoever it is that takes
115 * the tick on VPE 0 to run the full timer_interrupt().
116 */
117 if (cpu_data[cpu].vpe_id == 0) {
Ralf Baechle937a8012006-10-07 19:44:33 +0100118 timer_interrupt(irq, NULL);
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200119 smtc_timer_broadcast(cpu_data[cpu].vpe_id);
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200120 } else {
121 write_c0_compare(read_c0_count() +
122 (mips_hpt_frequency/HZ));
Ralf Baechle937a8012006-10-07 19:44:33 +0100123 local_timer_interrupt(irq, dev_id);
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200124 smtc_timer_broadcast(cpu_data[cpu].vpe_id);
125 }
126 }
Ralf Baechle41c594a2006-04-05 09:45:45 +0100127#else /* CONFIG_MIPS_MT_SMTC */
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200128 int r2 = cpu_has_mips_r2;
129
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000130 if (cpu == 0) {
131 /*
Ralf Baechleba339c02005-12-09 12:29:38 +0000132 * CPU 0 handles the global timer interrupt job and process
133 * accounting resets count/compare registers to trigger next
134 * timer int.
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000135 */
Ralf Baechleba339c02005-12-09 12:29:38 +0000136 if (!r2 || (read_c0_cause() & (1 << 26)))
Ralf Baechle937a8012006-10-07 19:44:33 +0100137 if (perf_irq())
Ralf Baechleba339c02005-12-09 12:29:38 +0000138 goto out;
139
140 /* we keep interrupt disabled all the time */
141 if (!r2 || (read_c0_cause() & (1 << 30)))
Ralf Baechle937a8012006-10-07 19:44:33 +0100142 timer_interrupt(irq, NULL);
Ralf Baechle11e6df62005-12-09 12:09:22 +0000143 } else {
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000144 /* Everyone else needs to reset the timer int here as
145 ll_local_timer_interrupt doesn't */
146 /*
147 * FIXME: need to cope with counter underflow.
148 * More support needs to be added to kernel/time for
149 * counter/timer interrupts on multiple CPU's
150 */
Ralf Baechle41c594a2006-04-05 09:45:45 +0100151 write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
152
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000153 /*
Ralf Baechle41c594a2006-04-05 09:45:45 +0100154 * Other CPUs should do profiling and process accounting
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000155 */
Ralf Baechle937a8012006-10-07 19:44:33 +0100156 local_timer_interrupt(irq, dev_id);
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000157 }
Ralf Baechleba339c02005-12-09 12:29:38 +0000158out:
Kevin D. Kissell846acaa2006-09-12 12:08:08 +0200159#endif /* CONFIG_MIPS_MT_SMTC */
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000160 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161}
162
163/*
Ralf Baechle224dc502006-10-21 02:05:20 +0100164 * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 */
166static unsigned int __init estimate_cpu_frequency(void)
167{
168 unsigned int prid = read_c0_prid() & 0xffff00;
169 unsigned int count;
170
Ralf Baechle41c594a2006-04-05 09:45:45 +0100171#if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_SIM)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 /*
173 * The SEAD board doesn't have a real time clock, so we can't
174 * really calculate the timer frequency
175 * For now we hardwire the SEAD board frequency to 12MHz.
176 */
Ralf Baechle42a3b4f2005-09-03 15:56:17 -0700177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) ||
179 (prid == (PRID_COMP_MIPS | PRID_IMP_25KF)))
180 count = 12000000;
181 else
182 count = 6000000;
183#endif
184#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA)
Ralf Baechlee79f55a2006-10-31 19:53:15 +0000185 unsigned long flags;
Ralf Baechle70e46f42006-10-31 18:33:09 +0000186 unsigned int start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
188 local_irq_save(flags);
189
190 /* Start counter exactly on falling edge of update flag */
191 while (CMOS_READ(RTC_REG_A) & RTC_UIP);
192 while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
193
194 /* Start r4k counter. */
Ralf Baechle70e46f42006-10-31 18:33:09 +0000195 start = read_c0_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197 /* Read counter exactly on falling edge of update flag */
198 while (CMOS_READ(RTC_REG_A) & RTC_UIP);
199 while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
200
Ralf Baechle70e46f42006-10-31 18:33:09 +0000201 count = read_c0_count() - start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 /* restore interrupts */
204 local_irq_restore(flags);
205#endif
206
207 mips_hpt_frequency = count;
208 if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
209 (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
210 count *= 2;
211
212 count += 5000; /* round */
213 count -= count%10000;
214
215 return count;
216}
217
218unsigned long __init mips_rtc_get_time(void)
219{
220 return mc146818_get_cmos_time();
221}
222
223void __init mips_time_init(void)
224{
Ralf Baechleece22462006-07-09 22:27:23 +0100225 unsigned int est_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 /* Set Data mode - binary. */
228 CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 est_freq = estimate_cpu_frequency ();
231
232 printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
233 (est_freq%1000000)*100/1000000);
234
235 cpu_khz = est_freq / 1000;
Ralf Baechle79894c72007-05-16 17:54:08 +0200236
237 mips_scroll_message();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
Ralf Baechle54d0a212006-07-09 21:38:56 +0100240void __init plat_timer_setup(struct irqaction *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
Atsushi Nemotof75f3692007-01-08 01:27:40 +0900242#ifdef MSC01E_INT_BASE
Ralf Baechlee01402b2005-07-14 15:57:16 +0000243 if (cpu_has_veic) {
244 set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch);
245 mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
Atsushi Nemotof75f3692007-01-08 01:27:40 +0900246 } else
247#endif
248 {
Ralf Baechlee01402b2005-07-14 15:57:16 +0000249 if (cpu_has_vint)
250 set_vi_handler (MIPSCPU_INT_CPUCTR, mips_timer_dispatch);
251 mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR;
252 }
253
254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 /* we are using the cpu counter for timer interrupts */
Ralf Baechlee01402b2005-07-14 15:57:16 +0000256 irq->handler = mips_timer_interrupt; /* we use our own handler */
Ralf Baechle41c594a2006-04-05 09:45:45 +0100257#ifdef CONFIG_MIPS_MT_SMTC
258 setup_irq_smtc(mips_cpu_timer_irq, irq, CPUCTR_IMASKBIT);
259#else
Ralf Baechlee01402b2005-07-14 15:57:16 +0000260 setup_irq(mips_cpu_timer_irq, irq);
Ralf Baechle41c594a2006-04-05 09:45:45 +0100261#endif /* CONFIG_MIPS_MT_SMTC */
Ralf Baechlee01402b2005-07-14 15:57:16 +0000262
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000263#ifdef CONFIG_SMP
264 /* irq_desc(riptor) is a global resource, when the interrupt overlaps
265 on seperate cpu's the first one tries to handle the second interrupt.
266 The effect is that the int remains disabled on the second cpu.
267 Mark the interrupt with IRQ_PER_CPU to avoid any confusion */
268 irq_desc[mips_cpu_timer_irq].status |= IRQ_PER_CPU;
Atsushi Nemoto14178362006-11-14 01:13:18 +0900269 set_irq_handler(mips_cpu_timer_irq, handle_percpu_irq);
Ralf Baechle340ee4b2005-08-17 17:44:08 +0000270#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}