aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/time.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-28 11:54:49 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-28 11:54:49 -0400
commitd1a76187a5be4f89c6cb19d800cb5fb7aac735c5 (patch)
tree2fac3ffbfffc7560eeef8364b541d0d7a0057920 /arch/sparc/kernel/time.c
parentc7e78cff6b7518212247fb20b1dc6411540dc9af (diff)
parent0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff)
Merge commit 'v2.6.28-rc2' into core/locking
Conflicts: arch/um/include/asm/system.h
Diffstat (limited to 'arch/sparc/kernel/time.c')
-rw-r--r--arch/sparc/kernel/time.c382
1 files changed, 64 insertions, 318 deletions
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 0762f5db1924..62c1d94cb434 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -23,22 +23,24 @@
23#include <linux/mm.h> 23#include <linux/mm.h>
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/time.h> 25#include <linux/time.h>
26#include <linux/rtc.h>
27#include <linux/rtc/m48t59.h>
26#include <linux/timex.h> 28#include <linux/timex.h>
27#include <linux/init.h> 29#include <linux/init.h>
28#include <linux/pci.h> 30#include <linux/pci.h>
29#include <linux/ioport.h> 31#include <linux/ioport.h>
30#include <linux/profile.h> 32#include <linux/profile.h>
33#include <linux/of.h>
31#include <linux/of_device.h> 34#include <linux/of_device.h>
35#include <linux/platform_device.h>
32 36
33#include <asm/oplib.h> 37#include <asm/oplib.h>
34#include <asm/timer.h> 38#include <asm/timer.h>
35#include <asm/mostek.h>
36#include <asm/system.h> 39#include <asm/system.h>
37#include <asm/irq.h> 40#include <asm/irq.h>
38#include <asm/io.h> 41#include <asm/io.h>
39#include <asm/idprom.h> 42#include <asm/idprom.h>
40#include <asm/machines.h> 43#include <asm/machines.h>
41#include <asm/sun4paddr.h>
42#include <asm/page.h> 44#include <asm/page.h>
43#include <asm/pcic.h> 45#include <asm/pcic.h>
44#include <asm/irq_regs.h> 46#include <asm/irq_regs.h>
@@ -46,34 +48,9 @@
46#include "irq.h" 48#include "irq.h"
47 49
48DEFINE_SPINLOCK(rtc_lock); 50DEFINE_SPINLOCK(rtc_lock);
49static enum sparc_clock_type sp_clock_typ;
50DEFINE_SPINLOCK(mostek_lock);
51void __iomem *mstk48t02_regs = NULL;
52static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
53static int set_rtc_mmss(unsigned long); 51static int set_rtc_mmss(unsigned long);
54static int sbus_do_settimeofday(struct timespec *tv); 52static int sbus_do_settimeofday(struct timespec *tv);
55 53
56#ifdef CONFIG_SUN4
57struct intersil *intersil_clock;
58#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
59 (intsil_cmd)
60
61#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
62 (intsil_cmd)
63
64#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
65 ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
66 INTERSIL_INTR_ENABLE))
67
68#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
69 ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
70 INTERSIL_INTR_ENABLE))
71
72#define intersil_read_intr(intersil_reg, towhere) towhere = \
73 intersil_reg->int_intr_reg
74
75#endif
76
77unsigned long profile_pc(struct pt_regs *regs) 54unsigned long profile_pc(struct pt_regs *regs)
78{ 55{
79 extern char __copy_user_begin[], __copy_user_end[]; 56 extern char __copy_user_begin[], __copy_user_end[];
@@ -96,7 +73,6 @@ unsigned long profile_pc(struct pt_regs *regs)
96EXPORT_SYMBOL(profile_pc); 73EXPORT_SYMBOL(profile_pc);
97 74
98__volatile__ unsigned int *master_l10_counter; 75__volatile__ unsigned int *master_l10_counter;
99__volatile__ unsigned int *master_l10_limit;
100 76
101/* 77/*
102 * timer_interrupt() needs to keep up the real-time clock, 78 * timer_interrupt() needs to keep up the real-time clock,
@@ -116,15 +92,7 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
116 92
117 /* Protect counter clear so that do_gettimeoffset works */ 93 /* Protect counter clear so that do_gettimeoffset works */
118 write_seqlock(&xtime_lock); 94 write_seqlock(&xtime_lock);
119#ifdef CONFIG_SUN4 95
120 if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
121 (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
122 int temp;
123 intersil_read_intr(intersil_clock, temp);
124 /* re-enable the irq */
125 enable_pil_irq(10);
126 }
127#endif
128 clear_clock_irq(); 96 clear_clock_irq();
129 97
130 do_timer(1); 98 do_timer(1);
@@ -147,157 +115,56 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
147 return IRQ_HANDLED; 115 return IRQ_HANDLED;
148} 116}
149 117
150/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ 118static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
151static void __devinit kick_start_clock(void)
152{ 119{
153 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; 120 struct platform_device *pdev = to_platform_device(dev);
154 unsigned char sec; 121 struct m48t59_plat_data *pdata = pdev->dev.platform_data;
155 int i, count; 122 void __iomem *regs = pdata->ioaddr;
156 123 unsigned char val = readb(regs + ofs);
157 prom_printf("CLOCK: Clock was stopped. Kick start "); 124
158 125 /* the year 0 is 1968 */
159 spin_lock_irq(&mostek_lock); 126 if (ofs == pdata->offset + M48T59_YEAR) {
160 127 val += 0x68;
161 /* Turn on the kick start bit to start the oscillator. */ 128 if ((val & 0xf) > 9)
162 regs->creg |= MSTK_CREG_WRITE; 129 val += 6;
163 regs->sec &= ~MSTK_STOP;
164 regs->hour |= MSTK_KICK_START;
165 regs->creg &= ~MSTK_CREG_WRITE;
166
167 spin_unlock_irq(&mostek_lock);
168
169 /* Delay to allow the clock oscillator to start. */
170 sec = MSTK_REG_SEC(regs);
171 for (i = 0; i < 3; i++) {
172 while (sec == MSTK_REG_SEC(regs))
173 for (count = 0; count < 100000; count++)
174 /* nothing */ ;
175 prom_printf(".");
176 sec = regs->sec;
177 }
178 prom_printf("\n");
179
180 spin_lock_irq(&mostek_lock);
181
182 /* Turn off kick start and set a "valid" time and date. */
183 regs->creg |= MSTK_CREG_WRITE;
184 regs->hour &= ~MSTK_KICK_START;
185 MSTK_SET_REG_SEC(regs,0);
186 MSTK_SET_REG_MIN(regs,0);
187 MSTK_SET_REG_HOUR(regs,0);
188 MSTK_SET_REG_DOW(regs,5);
189 MSTK_SET_REG_DOM(regs,1);
190 MSTK_SET_REG_MONTH(regs,8);
191 MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
192 regs->creg &= ~MSTK_CREG_WRITE;
193
194 spin_unlock_irq(&mostek_lock);
195
196 /* Ensure the kick start bit is off. If it isn't, turn it off. */
197 while (regs->hour & MSTK_KICK_START) {
198 prom_printf("CLOCK: Kick start still on!\n");
199
200 spin_lock_irq(&mostek_lock);
201 regs->creg |= MSTK_CREG_WRITE;
202 regs->hour &= ~MSTK_KICK_START;
203 regs->creg &= ~MSTK_CREG_WRITE;
204 spin_unlock_irq(&mostek_lock);
205 } 130 }
206 131 return val;
207 prom_printf("CLOCK: Kick start procedure successful.\n");
208}
209
210/* Return nonzero if the clock chip battery is low. */
211static inline int has_low_battery(void)
212{
213 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
214 unsigned char data1, data2;
215
216 spin_lock_irq(&mostek_lock);
217 data1 = regs->eeprom[0]; /* Read some data. */
218 regs->eeprom[0] = ~data1; /* Write back the complement. */
219 data2 = regs->eeprom[0]; /* Read back the complement. */
220 regs->eeprom[0] = data1; /* Restore the original value. */
221 spin_unlock_irq(&mostek_lock);
222
223 return (data1 == data2); /* Was the write blocked? */
224} 132}
225 133
226static void __devinit mostek_set_system_time(void) 134static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
227{ 135{
228 unsigned int year, mon, day, hour, min, sec; 136 struct platform_device *pdev = to_platform_device(dev);
229 struct mostek48t02 *mregs; 137 struct m48t59_plat_data *pdata = pdev->dev.platform_data;
230 138 void __iomem *regs = pdata->ioaddr;
231 mregs = (struct mostek48t02 *)mstk48t02_regs; 139
232 if(!mregs) { 140 if (ofs == pdata->offset + M48T59_YEAR) {
233 prom_printf("Something wrong, clock regs not mapped yet.\n"); 141 if (val < 0x68)
234 prom_halt(); 142 val += 0x32;
235 } 143 else
236 spin_lock_irq(&mostek_lock); 144 val -= 0x68;
237 mregs->creg |= MSTK_CREG_READ; 145 if ((val & 0xf) > 9)
238 sec = MSTK_REG_SEC(mregs); 146 val += 6;
239 min = MSTK_REG_MIN(mregs); 147 if ((val & 0xf0) > 0x9A)
240 hour = MSTK_REG_HOUR(mregs); 148 val += 0x60;
241 day = MSTK_REG_DOM(mregs); 149 }
242 mon = MSTK_REG_MONTH(mregs); 150 writeb(val, regs + ofs);
243 year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
244 xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
245 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
246 set_normalized_timespec(&wall_to_monotonic,
247 -xtime.tv_sec, -xtime.tv_nsec);
248 mregs->creg &= ~MSTK_CREG_READ;
249 spin_unlock_irq(&mostek_lock);
250} 151}
251 152
252/* Probe for the real time clock chip on Sun4 */ 153static struct m48t59_plat_data m48t59_data = {
253static inline void sun4_clock_probe(void) 154 .read_byte = mostek_read_byte,
254{ 155 .write_byte = mostek_write_byte,
255#ifdef CONFIG_SUN4 156};
256 int temp;
257 struct resource r;
258
259 memset(&r, 0, sizeof(r));
260 if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
261 sp_clock_typ = MSTK48T02;
262 r.start = sun4_clock_physaddr;
263 mstk48t02_regs = sbus_ioremap(&r, 0,
264 sizeof(struct mostek48t02), NULL);
265 mstk48t08_regs = NULL; /* To catch weirdness */
266 intersil_clock = NULL; /* just in case */
267
268 /* Kick start the clock if it is completely stopped. */
269 if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
270 kick_start_clock();
271 } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
272 /* intersil setup code */
273 printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
274 sp_clock_typ = INTERSIL;
275 r.start = sun4_clock_physaddr;
276 intersil_clock = (struct intersil *)
277 sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
278 mstk48t02_regs = 0; /* just be sure */
279 mstk48t08_regs = NULL; /* ditto */
280 /* initialise the clock */
281
282 intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
283
284 intersil_start(intersil_clock);
285
286 intersil_read_intr(intersil_clock, temp);
287 while (!(temp & 0x80))
288 intersil_read_intr(intersil_clock, temp);
289
290 intersil_read_intr(intersil_clock, temp);
291 while (!(temp & 0x80))
292 intersil_read_intr(intersil_clock, temp);
293
294 intersil_stop(intersil_clock);
295 157
296 } 158/* resource is set at runtime */
297#endif 159static struct platform_device m48t59_rtc = {
298} 160 .name = "rtc-m48t59",
161 .id = 0,
162 .num_resources = 1,
163 .dev = {
164 .platform_data = &m48t59_data,
165 },
166};
299 167
300#ifndef CONFIG_SUN4
301static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) 168static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
302{ 169{
303 struct device_node *dp = op->node; 170 struct device_node *dp = op->node;
@@ -306,38 +173,26 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
306 if (!model) 173 if (!model)
307 return -ENODEV; 174 return -ENODEV;
308 175
176 m48t59_rtc.resource = &op->resource[0];
309 if (!strcmp(model, "mk48t02")) { 177 if (!strcmp(model, "mk48t02")) {
310 sp_clock_typ = MSTK48T02;
311
312 /* Map the clock register io area read-only */ 178 /* Map the clock register io area read-only */
313 mstk48t02_regs = of_ioremap(&op->resource[0], 0, 179 m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
314 sizeof(struct mostek48t02), 180 2048, "rtc-m48t59");
315 "mk48t02"); 181 m48t59_data.type = M48T59RTC_TYPE_M48T02;
316 mstk48t08_regs = NULL; /* To catch weirdness */
317 } else if (!strcmp(model, "mk48t08")) { 182 } else if (!strcmp(model, "mk48t08")) {
318 sp_clock_typ = MSTK48T08; 183 m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
319 mstk48t08_regs = of_ioremap(&op->resource[0], 0, 184 8192, "rtc-m48t59");
320 sizeof(struct mostek48t08), 185 m48t59_data.type = M48T59RTC_TYPE_M48T08;
321 "mk48t08");
322
323 mstk48t02_regs = &mstk48t08_regs->regs;
324 } else 186 } else
325 return -ENODEV; 187 return -ENODEV;
326 188
327 /* Report a low battery voltage condition. */ 189 if (platform_device_register(&m48t59_rtc) < 0)
328 if (has_low_battery()) 190 printk(KERN_ERR "Registering RTC device failed\n");
329 printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
330
331 /* Kick start the clock if it is completely stopped. */
332 if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
333 kick_start_clock();
334
335 mostek_set_system_time();
336 191
337 return 0; 192 return 0;
338} 193}
339 194
340static struct of_device_id clock_match[] = { 195static struct of_device_id __initdata clock_match[] = {
341 { 196 {
342 .name = "eeprom", 197 .name = "eeprom",
343 }, 198 },
@@ -348,7 +203,7 @@ static struct of_platform_driver clock_driver = {
348 .match_table = clock_match, 203 .match_table = clock_match,
349 .probe = clock_probe, 204 .probe = clock_probe,
350 .driver = { 205 .driver = {
351 .name = "clock", 206 .name = "rtc",
352 }, 207 },
353}; 208};
354 209
@@ -364,7 +219,6 @@ static int __init clock_init(void)
364 * need to see the clock registers. 219 * need to see the clock registers.
365 */ 220 */
366fs_initcall(clock_init); 221fs_initcall(clock_init);
367#endif /* !CONFIG_SUN4 */
368 222
369static void __init sbus_time_init(void) 223static void __init sbus_time_init(void)
370{ 224{
@@ -372,51 +226,8 @@ static void __init sbus_time_init(void)
372 BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); 226 BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
373 btfixup(); 227 btfixup();
374 228
375 if (ARCH_SUN4)
376 sun4_clock_probe();
377
378 sparc_init_timers(timer_interrupt); 229 sparc_init_timers(timer_interrupt);
379 230
380#ifdef CONFIG_SUN4
381 if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
382 mostek_set_system_time();
383 } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
384 /* initialise the intersil on sun4 */
385 unsigned int year, mon, day, hour, min, sec;
386 int temp;
387 struct intersil *iregs;
388
389 iregs=intersil_clock;
390 if(!iregs) {
391 prom_printf("Something wrong, clock regs not mapped yet.\n");
392 prom_halt();
393 }
394
395 intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
396 disable_pil_irq(10);
397 intersil_stop(iregs);
398 intersil_read_intr(intersil_clock, temp);
399
400 temp = iregs->clk.int_csec;
401
402 sec = iregs->clk.int_sec;
403 min = iregs->clk.int_min;
404 hour = iregs->clk.int_hour;
405 day = iregs->clk.int_day;
406 mon = iregs->clk.int_month;
407 year = MSTK_CVT_YEAR(iregs->clk.int_year);
408
409 enable_pil_irq(10);
410 intersil_start(iregs);
411
412 xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
413 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
414 set_normalized_timespec(&wall_to_monotonic,
415 -xtime.tv_sec, -xtime.tv_nsec);
416 printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
417 }
418#endif
419
420 /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */ 231 /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
421 local_irq_enable(); 232 local_irq_enable();
422} 233}
@@ -522,80 +333,15 @@ static int sbus_do_settimeofday(struct timespec *tv)
522 return 0; 333 return 0;
523} 334}
524 335
525/* 336static int set_rtc_mmss(unsigned long secs)
526 * BUG: This routine does not handle hour overflow properly; it just
527 * sets the minutes. Usually you won't notice until after reboot!
528 */
529static int set_rtc_mmss(unsigned long nowtime)
530{ 337{
531 int real_seconds, real_minutes, mostek_minutes; 338 struct rtc_device *rtc = rtc_class_open("rtc0");
532 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; 339 int err = -1;
533 unsigned long flags;
534#ifdef CONFIG_SUN4
535 struct intersil *iregs = intersil_clock;
536 int temp;
537#endif
538 340
539 /* Not having a register set can lead to trouble. */ 341 if (rtc) {
540 if (!regs) { 342 err = rtc_set_mmss(rtc, secs);
541#ifdef CONFIG_SUN4 343 rtc_class_close(rtc);
542 if(!iregs)
543 return -1;
544 else {
545 temp = iregs->clk.int_csec;
546
547 mostek_minutes = iregs->clk.int_min;
548
549 real_seconds = nowtime % 60;
550 real_minutes = nowtime / 60;
551 if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
552 real_minutes += 30; /* correct for half hour time zone */
553 real_minutes %= 60;
554
555 if (abs(real_minutes - mostek_minutes) < 30) {
556 intersil_stop(iregs);
557 iregs->clk.int_sec=real_seconds;
558 iregs->clk.int_min=real_minutes;
559 intersil_start(iregs);
560 } else {
561 printk(KERN_WARNING
562 "set_rtc_mmss: can't update from %d to %d\n",
563 mostek_minutes, real_minutes);
564 return -1;
565 }
566
567 return 0;
568 }
569#endif
570 } 344 }
571 345
572 spin_lock_irqsave(&mostek_lock, flags); 346 return err;
573 /* Read the current RTC minutes. */
574 regs->creg |= MSTK_CREG_READ;
575 mostek_minutes = MSTK_REG_MIN(regs);
576 regs->creg &= ~MSTK_CREG_READ;
577
578 /*
579 * since we're only adjusting minutes and seconds,
580 * don't interfere with hour overflow. This avoids
581 * messing with unknown time zones but requires your
582 * RTC not to be off by more than 15 minutes
583 */
584 real_seconds = nowtime % 60;
585 real_minutes = nowtime / 60;
586 if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
587 real_minutes += 30; /* correct for half hour time zone */
588 real_minutes %= 60;
589
590 if (abs(real_minutes - mostek_minutes) < 30) {
591 regs->creg |= MSTK_CREG_WRITE;
592 MSTK_SET_REG_SEC(regs,real_seconds);
593 MSTK_SET_REG_MIN(regs,real_minutes);
594 regs->creg &= ~MSTK_CREG_WRITE;
595 spin_unlock_irqrestore(&mostek_lock, flags);
596 return 0;
597 } else {
598 spin_unlock_irqrestore(&mostek_lock, flags);
599 return -1;
600 }
601} 347}