blob: 27228f583dae061eab5cff7ca32017ed8b396e13 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4 * Copyright (c) 2003, 2004 Maciej W. Rozycki
5 *
6 * Common time service routines for MIPS machines. See
7 * Documentation/mips/time.README.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
Ralf Baechle656db502007-10-26 13:24:06 +010014#include <linux/bug.h>
Ralf Baechle7bcf7712007-10-11 23:46:09 +010015#include <linux/clockchips.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/sched.h>
20#include <linux/param.h>
Yoichi Yuasab1043cc2007-09-13 13:13:28 +090021#include <linux/profile.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/time.h>
23#include <linux/timex.h>
24#include <linux/smp.h>
25#include <linux/kernel_stat.h>
26#include <linux/spinlock.h>
27#include <linux/interrupt.h>
28#include <linux/module.h>
Ralf Baechleea580402007-10-11 23:46:09 +010029#include <linux/kallsyms.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#include <asm/bootinfo.h>
Ralf Baechleec74e362005-07-13 11:48:45 +000032#include <asm/cache.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/compiler.h>
34#include <asm/cpu.h>
35#include <asm/cpu-features.h>
36#include <asm/div64.h>
37#include <asm/sections.h>
Ralf Baechleea580402007-10-11 23:46:09 +010038#include <asm/smtc_ipi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/time.h>
40
Ralf Baechle7bcf7712007-10-11 23:46:09 +010041#include <irq.h>
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 * forward reference
45 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070046DEFINE_SPINLOCK(rtc_lock);
Ralf Baechle4b550482007-10-11 23:46:08 +010047EXPORT_SYMBOL(rtc_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Ralf Baechle4b550482007-10-11 23:46:08 +010049int __weak rtc_mips_set_time(unsigned long sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
51 return 0;
52}
Ralf Baechle4b550482007-10-11 23:46:08 +010053EXPORT_SYMBOL(rtc_mips_set_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Ralf Baechle4b550482007-10-11 23:46:08 +010055int __weak rtc_mips_set_mmss(unsigned long nowtime)
56{
57 return rtc_mips_set_time(nowtime);
58}
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Ralf Baechlef5ff0a22007-08-13 15:26:12 +010060int update_persistent_clock(struct timespec now)
61{
62 return rtc_mips_set_mmss(now.tv_sec);
63}
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Linus Torvalds1da177e2005-04-16 15:20:36 -070065/*
66 * Null high precision timer functions for systems lacking one.
67 */
Atsushi Nemoto00598562006-11-12 00:10:28 +090068static cycle_t null_hpt_read(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
70 return 0;
71}
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 * High precision timer functions for a R4k-compatible timer.
75 */
Atsushi Nemoto00598562006-11-12 00:10:28 +090076static cycle_t c0_hpt_read(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077{
78 return read_c0_count();
79}
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081int (*mips_timer_state)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Linus Torvalds1da177e2005-04-16 15:20:36 -070083/*
84 * local_timer_interrupt() does profiling and process accounting
85 * on a per-CPU basis.
86 *
87 * In UP mode, it is invoked from the (global) timer_interrupt.
88 *
89 * In SMP mode, it might invoked by per-CPU timer interrupt, or
90 * a broadcasted inter-processor interrupt which itself is triggered
91 * by the global timer interrupt.
92 */
David Howells7d12e782006-10-05 14:55:46 +010093void local_timer_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
Ralf Baechle937a8012006-10-07 19:44:33 +010095 profile_tick(CPU_PROFILING);
David Howells7d12e782006-10-05 14:55:46 +010096 update_process_times(user_mode(get_irq_regs()));
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98
David Howells7d12e782006-10-05 14:55:46 +010099int null_perf_irq(void)
Ralf Baechleba339c02005-12-09 12:29:38 +0000100{
101 return 0;
102}
103
Ralf Baechle91a2fcc2007-10-11 23:46:09 +0100104EXPORT_SYMBOL(null_perf_irq);
105
David Howells7d12e782006-10-05 14:55:46 +0100106int (*perf_irq)(void) = null_perf_irq;
Ralf Baechleba339c02005-12-09 12:29:38 +0000107
Ralf Baechleba339c02005-12-09 12:29:38 +0000108EXPORT_SYMBOL(perf_irq);
109
Chris Dearmanffe9ee42007-05-24 22:24:20 +0100110/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 * time_init() - it does the following things.
112 *
Ralf Baechle4b550482007-10-11 23:46:08 +0100113 * 1) plat_time_init() -
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 * a) (optional) set up RTC routines,
115 * b) (optional) calibrate and set the mips_hpt_frequency
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900116 * (only needed if you intended to use cpu counter as timer interrupt
117 * source)
Ralf Baechle4b550482007-10-11 23:46:08 +0100118 * 2) calculate a couple of cached variables for later usage
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 */
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121unsigned int mips_hpt_frequency;
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123static unsigned int __init calibrate_hpt(void)
124{
Atsushi Nemoto00598562006-11-12 00:10:28 +0900125 cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 const int loops = HZ / 10;
128 int log_2_loops = 0;
129 int i;
130
131 /*
132 * We want to calibrate for 0.1s, but to avoid a 64-bit
133 * division we round the number of loops up to the nearest
134 * power of 2.
135 */
136 while (loops > 1 << log_2_loops)
137 log_2_loops++;
138 i = 1 << log_2_loops;
139
140 /*
141 * Wait for a rising edge of the timer interrupt.
142 */
143 while (mips_timer_state());
144 while (!mips_timer_state());
145
146 /*
147 * Now see how many high precision timer ticks happen
148 * during the calculated number of periods between timer
149 * interrupts.
150 */
Atsushi Nemoto00598562006-11-12 00:10:28 +0900151 hpt_start = clocksource_mips.read();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 do {
153 while (mips_timer_state());
154 while (!mips_timer_state());
155 } while (--i);
Atsushi Nemoto00598562006-11-12 00:10:28 +0900156 hpt_end = clocksource_mips.read();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Atsushi Nemoto00598562006-11-12 00:10:28 +0900158 hpt_count = (hpt_end - hpt_start) & clocksource_mips.mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 hz = HZ;
Atsushi Nemoto00598562006-11-12 00:10:28 +0900160 frequency = hpt_count * hz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162 return frequency >> log_2_loops;
163}
164
Atsushi Nemoto00598562006-11-12 00:10:28 +0900165struct clocksource clocksource_mips = {
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900166 .name = "MIPS",
Franck Bui-Huu55d0b4e2007-05-04 17:36:44 +0200167 .mask = CLOCKSOURCE_MASK(32),
Thomas Gleixner877fe382007-02-16 01:27:40 -0800168 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900169};
170
Ralf Baechle93c846f2007-10-19 08:13:08 +0100171void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900172{
173 u64 temp;
174 u32 shift;
175
Ralf Baechle93c846f2007-10-19 08:13:08 +0100176 /* Find a shift value */
177 for (shift = 32; shift > 0; shift--) {
178 temp = (u64) NSEC_PER_SEC << shift;
179 do_div(temp, clock);
180 if ((temp >> 32) == 0)
181 break;
182 }
183 cs->shift = shift;
184 cs->mult = (u32) temp;
185}
186
187void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
188 unsigned int clock)
189{
190 u64 temp;
191 u32 shift;
192
193 /* Find a shift value */
194 for (shift = 32; shift > 0; shift--) {
Atsushi Nemoto508a7752007-10-20 00:28:33 +0900195 temp = (u64) clock << shift;
196 do_div(temp, NSEC_PER_SEC);
Ralf Baechle93c846f2007-10-19 08:13:08 +0100197 if ((temp >> 32) == 0)
198 break;
199 }
200 cd->shift = shift;
201 cd->mult = (u32) temp;
202}
203
204static void __init init_mips_clocksource(void)
205{
Atsushi Nemoto00598562006-11-12 00:10:28 +0900206 if (!mips_hpt_frequency || clocksource_mips.read == null_hpt_read)
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900207 return;
208
209 /* Calclate a somewhat reasonable rating value */
210 clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
Ralf Baechle93c846f2007-10-19 08:13:08 +0100211
212 clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900213
214 clocksource_register(&clocksource_mips);
215}
216
Ralf Baechle4b550482007-10-11 23:46:08 +0100217void __init __weak plat_time_init(void)
218{
219}
220
Ralf Baechle656db502007-10-26 13:24:06 +0100221/*
222 * This function exists in order to cause an error due to a duplicate
223 * definition if platform code should have its own implementation. The hook
224 * to use instead is plat_time_init. plat_time_init does not receive the
225 * irqaction pointer argument anymore. This is because any function which
226 * initializes an interrupt timer now takes care of its own request_irq rsp.
227 * setup_irq calls and each clock_event_device should use its own
228 * struct irqrequest.
229 */
230void __init plat_timer_setup(struct irqaction *irq)
Ralf Baechle7bcf7712007-10-11 23:46:09 +0100231{
Ralf Baechle656db502007-10-26 13:24:06 +0100232 BUG();
Ralf Baechle7bcf7712007-10-11 23:46:09 +0100233}
234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235void __init time_init(void)
236{
Ralf Baechle4b550482007-10-11 23:46:08 +0100237 plat_time_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 /* Choose appropriate high precision timer routines. */
Atsushi Nemoto00598562006-11-12 00:10:28 +0900240 if (!cpu_has_counter && !clocksource_mips.read)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 /* No high precision timer -- sorry. */
Atsushi Nemoto00598562006-11-12 00:10:28 +0900242 clocksource_mips.read = null_hpt_read;
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900243 else if (!mips_hpt_frequency && !mips_timer_state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 /* A high precision timer of unknown frequency. */
Atsushi Nemoto00598562006-11-12 00:10:28 +0900245 if (!clocksource_mips.read)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 /* No external high precision timer -- use R4k. */
Atsushi Nemoto00598562006-11-12 00:10:28 +0900247 clocksource_mips.read = c0_hpt_read;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 } else {
249 /* We know counter frequency. Or we can get it. */
Atsushi Nemoto00598562006-11-12 00:10:28 +0900250 if (!clocksource_mips.read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 /* No external high precision timer -- use R4k. */
Atsushi Nemoto00598562006-11-12 00:10:28 +0900252 clocksource_mips.read = c0_hpt_read;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 }
254 if (!mips_hpt_frequency)
255 mips_hpt_frequency = calibrate_hpt();
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /* Report the high precision timer rate for a reference. */
258 printk("Using %u.%03u MHz high precision timer.\n",
259 ((mips_hpt_frequency + 500) / 1000) / 1000,
260 ((mips_hpt_frequency + 500) / 1000) % 1000);
261 }
262
Atsushi Nemoto16b7b2a2006-10-24 00:21:27 +0900263 init_mips_clocksource();
Ralf Baechle7bcf7712007-10-11 23:46:09 +0100264 mips_clockevent_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265}