blob: e7fa0d1078a383685e16abe15d7876a441f7bddf [file] [log] [blame]
Ralf Baechlec78cbf42005-09-30 13:59:37 +01001#include <linux/types.h>
Ralf Baechlec78cbf42005-09-30 13:59:37 +01002#include <linux/init.h>
3#include <linux/kernel_stat.h>
4#include <linux/sched.h>
5#include <linux/spinlock.h>
Nicolas Kaiserdd6bfd62006-11-07 09:56:24 +01006#include <linux/interrupt.h>
7#include <linux/mc146818rtc.h>
Ralf Baechlef6e23732007-07-10 17:32:56 +01008#include <linux/smp.h>
Nicolas Kaiserdd6bfd62006-11-07 09:56:24 +01009#include <linux/timex.h>
Ralf Baechlec78cbf42005-09-30 13:59:37 +010010
Ralf Baechlec78cbf42005-09-30 13:59:37 +010011#include <asm/hardirq.h>
12#include <asm/div64.h>
13#include <asm/cpu.h>
14#include <asm/time.h>
Ralf Baechlec78cbf42005-09-30 13:59:37 +010015#include <asm/irq.h>
Ralf Baechlec78cbf42005-09-30 13:59:37 +010016#include <asm/mc146818-time.h>
17#include <asm/msc01_ic.h>
18
19#include <asm/mips-boards/generic.h>
20#include <asm/mips-boards/prom.h>
21#include <asm/mips-boards/simint.h>
Ralf Baechlec78cbf42005-09-30 13:59:37 +010022
23
24unsigned long cpu_khz;
25
Ralf Baechlec78cbf42005-09-30 13:59:37 +010026/*
Ralf Baechle224dc502006-10-21 02:05:20 +010027 * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
Ralf Baechlec78cbf42005-09-30 13:59:37 +010028 */
29static unsigned int __init estimate_cpu_frequency(void)
30{
31 unsigned int prid = read_c0_prid() & 0xffff00;
32 unsigned int count;
33
34#if 1
35 /*
36 * hardwire the board frequency to 12MHz.
37 */
38
39 if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) ||
40 (prid == (PRID_COMP_MIPS | PRID_IMP_25KF)))
41 count = 12000000;
42 else
43 count = 6000000;
44#else
45 unsigned int flags;
46
47 local_irq_save(flags);
48
49 /* Start counter exactly on falling edge of update flag */
50 while (CMOS_READ(RTC_REG_A) & RTC_UIP);
51 while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
52
53 /* Start r4k counter. */
54 write_c0_count(0);
55
56 /* Read counter exactly on falling edge of update flag */
57 while (CMOS_READ(RTC_REG_A) & RTC_UIP);
58 while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
59
60 count = read_c0_count();
61
62 /* restore interrupts */
63 local_irq_restore(flags);
64#endif
65
66 mips_hpt_frequency = count;
67
68 if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
69 (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
70 count *= 2;
71
72 count += 5000; /* round */
73 count -= count%10000;
74
75 return count;
76}
77
Ralf Baechle4b550482007-10-11 23:46:08 +010078void __init plat_time_init(void)
Ralf Baechlec78cbf42005-09-30 13:59:37 +010079{
80 unsigned int est_freq, flags;
81
82 local_irq_save(flags);
83
Ralf Baechlef6e23732007-07-10 17:32:56 +010084 /* Set Data mode - binary. */
Ralf Baechlec78cbf42005-09-30 13:59:37 +010085 CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
86
Ralf Baechle49a89ef2007-10-11 23:46:15 +010087 est_freq = estimate_cpu_frequency();
Ralf Baechlec78cbf42005-09-30 13:59:37 +010088
Ralf Baechlef6e23732007-07-10 17:32:56 +010089 printk(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq / 1000000,
90 (est_freq % 1000000) * 100 / 1000000);
Ralf Baechlec78cbf42005-09-30 13:59:37 +010091
Ralf Baechlef6e23732007-07-10 17:32:56 +010092 cpu_khz = est_freq / 1000;
Ralf Baechlec78cbf42005-09-30 13:59:37 +010093
94 local_irq_restore(flags);
95}
96
97static int mips_cpu_timer_irq;
98
Ralf Baechle937a8012006-10-07 19:44:33 +010099static void mips_timer_dispatch(void)
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100100{
Ralf Baechle937a8012006-10-07 19:44:33 +0100101 do_IRQ(mips_cpu_timer_irq);
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100102}
103
104
Ralf Baechle5fd32652006-07-10 02:37:21 +0100105void __init plat_timer_setup(struct irqaction *irq)
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100106{
107 if (cpu_has_veic) {
108 set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
109 mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
Ralf Baechlef6e23732007-07-10 17:32:56 +0100110 } else {
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100111 if (cpu_has_vint)
Ralf Baechle3b1d4ed2007-06-20 22:27:10 +0100112 set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
113 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100114 }
115
116 /* we are using the cpu counter for timer interrupts */
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100117 setup_irq(mips_cpu_timer_irq, irq);
118
119#ifdef CONFIG_SMP
120 /* irq_desc(riptor) is a global resource, when the interrupt overlaps
121 on seperate cpu's the first one tries to handle the second interrupt.
122 The effect is that the int remains disabled on the second cpu.
123 Mark the interrupt with IRQ_PER_CPU to avoid any confusion */
Atsushi Nemoto14178362006-11-14 01:13:18 +0900124 irq_desc[mips_cpu_timer_irq].flags |= IRQ_PER_CPU;
125 set_irq_handler(mips_cpu_timer_irq, handle_percpu_irq);
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100126#endif
Ralf Baechlec78cbf42005-09-30 13:59:37 +0100127}