ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc64 / kernel / pmac_time.c
1 /*
2  * Support for periodic interrupts (100 per second) and for getting
3  * the current time from the RTC on Power Macintoshes.
4  *
5  * We use the decrementer register for our periodic interrupts.
6  *
7  * Paul Mackerras       August 1996.
8  * Copyright (C) 1996 Paul Mackerras.
9  */
10 #include <linux/config.h>
11 #include <linux/errno.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/param.h>
15 #include <linux/string.h>
16 #include <linux/mm.h>
17 #include <linux/init.h>
18 #include <linux/time.h>
19 #include <linux/adb.h>
20 #include <linux/pmu.h>
21
22 #include <asm/sections.h>
23 #include <asm/prom.h>
24 #include <asm/system.h>
25 #include <asm/io.h>
26 #include <asm/pgtable.h>
27 #include <asm/machdep.h>
28 #include <asm/hardirq.h>
29 #include <asm/time.h>
30 #include <asm/nvram.h>
31
32 #undef DEBUG
33
34 #ifdef DEBUG
35 #define DBG(x...) printk(x)
36 #else
37 #define DBG(x...)
38 #endif
39
40 extern void setup_default_decr(void);
41
42 extern unsigned long ppc_tb_freq;
43 extern unsigned long ppc_proc_freq;
44
45 /* Apparently the RTC stores seconds since 1 Jan 1904 */
46 #define RTC_OFFSET      2082844800
47
48 /*
49  * Calibrate the decrementer frequency with the VIA timer 1.
50  */
51 #define VIA_TIMER_FREQ_6        4700000 /* time 1 frequency * 6 */
52
53 extern struct timezone sys_tz;
54 extern void to_tm(int tim, struct rtc_time * tm);
55
56 void __pmac pmac_get_rtc_time(struct rtc_time *tm)
57 {
58         struct adb_request req;
59         unsigned int now;
60
61         /* Get the time from the RTC */
62         if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
63                 return;
64         while (!req.complete)
65                 pmu_poll();
66         if (req.reply_len != 4)
67                 printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
68                        req.reply_len);
69         now = (req.reply[0] << 24) + (req.reply[1] << 16)
70                 + (req.reply[2] << 8) + req.reply[3];
71         DBG("get: %u -> %u\n", (int)now, (int)(now - RTC_OFFSET));
72         now -= RTC_OFFSET;
73
74         to_tm(now, tm);
75         tm->tm_year -= 1900;
76         tm->tm_mon -= 1;
77         
78         DBG("-> tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n",
79                tm->tm_mday, tm->tm_mon, tm->tm_year,
80                tm->tm_hour, tm->tm_min, tm->tm_sec);
81 }
82
83 int __pmac pmac_set_rtc_time(struct rtc_time *tm)
84 {
85         struct adb_request req;
86         unsigned int nowtime;
87
88         DBG("set: tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n",
89                tm->tm_mday, tm->tm_mon, tm->tm_year,
90                tm->tm_hour, tm->tm_min, tm->tm_sec);
91
92         nowtime = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
93                          tm->tm_hour, tm->tm_min, tm->tm_sec);
94         DBG("-> %u -> %u\n", (int)nowtime, (int)(nowtime + RTC_OFFSET));
95         nowtime += RTC_OFFSET;
96
97         if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
98                         nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
99                 return 0;
100         while (!req.complete)
101                 pmu_poll();
102         if (req.reply_len != 0)
103                 printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
104                        req.reply_len);
105         return 1;
106 }
107
108 void __init pmac_get_boot_time(struct rtc_time *tm)
109 {
110         pmac_get_rtc_time(tm);
111
112 #ifdef disabled__CONFIG_NVRAM
113         s32 delta = 0;
114         int dst;
115         
116         delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
117         delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
118         delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
119         if (delta & 0x00800000UL)
120                 delta |= 0xFF000000UL;
121         dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
122         printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
123                 dst ? "on" : "off");
124 #endif
125 }
126
127 /*
128  * Query the OF and get the decr frequency.
129  * This was taken from the pmac time_init() when merging the prep/pmac
130  * time functions.
131  */
132 void __init pmac_calibrate_decr(void)
133 {
134         struct device_node *cpu;
135         unsigned int freq, *fp;
136         struct div_result divres;
137
138         /*
139          * The cpu node should have a timebase-frequency property
140          * to tell us the rate at which the decrementer counts.
141          */
142         cpu = find_type_devices("cpu");
143         if (cpu == 0)
144                 panic("can't find cpu node in time_init");
145         fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
146         if (fp == 0)
147                 panic("can't get cpu timebase frequency");
148         freq = *fp;
149         printk("time_init: decrementer frequency = %u.%.6u MHz\n",
150                freq/1000000, freq%1000000);
151         tb_ticks_per_jiffy = freq / HZ;
152         tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
153         tb_ticks_per_usec = freq / 1000000;
154         tb_to_us = mulhwu_scale_factor(freq, 1000000);
155         div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
156         tb_to_xs = divres.result_low;
157         ppc_tb_freq = freq;
158
159         fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL);
160         if (fp == 0)
161                 panic("can't get cpu processor frequency");
162         ppc_proc_freq = *fp;
163
164         setup_default_decr();
165 }
166