diff options
Diffstat (limited to 'arch/sh64')
-rw-r--r-- | arch/sh64/kernel/time.c | 196 |
1 files changed, 67 insertions, 129 deletions
diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c index 06f3c179e345..d1a9b5b078bd 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * arch/sh64/kernel/time.c | 6 | * arch/sh64/kernel/time.c |
7 | * | 7 | * |
8 | * Copyright (C) 2000, 2001 Paolo Alberelli | 8 | * Copyright (C) 2000, 2001 Paolo Alberelli |
9 | * Copyright (C) 2003, 2004 Paul Mundt | 9 | * Copyright (C) 2003 - 2007 Paul Mundt |
10 | * Copyright (C) 2003 Richard Curnow | 10 | * Copyright (C) 2003 Richard Curnow |
11 | * | 11 | * |
12 | * Original TMU/RTC code taken from sh version. | 12 | * Original TMU/RTC code taken from sh version. |
@@ -14,7 +14,6 @@ | |||
14 | * Some code taken from i386 version. | 14 | * Some code taken from i386 version. |
15 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | 15 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds |
16 | */ | 16 | */ |
17 | |||
18 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
19 | #include <linux/rwsem.h> | 18 | #include <linux/rwsem.h> |
20 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
@@ -30,17 +29,15 @@ | |||
30 | #include <linux/smp.h> | 29 | #include <linux/smp.h> |
31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
32 | #include <linux/bcd.h> | 31 | #include <linux/bcd.h> |
33 | 32 | #include <linux/timex.h> | |
33 | #include <linux/irq.h> | ||
34 | #include <linux/platform_device.h> | ||
34 | #include <asm/registers.h> /* required by inline __asm__ stmt. */ | 35 | #include <asm/registers.h> /* required by inline __asm__ stmt. */ |
35 | |||
36 | #include <asm/processor.h> | 36 | #include <asm/processor.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/io.h> | 38 | #include <asm/io.h> |
39 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
40 | #include <asm/delay.h> | 40 | #include <asm/delay.h> |
41 | |||
42 | #include <linux/timex.h> | ||
43 | #include <linux/irq.h> | ||
44 | #include <asm/hardware.h> | 41 | #include <asm/hardware.h> |
45 | 42 | ||
46 | #define TMU_TOCR_INIT 0x00 | 43 | #define TMU_TOCR_INIT 0x00 |
@@ -48,19 +45,11 @@ | |||
48 | #define TMU_TSTR_INIT 1 | 45 | #define TMU_TSTR_INIT 1 |
49 | #define TMU_TSTR_OFF 0 | 46 | #define TMU_TSTR_OFF 0 |
50 | 47 | ||
51 | /* RCR1 Bits */ | 48 | /* Real Time Clock */ |
52 | #define RCR1_CF 0x80 /* Carry Flag */ | 49 | #define RTC_BLOCK_OFF 0x01040000 |
53 | #define RCR1_CIE 0x10 /* Carry Interrupt Enable */ | 50 | #define RTC_BASE PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF |
54 | #define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ | 51 | #define RTC_RCR1_CIE 0x10 /* Carry Interrupt Enable */ |
55 | #define RCR1_AF 0x01 /* Alarm Flag */ | 52 | #define RTC_RCR1 (rtc_base + 0x38) |
56 | |||
57 | /* RCR2 Bits */ | ||
58 | #define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ | ||
59 | #define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ | ||
60 | #define RCR2_RTCEN 0x08 /* ENable RTC */ | ||
61 | #define RCR2_ADJ 0x04 /* ADJustment (30-second) */ | ||
62 | #define RCR2_RESET 0x02 /* Reset bit */ | ||
63 | #define RCR2_START 0x01 /* Start bit */ | ||
64 | 53 | ||
65 | /* Clock, Power and Reset Controller */ | 54 | /* Clock, Power and Reset Controller */ |
66 | #define CPRC_BLOCK_OFF 0x01010000 | 55 | #define CPRC_BLOCK_OFF 0x01010000 |
@@ -84,27 +73,6 @@ | |||
84 | #define TMU0_TCNT TMU0_BASE+0x4 /* Long access */ | 73 | #define TMU0_TCNT TMU0_BASE+0x4 /* Long access */ |
85 | #define TMU0_TCR TMU0_BASE+0x8 /* Word access */ | 74 | #define TMU0_TCR TMU0_BASE+0x8 /* Word access */ |
86 | 75 | ||
87 | /* Real Time Clock */ | ||
88 | #define RTC_BLOCK_OFF 0x01040000 | ||
89 | #define RTC_BASE PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF | ||
90 | |||
91 | #define R64CNT rtc_base+0x00 | ||
92 | #define RSECCNT rtc_base+0x04 | ||
93 | #define RMINCNT rtc_base+0x08 | ||
94 | #define RHRCNT rtc_base+0x0c | ||
95 | #define RWKCNT rtc_base+0x10 | ||
96 | #define RDAYCNT rtc_base+0x14 | ||
97 | #define RMONCNT rtc_base+0x18 | ||
98 | #define RYRCNT rtc_base+0x1c /* 16bit */ | ||
99 | #define RSECAR rtc_base+0x20 | ||
100 | #define RMINAR rtc_base+0x24 | ||
101 | #define RHRAR rtc_base+0x28 | ||
102 | #define RWKAR rtc_base+0x2c | ||
103 | #define RDAYAR rtc_base+0x30 | ||
104 | #define RMONAR rtc_base+0x34 | ||
105 | #define RCR1 rtc_base+0x38 | ||
106 | #define RCR2 rtc_base+0x3c | ||
107 | |||
108 | #define TICK_SIZE (tick_nsec / 1000) | 76 | #define TICK_SIZE (tick_nsec / 1000) |
109 | 77 | ||
110 | static unsigned long tmu_base, rtc_base; | 78 | static unsigned long tmu_base, rtc_base; |
@@ -236,47 +204,23 @@ int do_settimeofday(struct timespec *tv) | |||
236 | } | 204 | } |
237 | EXPORT_SYMBOL(do_settimeofday); | 205 | EXPORT_SYMBOL(do_settimeofday); |
238 | 206 | ||
239 | static int set_rtc_time(unsigned long nowtime) | 207 | /* Dummy RTC ops */ |
208 | static void null_rtc_get_time(struct timespec *tv) | ||
240 | { | 209 | { |
241 | int retval = 0; | 210 | tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0); |
242 | int real_seconds, real_minutes, cmos_minutes; | 211 | tv->tv_nsec = 0; |
243 | 212 | } | |
244 | ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */ | ||
245 | |||
246 | cmos_minutes = ctrl_inb(RMINCNT); | ||
247 | BCD_TO_BIN(cmos_minutes); | ||
248 | |||
249 | /* | ||
250 | * since we're only adjusting minutes and seconds, | ||
251 | * don't interfere with hour overflow. This avoids | ||
252 | * messing with unknown time zones but requires your | ||
253 | * RTC not to be off by more than 15 minutes | ||
254 | */ | ||
255 | real_seconds = nowtime % 60; | ||
256 | real_minutes = nowtime / 60; | ||
257 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
258 | real_minutes += 30; /* correct for half hour time zone */ | ||
259 | real_minutes %= 60; | ||
260 | |||
261 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
262 | BIN_TO_BCD(real_seconds); | ||
263 | BIN_TO_BCD(real_minutes); | ||
264 | ctrl_outb(real_seconds, RSECCNT); | ||
265 | ctrl_outb(real_minutes, RMINCNT); | ||
266 | } else { | ||
267 | printk(KERN_WARNING | ||
268 | "set_rtc_time: can't update from %d to %d\n", | ||
269 | cmos_minutes, real_minutes); | ||
270 | retval = -1; | ||
271 | } | ||
272 | |||
273 | ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */ | ||
274 | 213 | ||
275 | return retval; | 214 | static int null_rtc_set_time(const time_t secs) |
215 | { | ||
216 | return 0; | ||
276 | } | 217 | } |
277 | 218 | ||
219 | void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; | ||
220 | int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; | ||
221 | |||
278 | /* last time the RTC clock got updated */ | 222 | /* last time the RTC clock got updated */ |
279 | static long last_rtc_update = 0; | 223 | static long last_rtc_update; |
280 | 224 | ||
281 | /* | 225 | /* |
282 | * timer_interrupt() needs to keep up the real-time clock, | 226 | * timer_interrupt() needs to keep up the real-time clock, |
@@ -312,10 +256,11 @@ static inline void do_timer_interrupt(void) | |||
312 | xtime.tv_sec > last_rtc_update + 660 && | 256 | xtime.tv_sec > last_rtc_update + 660 && |
313 | (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && | 257 | (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && |
314 | (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { | 258 | (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { |
315 | if (set_rtc_time(xtime.tv_sec) == 0) | 259 | if (rtc_sh_set_time(xtime.tv_sec) == 0) |
316 | last_rtc_update = xtime.tv_sec; | 260 | last_rtc_update = xtime.tv_sec; |
317 | else | 261 | else |
318 | last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ | 262 | /* do it again in 60 s */ |
263 | last_rtc_update = xtime.tv_sec - 600; | ||
319 | } | 264 | } |
320 | } | 265 | } |
321 | 266 | ||
@@ -347,50 +292,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
347 | return IRQ_HANDLED; | 292 | return IRQ_HANDLED; |
348 | } | 293 | } |
349 | 294 | ||
350 | static unsigned long get_rtc_time(void) | ||
351 | { | ||
352 | unsigned int sec, min, hr, wk, day, mon, yr, yr100; | ||
353 | |||
354 | again: | ||
355 | do { | ||
356 | ctrl_outb(0, RCR1); /* Clear CF-bit */ | ||
357 | sec = ctrl_inb(RSECCNT); | ||
358 | min = ctrl_inb(RMINCNT); | ||
359 | hr = ctrl_inb(RHRCNT); | ||
360 | wk = ctrl_inb(RWKCNT); | ||
361 | day = ctrl_inb(RDAYCNT); | ||
362 | mon = ctrl_inb(RMONCNT); | ||
363 | yr = ctrl_inw(RYRCNT); | ||
364 | yr100 = (yr >> 8); | ||
365 | yr &= 0xff; | ||
366 | } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); | ||
367 | |||
368 | BCD_TO_BIN(yr100); | ||
369 | BCD_TO_BIN(yr); | ||
370 | BCD_TO_BIN(mon); | ||
371 | BCD_TO_BIN(day); | ||
372 | BCD_TO_BIN(hr); | ||
373 | BCD_TO_BIN(min); | ||
374 | BCD_TO_BIN(sec); | ||
375 | |||
376 | if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 || | ||
377 | hr > 23 || min > 59 || sec > 59) { | ||
378 | printk(KERN_ERR | ||
379 | "SH RTC: invalid value, resetting to 1 Jan 2000\n"); | ||
380 | ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */ | ||
381 | ctrl_outb(0, RSECCNT); | ||
382 | ctrl_outb(0, RMINCNT); | ||
383 | ctrl_outb(0, RHRCNT); | ||
384 | ctrl_outb(6, RWKCNT); | ||
385 | ctrl_outb(1, RDAYCNT); | ||
386 | ctrl_outb(1, RMONCNT); | ||
387 | ctrl_outw(0x2000, RYRCNT); | ||
388 | ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */ | ||
389 | goto again; | ||
390 | } | ||
391 | |||
392 | return mktime(yr100 * 100 + yr, mon, day, hr, min, sec); | ||
393 | } | ||
394 | 295 | ||
395 | static __init unsigned int get_cpu_hz(void) | 296 | static __init unsigned int get_cpu_hz(void) |
396 | { | 297 | { |
@@ -406,8 +307,8 @@ static __init unsigned int get_cpu_hz(void) | |||
406 | register unsigned long long __rtc_irq_flag __asm__ ("r3"); | 307 | register unsigned long long __rtc_irq_flag __asm__ ("r3"); |
407 | 308 | ||
408 | local_irq_enable(); | 309 | local_irq_enable(); |
409 | do {} while (ctrl_inb(R64CNT) != 0); | 310 | do {} while (ctrl_inb(rtc_base) != 0); |
410 | ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */ | 311 | ctrl_outb(RTC_RCR1_CIE, RTC_RCR1); /* Enable carry interrupt */ |
411 | 312 | ||
412 | /* | 313 | /* |
413 | * r3 is arbitrary. CDC does not support "=z". | 314 | * r3 is arbitrary. CDC does not support "=z". |
@@ -470,7 +371,7 @@ static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id) | |||
470 | { | 371 | { |
471 | struct pt_regs *regs = get_irq_regs(); | 372 | struct pt_regs *regs = get_irq_regs(); |
472 | 373 | ||
473 | ctrl_outb(0, RCR1); /* Disable Carry Interrupts */ | 374 | ctrl_outb(0, RTC_RCR1); /* Disable Carry Interrupts */ |
474 | regs->regs[3] = 1; /* Using r3 */ | 375 | regs->regs[3] = 1; /* Using r3 */ |
475 | 376 | ||
476 | return IRQ_HANDLED; | 377 | return IRQ_HANDLED; |
@@ -513,8 +414,7 @@ void __init time_init(void) | |||
513 | panic("Unable to remap CPRC\n"); | 414 | panic("Unable to remap CPRC\n"); |
514 | } | 415 | } |
515 | 416 | ||
516 | xtime.tv_sec = get_rtc_time(); | 417 | rtc_sh_get_time(&xtime); |
517 | xtime.tv_nsec = 0; | ||
518 | 418 | ||
519 | setup_irq(TIMER_IRQ, &irq0); | 419 | setup_irq(TIMER_IRQ, &irq0); |
520 | setup_irq(RTC_IRQ, &irq1); | 420 | setup_irq(RTC_IRQ, &irq1); |
@@ -525,7 +425,7 @@ void __init time_init(void) | |||
525 | /* Note careful order of operations to maintain reasonable precision and avoid overflow. */ | 425 | /* Note careful order of operations to maintain reasonable precision and avoid overflow. */ |
526 | scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ)); | 426 | scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ)); |
527 | 427 | ||
528 | disable_irq(RTC_IRQ); | 428 | free_irq(RTC_IRQ, NULL); |
529 | 429 | ||
530 | printk("CPU clock: %d.%02dMHz\n", | 430 | printk("CPU clock: %d.%02dMHz\n", |
531 | (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); | 431 | (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); |
@@ -591,3 +491,41 @@ void enter_deep_standby(void) | |||
591 | asm __volatile__ ("nop"); | 491 | asm __volatile__ ("nop"); |
592 | panic("Unexpected wakeup!\n"); | 492 | panic("Unexpected wakeup!\n"); |
593 | } | 493 | } |
494 | |||
495 | static struct resource rtc_resources[] = { | ||
496 | [0] = { | ||
497 | /* RTC base, filled in by rtc_init */ | ||
498 | .flags = IORESOURCE_IO, | ||
499 | }, | ||
500 | [1] = { | ||
501 | /* Period IRQ */ | ||
502 | .start = IRQ_PRI, | ||
503 | .flags = IORESOURCE_IRQ, | ||
504 | }, | ||
505 | [2] = { | ||
506 | /* Carry IRQ */ | ||
507 | .start = IRQ_CUI, | ||
508 | .flags = IORESOURCE_IRQ, | ||
509 | }, | ||
510 | [3] = { | ||
511 | /* Alarm IRQ */ | ||
512 | .start = IRQ_ATI, | ||
513 | .flags = IORESOURCE_IRQ, | ||
514 | }, | ||
515 | }; | ||
516 | |||
517 | static struct platform_device rtc_device = { | ||
518 | .name = "sh-rtc", | ||
519 | .id = -1, | ||
520 | .num_resources = ARRAY_SIZE(rtc_resources), | ||
521 | .resource = rtc_resources, | ||
522 | }; | ||
523 | |||
524 | static int __init rtc_init(void) | ||
525 | { | ||
526 | rtc_resources[0].start = rtc_base; | ||
527 | rtc_resources[0].end = rtc_resources[0].start + 0x58 - 1; | ||
528 | |||
529 | return platform_device_register(&rtc_device); | ||
530 | } | ||
531 | device_initcall(rtc_init); | ||