diff options
Diffstat (limited to 'arch/sh/kernel/time.c')
-rw-r--r-- | arch/sh/kernel/time.c | 518 |
1 files changed, 32 insertions, 486 deletions
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 671b876416bf..314a275c04e0 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | 4 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka |
5 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | 5 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> |
6 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | 6 | * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt |
7 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | 7 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> |
8 | * | 8 | * |
9 | * Some code taken from i386 version. | 9 | * Some code taken from i386 version. |
@@ -11,50 +11,21 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/config.h> | 13 | #include <linux/config.h> |
14 | #include <linux/errno.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
18 | #include <linux/param.h> | 15 | #include <linux/module.h> |
19 | #include <linux/string.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/time.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/init.h> | 16 | #include <linux/init.h> |
25 | #include <linux/smp.h> | ||
26 | #include <linux/profile.h> | 17 | #include <linux/profile.h> |
27 | 18 | #include <asm/clock.h> | |
28 | #include <asm/processor.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/delay.h> | ||
33 | #include <asm/machvec.h> | ||
34 | #include <asm/rtc.h> | 19 | #include <asm/rtc.h> |
35 | #include <asm/freq.h> | 20 | #include <asm/timer.h> |
36 | #include <asm/cpu/timer.h> | ||
37 | #ifdef CONFIG_SH_KGDB | ||
38 | #include <asm/kgdb.h> | 21 | #include <asm/kgdb.h> |
39 | #endif | ||
40 | |||
41 | #include <linux/timex.h> | ||
42 | #include <linux/irq.h> | ||
43 | |||
44 | #define TMU_TOCR_INIT 0x00 | ||
45 | #define TMU0_TCR_INIT 0x0020 | ||
46 | #define TMU_TSTR_INIT 1 | ||
47 | |||
48 | #define TMU0_TCR_CALIB 0x0000 | ||
49 | |||
50 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
51 | #define CLOCKGEN_MEMCLKCR 0xbb040038 | ||
52 | #define MEMCLKCR_RATIO_MASK 0x7 | ||
53 | #endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */ | ||
54 | 22 | ||
55 | extern unsigned long wall_jiffies; | 23 | extern unsigned long wall_jiffies; |
56 | #define TICK_SIZE (tick_nsec / 1000) | 24 | struct sys_timer *sys_timer; |
57 | DEFINE_SPINLOCK(tmu0_lock); | 25 | |
26 | /* Move this somewhere more sensible.. */ | ||
27 | DEFINE_SPINLOCK(rtc_lock); | ||
28 | EXPORT_SYMBOL(rtc_lock); | ||
58 | 29 | ||
59 | /* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want | 30 | /* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want |
60 | * these routines anywhere... */ | 31 | * these routines anywhere... */ |
@@ -66,98 +37,14 @@ void (*rtc_get_time)(struct timespec *); | |||
66 | int (*rtc_set_time)(const time_t); | 37 | int (*rtc_set_time)(const time_t); |
67 | #endif | 38 | #endif |
68 | 39 | ||
69 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
70 | static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 }; | ||
71 | #endif | ||
72 | #if defined(CONFIG_CPU_SH3) | ||
73 | static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
74 | static int stc_values[] = { 0, 1, 4, 2, 5, 0, 0, 0 }; | ||
75 | #define bfc_divisors stc_multipliers | ||
76 | #define bfc_values stc_values | ||
77 | static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; | ||
78 | static int ifc_values[] = { 0, 1, 4, 2, 0, 0, 0, 0 }; | ||
79 | static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
80 | static int pfc_values[] = { 0, 1, 4, 2, 5, 0, 0, 0 }; | ||
81 | #elif defined(CONFIG_CPU_SH4) | ||
82 | #if defined(CONFIG_CPU_SUBTYPE_SH73180) | ||
83 | static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 12, 16 }; | ||
84 | static int ifc_values[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; | ||
85 | #define bfc_divisors ifc_divisors /* Same */ | ||
86 | #define bfc_values ifc_values | ||
87 | #define pfc_divisors ifc_divisors /* Same */ | ||
88 | #define pfc_values ifc_values | ||
89 | #else | ||
90 | static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; | ||
91 | static int ifc_values[] = { 0, 1, 2, 3, 0, 4, 0, 5 }; | ||
92 | #define bfc_divisors ifc_divisors /* Same */ | ||
93 | #define bfc_values ifc_values | ||
94 | static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; | ||
95 | static int pfc_values[] = { 0, 0, 1, 2, 0, 3, 0, 4 }; | ||
96 | #endif | ||
97 | #else | ||
98 | #error "Unknown ifc/bfc/pfc/stc values for this processor" | ||
99 | #endif | ||
100 | |||
101 | /* | 40 | /* |
102 | * Scheduler clock - returns current time in nanosec units. | 41 | * Scheduler clock - returns current time in nanosec units. |
103 | */ | 42 | */ |
104 | unsigned long long sched_clock(void) | 43 | unsigned long long __attribute__ ((weak)) sched_clock(void) |
105 | { | 44 | { |
106 | return (unsigned long long)jiffies * (1000000000 / HZ); | 45 | return (unsigned long long)jiffies * (1000000000 / HZ); |
107 | } | 46 | } |
108 | 47 | ||
109 | static unsigned long do_gettimeoffset(void) | ||
110 | { | ||
111 | int count; | ||
112 | unsigned long flags; | ||
113 | |||
114 | static int count_p = 0x7fffffff; /* for the first call after boot */ | ||
115 | static unsigned long jiffies_p = 0; | ||
116 | |||
117 | /* | ||
118 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
119 | */ | ||
120 | unsigned long jiffies_t; | ||
121 | |||
122 | spin_lock_irqsave(&tmu0_lock, flags); | ||
123 | /* timer count may underflow right here */ | ||
124 | count = ctrl_inl(TMU0_TCNT); /* read the latched count */ | ||
125 | |||
126 | jiffies_t = jiffies; | ||
127 | |||
128 | /* | ||
129 | * avoiding timer inconsistencies (they are rare, but they happen)... | ||
130 | * there is one kind of problem that must be avoided here: | ||
131 | * 1. the timer counter underflows | ||
132 | */ | ||
133 | |||
134 | if( jiffies_t == jiffies_p ) { | ||
135 | if( count > count_p ) { | ||
136 | /* the nutcase */ | ||
137 | |||
138 | if(ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */ | ||
139 | /* | ||
140 | * We cannot detect lost timer interrupts ... | ||
141 | * well, that's why we call them lost, don't we? :) | ||
142 | * [hmm, on the Pentium and Alpha we can ... sort of] | ||
143 | */ | ||
144 | count -= LATCH; | ||
145 | } else { | ||
146 | printk("do_slow_gettimeoffset(): hardware timer problem?\n"); | ||
147 | } | ||
148 | } | ||
149 | } else | ||
150 | jiffies_p = jiffies_t; | ||
151 | |||
152 | count_p = count; | ||
153 | spin_unlock_irqrestore(&tmu0_lock, flags); | ||
154 | |||
155 | count = ((LATCH-1) - count) * TICK_SIZE; | ||
156 | count = (count + LATCH/2) / LATCH; | ||
157 | |||
158 | return count; | ||
159 | } | ||
160 | |||
161 | void do_gettimeofday(struct timeval *tv) | 48 | void do_gettimeofday(struct timeval *tv) |
162 | { | 49 | { |
163 | unsigned long seq; | 50 | unsigned long seq; |
@@ -166,7 +53,7 @@ void do_gettimeofday(struct timeval *tv) | |||
166 | 53 | ||
167 | do { | 54 | do { |
168 | seq = read_seqbegin(&xtime_lock); | 55 | seq = read_seqbegin(&xtime_lock); |
169 | usec = do_gettimeoffset(); | 56 | usec = get_timer_offset(); |
170 | 57 | ||
171 | lost = jiffies - wall_jiffies; | 58 | lost = jiffies - wall_jiffies; |
172 | if (lost) | 59 | if (lost) |
@@ -202,7 +89,7 @@ int do_settimeofday(struct timespec *tv) | |||
202 | * wall time. Discover what correction gettimeofday() would have | 89 | * wall time. Discover what correction gettimeofday() would have |
203 | * made, and then undo it! | 90 | * made, and then undo it! |
204 | */ | 91 | */ |
205 | nsec -= 1000 * (do_gettimeoffset() + | 92 | nsec -= 1000 * (get_timer_offset() + |
206 | (jiffies - wall_jiffies) * (1000000 / HZ)); | 93 | (jiffies - wall_jiffies) * (1000000 / HZ)); |
207 | 94 | ||
208 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | 95 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); |
@@ -224,10 +111,10 @@ EXPORT_SYMBOL(do_settimeofday); | |||
224 | static long last_rtc_update; | 111 | static long last_rtc_update; |
225 | 112 | ||
226 | /* | 113 | /* |
227 | * timer_interrupt() needs to keep up the real-time clock, | 114 | * handle_timer_tick() needs to keep up the real-time clock, |
228 | * as well as call the "do_timer()" routine every clocktick | 115 | * as well as call the "do_timer()" routine every clocktick |
229 | */ | 116 | */ |
230 | static inline void do_timer_interrupt(int irq, struct pt_regs *regs) | 117 | void handle_timer_tick(struct pt_regs *regs) |
231 | { | 118 | { |
232 | do_timer(regs); | 119 | do_timer(regs); |
233 | #ifndef CONFIG_SMP | 120 | #ifndef CONFIG_SMP |
@@ -252,337 +139,35 @@ static inline void do_timer_interrupt(int irq, struct pt_regs *regs) | |||
252 | if (rtc_set_time(xtime.tv_sec) == 0) | 139 | if (rtc_set_time(xtime.tv_sec) == 0) |
253 | last_rtc_update = xtime.tv_sec; | 140 | last_rtc_update = xtime.tv_sec; |
254 | else | 141 | else |
255 | last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ | 142 | /* do it again in 60s */ |
143 | last_rtc_update = xtime.tv_sec - 600; | ||
256 | } | 144 | } |
257 | } | 145 | } |
258 | 146 | ||
259 | /* | 147 | static struct sysdev_class timer_sysclass = { |
260 | * This is the same as the above, except we _also_ save the current | 148 | set_kset_name("timer"), |
261 | * Time Stamp Counter value at the time of the timer interrupt, so that | ||
262 | * we later on can estimate the time of day more exactly. | ||
263 | */ | ||
264 | static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
265 | { | ||
266 | unsigned long timer_status; | ||
267 | |||
268 | /* Clear UNF bit */ | ||
269 | timer_status = ctrl_inw(TMU0_TCR); | ||
270 | timer_status &= ~0x100; | ||
271 | ctrl_outw(timer_status, TMU0_TCR); | ||
272 | |||
273 | /* | ||
274 | * Here we are in the timer irq handler. We just have irqs locally | ||
275 | * disabled but we don't know if the timer_bh is running on the other | ||
276 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
277 | * the irq version of write_lock because as just said we have irq | ||
278 | * locally disabled. -arca | ||
279 | */ | ||
280 | write_seqlock(&xtime_lock); | ||
281 | do_timer_interrupt(irq, regs); | ||
282 | write_sequnlock(&xtime_lock); | ||
283 | |||
284 | return IRQ_HANDLED; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Hah! We'll see if this works (switching from usecs to nsecs). | ||
289 | */ | ||
290 | static unsigned int __init get_timer_frequency(void) | ||
291 | { | ||
292 | u32 freq; | ||
293 | struct timespec ts1, ts2; | ||
294 | unsigned long diff_nsec; | ||
295 | unsigned long factor; | ||
296 | |||
297 | /* Setup the timer: We don't want to generate interrupts, just | ||
298 | * have it count down at its natural rate. | ||
299 | */ | ||
300 | ctrl_outb(0, TMU_TSTR); | ||
301 | #if !defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
302 | ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); | ||
303 | #endif | ||
304 | ctrl_outw(TMU0_TCR_CALIB, TMU0_TCR); | ||
305 | ctrl_outl(0xffffffff, TMU0_TCOR); | ||
306 | ctrl_outl(0xffffffff, TMU0_TCNT); | ||
307 | |||
308 | rtc_get_time(&ts2); | ||
309 | |||
310 | do { | ||
311 | rtc_get_time(&ts1); | ||
312 | } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); | ||
313 | |||
314 | /* actually start the timer */ | ||
315 | ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); | ||
316 | |||
317 | do { | ||
318 | rtc_get_time(&ts2); | ||
319 | } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); | ||
320 | |||
321 | freq = 0xffffffff - ctrl_inl(TMU0_TCNT); | ||
322 | if (ts2.tv_nsec < ts1.tv_nsec) { | ||
323 | ts2.tv_nsec += 1000000000; | ||
324 | ts2.tv_sec--; | ||
325 | } | ||
326 | |||
327 | diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec); | ||
328 | |||
329 | /* this should work well if the RTC has a precision of n Hz, where | ||
330 | * n is an integer. I don't think we have to worry about the other | ||
331 | * cases. */ | ||
332 | factor = (1000000000 + diff_nsec/2) / diff_nsec; | ||
333 | |||
334 | if (factor * diff_nsec > 1100000000 || | ||
335 | factor * diff_nsec < 900000000) | ||
336 | panic("weird RTC (diff_nsec %ld)", diff_nsec); | ||
337 | |||
338 | return freq * factor; | ||
339 | } | ||
340 | |||
341 | void (*board_time_init)(void); | ||
342 | void (*board_timer_setup)(struct irqaction *irq); | ||
343 | |||
344 | static unsigned int sh_pclk_freq __initdata = CONFIG_SH_PCLK_FREQ; | ||
345 | |||
346 | static int __init sh_pclk_setup(char *str) | ||
347 | { | ||
348 | unsigned int freq; | ||
349 | |||
350 | if (get_option(&str, &freq)) | ||
351 | sh_pclk_freq = freq; | ||
352 | |||
353 | return 1; | ||
354 | } | ||
355 | __setup("sh_pclk=", sh_pclk_setup); | ||
356 | |||
357 | static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL}; | ||
358 | |||
359 | void get_current_frequency_divisors(unsigned int *ifc, unsigned int *bfc, unsigned int *pfc) | ||
360 | { | ||
361 | unsigned int frqcr = ctrl_inw(FRQCR); | ||
362 | |||
363 | #if defined(CONFIG_CPU_SH3) | ||
364 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
365 | *ifc = md_table[((frqcr & 0x0070) >> 4)]; | ||
366 | *bfc = md_table[((frqcr & 0x0700) >> 8)]; | ||
367 | *pfc = md_table[frqcr & 0x0007]; | ||
368 | #elif defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
369 | *bfc = stc_multipliers[(frqcr & 0x0300) >> 8]; | ||
370 | *ifc = ifc_divisors[(frqcr & 0x0030) >> 4]; | ||
371 | *pfc = pfc_divisors[frqcr & 0x0003]; | ||
372 | #else | ||
373 | unsigned int tmp; | ||
374 | |||
375 | tmp = (frqcr & 0x8000) >> 13; | ||
376 | tmp |= (frqcr & 0x0030) >> 4; | ||
377 | *bfc = stc_multipliers[tmp]; | ||
378 | tmp = (frqcr & 0x4000) >> 12; | ||
379 | tmp |= (frqcr & 0x000c) >> 2; | ||
380 | *ifc = ifc_divisors[tmp]; | ||
381 | tmp = (frqcr & 0x2000) >> 11; | ||
382 | tmp |= frqcr & 0x0003; | ||
383 | *pfc = pfc_divisors[tmp]; | ||
384 | #endif | ||
385 | #elif defined(CONFIG_CPU_SH4) | ||
386 | #if defined(CONFIG_CPU_SUBTYPE_SH73180) | ||
387 | *ifc = ifc_divisors[(frqcr>> 20) & 0x0007]; | ||
388 | *bfc = bfc_divisors[(frqcr>> 12) & 0x0007]; | ||
389 | *pfc = pfc_divisors[frqcr & 0x0007]; | ||
390 | #else | ||
391 | *ifc = ifc_divisors[(frqcr >> 6) & 0x0007]; | ||
392 | *bfc = bfc_divisors[(frqcr >> 3) & 0x0007]; | ||
393 | *pfc = pfc_divisors[frqcr & 0x0007]; | ||
394 | #endif | ||
395 | #endif | ||
396 | } | ||
397 | |||
398 | /* | ||
399 | * This bit of ugliness builds up accessor routines to get at both | ||
400 | * the divisors and the physical values. | ||
401 | */ | ||
402 | #define _FREQ_TABLE(x) \ | ||
403 | unsigned int get_##x##_divisor(unsigned int value) \ | ||
404 | { return x##_divisors[value]; } \ | ||
405 | \ | ||
406 | unsigned int get_##x##_value(unsigned int divisor) \ | ||
407 | { return x##_values[(divisor - 1)]; } | ||
408 | |||
409 | _FREQ_TABLE(ifc); | ||
410 | _FREQ_TABLE(bfc); | ||
411 | _FREQ_TABLE(pfc); | ||
412 | |||
413 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
414 | |||
415 | /* | ||
416 | * The ST40 divisors are totally different so we set the cpu data | ||
417 | * clocks using a different algorithm | ||
418 | * | ||
419 | * I've just plugged this from the 2.4 code | ||
420 | * - Alex Bennee <kernel-hacker@bennee.com> | ||
421 | */ | ||
422 | #define CCN_PVR_CHIP_SHIFT 24 | ||
423 | #define CCN_PVR_CHIP_MASK 0xff | ||
424 | #define CCN_PVR_CHIP_ST40STB1 0x4 | ||
425 | |||
426 | |||
427 | struct frqcr_data { | ||
428 | unsigned short frqcr; | ||
429 | |||
430 | struct { | ||
431 | unsigned char multiplier; | ||
432 | unsigned char divisor; | ||
433 | } factor[3]; | ||
434 | }; | ||
435 | |||
436 | static struct frqcr_data st40_frqcr_table[] = { | ||
437 | { 0x000, {{1,1}, {1,1}, {1,2}}}, | ||
438 | { 0x002, {{1,1}, {1,1}, {1,4}}}, | ||
439 | { 0x004, {{1,1}, {1,1}, {1,8}}}, | ||
440 | { 0x008, {{1,1}, {1,2}, {1,2}}}, | ||
441 | { 0x00A, {{1,1}, {1,2}, {1,4}}}, | ||
442 | { 0x00C, {{1,1}, {1,2}, {1,8}}}, | ||
443 | { 0x011, {{1,1}, {2,3}, {1,6}}}, | ||
444 | { 0x013, {{1,1}, {2,3}, {1,3}}}, | ||
445 | { 0x01A, {{1,1}, {1,2}, {1,4}}}, | ||
446 | { 0x01C, {{1,1}, {1,2}, {1,8}}}, | ||
447 | { 0x023, {{1,1}, {2,3}, {1,3}}}, | ||
448 | { 0x02C, {{1,1}, {1,2}, {1,8}}}, | ||
449 | { 0x048, {{1,2}, {1,2}, {1,4}}}, | ||
450 | { 0x04A, {{1,2}, {1,2}, {1,6}}}, | ||
451 | { 0x04C, {{1,2}, {1,2}, {1,8}}}, | ||
452 | { 0x05A, {{1,2}, {1,3}, {1,6}}}, | ||
453 | { 0x05C, {{1,2}, {1,3}, {1,6}}}, | ||
454 | { 0x063, {{1,2}, {1,4}, {1,4}}}, | ||
455 | { 0x06C, {{1,2}, {1,4}, {1,8}}}, | ||
456 | { 0x091, {{1,3}, {1,3}, {1,6}}}, | ||
457 | { 0x093, {{1,3}, {1,3}, {1,6}}}, | ||
458 | { 0x0A3, {{1,3}, {1,6}, {1,6}}}, | ||
459 | { 0x0DA, {{1,4}, {1,4}, {1,8}}}, | ||
460 | { 0x0DC, {{1,4}, {1,4}, {1,8}}}, | ||
461 | { 0x0EC, {{1,4}, {1,8}, {1,8}}}, | ||
462 | { 0x123, {{1,4}, {1,4}, {1,8}}}, | ||
463 | { 0x16C, {{1,4}, {1,8}, {1,8}}}, | ||
464 | }; | 149 | }; |
465 | 150 | ||
466 | struct memclk_data { | 151 | static int __init timer_init_sysfs(void) |
467 | unsigned char multiplier; | ||
468 | unsigned char divisor; | ||
469 | }; | ||
470 | |||
471 | static struct memclk_data st40_memclk_table[8] = { | ||
472 | {1,1}, // 000 | ||
473 | {1,2}, // 001 | ||
474 | {1,3}, // 010 | ||
475 | {2,3}, // 011 | ||
476 | {1,4}, // 100 | ||
477 | {1,6}, // 101 | ||
478 | {1,8}, // 110 | ||
479 | {1,8} // 111 | ||
480 | }; | ||
481 | |||
482 | static void st40_specific_time_init(unsigned int module_clock, unsigned short frqcr) | ||
483 | { | 152 | { |
484 | unsigned int cpu_clock, master_clock, bus_clock, memory_clock; | 153 | int ret = sysdev_class_register(&timer_sysclass); |
485 | struct frqcr_data *d; | 154 | if (ret != 0) |
486 | int a; | 155 | return ret; |
487 | unsigned long memclkcr; | ||
488 | struct memclk_data *e; | ||
489 | 156 | ||
490 | for (a = 0; a < ARRAY_SIZE(st40_frqcr_table); a++) { | 157 | sys_timer->dev.cls = &timer_sysclass; |
491 | d = &st40_frqcr_table[a]; | 158 | return sysdev_register(&sys_timer->dev); |
492 | 159 | } | |
493 | if (d->frqcr == (frqcr & 0x1ff)) | ||
494 | break; | ||
495 | } | ||
496 | 160 | ||
497 | if (a == ARRAY_SIZE(st40_frqcr_table)) { | 161 | device_initcall(timer_init_sysfs); |
498 | d = st40_frqcr_table; | ||
499 | 162 | ||
500 | printk("ERROR: Unrecognised FRQCR value (0x%x), " | 163 | void (*board_time_init)(void); |
501 | "using default multipliers\n", frqcr); | ||
502 | } | ||
503 | |||
504 | memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); | ||
505 | e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; | ||
506 | |||
507 | printk(KERN_INFO "Clock multipliers: CPU: %d/%d Bus: %d/%d " | ||
508 | "Mem: %d/%d Periph: %d/%d\n", | ||
509 | d->factor[0].multiplier, d->factor[0].divisor, | ||
510 | d->factor[1].multiplier, d->factor[1].divisor, | ||
511 | e->multiplier, e->divisor, | ||
512 | d->factor[2].multiplier, d->factor[2].divisor); | ||
513 | |||
514 | master_clock = module_clock * d->factor[2].divisor | ||
515 | / d->factor[2].multiplier; | ||
516 | bus_clock = master_clock * d->factor[1].multiplier | ||
517 | / d->factor[1].divisor; | ||
518 | memory_clock = master_clock * e->multiplier | ||
519 | / e->divisor; | ||
520 | cpu_clock = master_clock * d->factor[0].multiplier | ||
521 | / d->factor[0].divisor; | ||
522 | |||
523 | current_cpu_data.cpu_clock = cpu_clock; | ||
524 | current_cpu_data.master_clock = master_clock; | ||
525 | current_cpu_data.bus_clock = bus_clock; | ||
526 | current_cpu_data.memory_clock = memory_clock; | ||
527 | current_cpu_data.module_clock = module_clock; | ||
528 | } | ||
529 | #endif | ||
530 | 164 | ||
531 | void __init time_init(void) | 165 | void __init time_init(void) |
532 | { | 166 | { |
533 | unsigned int timer_freq = 0; | ||
534 | unsigned int ifc, pfc, bfc; | ||
535 | unsigned long interval; | ||
536 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
537 | unsigned long pvr; | ||
538 | unsigned short frqcr; | ||
539 | #endif | ||
540 | |||
541 | if (board_time_init) | 167 | if (board_time_init) |
542 | board_time_init(); | 168 | board_time_init(); |
543 | 169 | ||
544 | /* | 170 | clk_init(); |
545 | * If we don't have an RTC (such as with the SH7300), don't attempt to | ||
546 | * probe the timer frequency. Rely on an either hardcoded peripheral | ||
547 | * clock value, or on the sh_pclk command line option. Note that we | ||
548 | * still need to have CONFIG_SH_PCLK_FREQ set in order for things like | ||
549 | * CLOCK_TICK_RATE to be sane. | ||
550 | */ | ||
551 | current_cpu_data.module_clock = sh_pclk_freq; | ||
552 | |||
553 | #ifdef CONFIG_SH_PCLK_CALC | ||
554 | /* XXX: Switch this over to a more generic test. */ | ||
555 | { | ||
556 | unsigned int freq; | ||
557 | |||
558 | /* | ||
559 | * If we've specified a peripheral clock frequency, and we have | ||
560 | * an RTC, compare it against the autodetected value. Complain | ||
561 | * if there's a mismatch. | ||
562 | */ | ||
563 | timer_freq = get_timer_frequency(); | ||
564 | freq = timer_freq * 4; | ||
565 | |||
566 | if (sh_pclk_freq && (sh_pclk_freq/100*99 > freq || sh_pclk_freq/100*101 < freq)) { | ||
567 | printk(KERN_NOTICE "Calculated peripheral clock value " | ||
568 | "%d differs from sh_pclk value %d, fixing..\n", | ||
569 | freq, sh_pclk_freq); | ||
570 | current_cpu_data.module_clock = freq; | ||
571 | } | ||
572 | } | ||
573 | #endif | ||
574 | |||
575 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
576 | /* XXX: Update ST40 code to use board_time_init() */ | ||
577 | pvr = ctrl_inl(CCN_PVR); | ||
578 | frqcr = ctrl_inw(FRQCR); | ||
579 | printk("time.c ST40 Probe: PVR %08lx, FRQCR %04hx\n", pvr, frqcr); | ||
580 | |||
581 | if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) | ||
582 | st40_specific_time_init(current_cpu_data.module_clock, frqcr); | ||
583 | else | ||
584 | #endif | ||
585 | get_current_frequency_divisors(&ifc, &bfc, &pfc); | ||
586 | 171 | ||
587 | if (rtc_get_time) { | 172 | if (rtc_get_time) { |
588 | rtc_get_time(&xtime); | 173 | rtc_get_time(&xtime); |
@@ -594,51 +179,12 @@ void __init time_init(void) | |||
594 | set_normalized_timespec(&wall_to_monotonic, | 179 | set_normalized_timespec(&wall_to_monotonic, |
595 | -xtime.tv_sec, -xtime.tv_nsec); | 180 | -xtime.tv_sec, -xtime.tv_nsec); |
596 | 181 | ||
597 | if (board_timer_setup) { | ||
598 | board_timer_setup(&irq0); | ||
599 | } else { | ||
600 | setup_irq(TIMER_IRQ, &irq0); | ||
601 | } | ||
602 | |||
603 | /* | 182 | /* |
604 | * for ST40 chips the current_cpu_data should already be set | 183 | * Find the timer to use as the system timer, it will be |
605 | * so not having valid pfc/bfc/ifc shouldn't be a problem | 184 | * initialized for us. |
606 | */ | 185 | */ |
607 | if (!current_cpu_data.master_clock) | 186 | sys_timer = get_sys_timer(); |
608 | current_cpu_data.master_clock = current_cpu_data.module_clock * pfc; | 187 | printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); |
609 | if (!current_cpu_data.bus_clock) | ||
610 | current_cpu_data.bus_clock = current_cpu_data.master_clock / bfc; | ||
611 | if (!current_cpu_data.cpu_clock) | ||
612 | current_cpu_data.cpu_clock = current_cpu_data.master_clock / ifc; | ||
613 | |||
614 | printk("CPU clock: %d.%02dMHz\n", | ||
615 | (current_cpu_data.cpu_clock / 1000000), | ||
616 | (current_cpu_data.cpu_clock % 1000000)/10000); | ||
617 | printk("Bus clock: %d.%02dMHz\n", | ||
618 | (current_cpu_data.bus_clock / 1000000), | ||
619 | (current_cpu_data.bus_clock % 1000000)/10000); | ||
620 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
621 | printk("Memory clock: %d.%02dMHz\n", | ||
622 | (current_cpu_data.memory_clock / 1000000), | ||
623 | (current_cpu_data.memory_clock % 1000000)/10000); | ||
624 | #endif | ||
625 | printk("Module clock: %d.%02dMHz\n", | ||
626 | (current_cpu_data.module_clock / 1000000), | ||
627 | (current_cpu_data.module_clock % 1000000)/10000); | ||
628 | |||
629 | interval = (current_cpu_data.module_clock/4 + HZ/2) / HZ; | ||
630 | |||
631 | printk("Interval = %ld\n", interval); | ||
632 | |||
633 | /* Start TMU0 */ | ||
634 | ctrl_outb(0, TMU_TSTR); | ||
635 | #if !defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
636 | ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); | ||
637 | #endif | ||
638 | ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); | ||
639 | ctrl_outl(interval, TMU0_TCOR); | ||
640 | ctrl_outl(interval, TMU0_TCNT); | ||
641 | ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); | ||
642 | 188 | ||
643 | #if defined(CONFIG_SH_KGDB) | 189 | #if defined(CONFIG_SH_KGDB) |
644 | /* | 190 | /* |