1f6d57916SPaul Mackerras /*
2f6d57916SPaul Mackerras  * Support for periodic interrupts (100 per second) and for getting
3f6d57916SPaul Mackerras  * the current time from the RTC on Power Macintoshes.
4f6d57916SPaul Mackerras  *
5f6d57916SPaul Mackerras  * We use the decrementer register for our periodic interrupts.
6f6d57916SPaul Mackerras  *
7f6d57916SPaul Mackerras  * Paul Mackerras	August 1996.
8f6d57916SPaul Mackerras  * Copyright (C) 1996 Paul Mackerras.
9f6d57916SPaul Mackerras  */
10f6d57916SPaul Mackerras #include <linux/config.h>
11f6d57916SPaul Mackerras #include <linux/errno.h>
12f6d57916SPaul Mackerras #include <linux/sched.h>
13f6d57916SPaul Mackerras #include <linux/kernel.h>
14f6d57916SPaul Mackerras #include <linux/param.h>
15f6d57916SPaul Mackerras #include <linux/string.h>
16f6d57916SPaul Mackerras #include <linux/mm.h>
17f6d57916SPaul Mackerras #include <linux/init.h>
18f6d57916SPaul Mackerras #include <linux/time.h>
19f6d57916SPaul Mackerras #include <linux/adb.h>
20f6d57916SPaul Mackerras #include <linux/cuda.h>
21f6d57916SPaul Mackerras #include <linux/pmu.h>
22f6d57916SPaul Mackerras #include <linux/hardirq.h>
23f6d57916SPaul Mackerras 
24f6d57916SPaul Mackerras #include <asm/sections.h>
25f6d57916SPaul Mackerras #include <asm/prom.h>
26f6d57916SPaul Mackerras #include <asm/system.h>
27f6d57916SPaul Mackerras #include <asm/io.h>
28f6d57916SPaul Mackerras #include <asm/pgtable.h>
29f6d57916SPaul Mackerras #include <asm/machdep.h>
30f6d57916SPaul Mackerras #include <asm/time.h>
31f6d57916SPaul Mackerras #include <asm/nvram.h>
32f6d57916SPaul Mackerras 
33f6d57916SPaul Mackerras /* Apparently the RTC stores seconds since 1 Jan 1904 */
34f6d57916SPaul Mackerras #define RTC_OFFSET	2082844800
35f6d57916SPaul Mackerras 
36f6d57916SPaul Mackerras /*
37f6d57916SPaul Mackerras  * Calibrate the decrementer frequency with the VIA timer 1.
38f6d57916SPaul Mackerras  */
39f6d57916SPaul Mackerras #define VIA_TIMER_FREQ_6	4700000	/* time 1 frequency * 6 */
40f6d57916SPaul Mackerras 
41f6d57916SPaul Mackerras /* VIA registers */
42f6d57916SPaul Mackerras #define RS		0x200		/* skip between registers */
43f6d57916SPaul Mackerras #define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
44f6d57916SPaul Mackerras #define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
45f6d57916SPaul Mackerras #define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
46f6d57916SPaul Mackerras #define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
47f6d57916SPaul Mackerras #define ACR		(11*RS)		/* Auxiliary control register */
48f6d57916SPaul Mackerras #define IFR		(13*RS)		/* Interrupt flag register */
49f6d57916SPaul Mackerras 
50f6d57916SPaul Mackerras /* Bits in ACR */
51f6d57916SPaul Mackerras #define T1MODE		0xc0		/* Timer 1 mode */
52f6d57916SPaul Mackerras #define T1MODE_CONT	0x40		/*  continuous interrupts */
53f6d57916SPaul Mackerras 
54f6d57916SPaul Mackerras /* Bits in IFR and IER */
55f6d57916SPaul Mackerras #define T1_INT		0x40		/* Timer 1 interrupt */
56f6d57916SPaul Mackerras 
57f6d57916SPaul Mackerras extern struct timezone sys_tz;
58f6d57916SPaul Mackerras 
59f6d57916SPaul Mackerras long __init
60f6d57916SPaul Mackerras pmac_time_init(void)
61f6d57916SPaul Mackerras {
62f6d57916SPaul Mackerras #ifdef CONFIG_NVRAM
63f6d57916SPaul Mackerras 	s32 delta = 0;
64f6d57916SPaul Mackerras 	int dst;
65f6d57916SPaul Mackerras 
66f6d57916SPaul Mackerras 	delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
67f6d57916SPaul Mackerras 	delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
68f6d57916SPaul Mackerras 	delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
69f6d57916SPaul Mackerras 	if (delta & 0x00800000UL)
70f6d57916SPaul Mackerras 		delta |= 0xFF000000UL;
71f6d57916SPaul Mackerras 	dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
72f6d57916SPaul Mackerras 	printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
73f6d57916SPaul Mackerras 		dst ? "on" : "off");
74f6d57916SPaul Mackerras 	return delta;
75f6d57916SPaul Mackerras #else
76f6d57916SPaul Mackerras 	return 0;
77f6d57916SPaul Mackerras #endif
78f6d57916SPaul Mackerras }
79f6d57916SPaul Mackerras 
80143a1decSPaul Mackerras unsigned long pmac_get_boot_time(void)
81f6d57916SPaul Mackerras {
82f6d57916SPaul Mackerras #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
83f6d57916SPaul Mackerras 	struct adb_request req;
84f6d57916SPaul Mackerras 	unsigned long now;
85f6d57916SPaul Mackerras #endif
86f6d57916SPaul Mackerras 
87f6d57916SPaul Mackerras 	/* Get the time from the RTC */
88f6d57916SPaul Mackerras 	switch (sys_ctrler) {
89f6d57916SPaul Mackerras #ifdef CONFIG_ADB_CUDA
90f6d57916SPaul Mackerras 	case SYS_CTRLER_CUDA:
91f6d57916SPaul Mackerras 		if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
92f6d57916SPaul Mackerras 			return 0;
93f6d57916SPaul Mackerras 		while (!req.complete)
94f6d57916SPaul Mackerras 			cuda_poll();
95f6d57916SPaul Mackerras 		if (req.reply_len != 7)
96f6d57916SPaul Mackerras 			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
97f6d57916SPaul Mackerras 			       req.reply_len);
98f6d57916SPaul Mackerras 		now = (req.reply[3] << 24) + (req.reply[4] << 16)
99f6d57916SPaul Mackerras 			+ (req.reply[5] << 8) + req.reply[6];
100f6d57916SPaul Mackerras 		return now - RTC_OFFSET;
101f6d57916SPaul Mackerras #endif /* CONFIG_ADB_CUDA */
102f6d57916SPaul Mackerras #ifdef CONFIG_ADB_PMU
103f6d57916SPaul Mackerras 	case SYS_CTRLER_PMU:
104f6d57916SPaul Mackerras 		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
105f6d57916SPaul Mackerras 			return 0;
106f6d57916SPaul Mackerras 		while (!req.complete)
107f6d57916SPaul Mackerras 			pmu_poll();
108f6d57916SPaul Mackerras 		if (req.reply_len != 4)
109f6d57916SPaul Mackerras 			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
110f6d57916SPaul Mackerras 			       req.reply_len);
111f6d57916SPaul Mackerras 		now = (req.reply[0] << 24) + (req.reply[1] << 16)
112f6d57916SPaul Mackerras 			+ (req.reply[2] << 8) + req.reply[3];
113f6d57916SPaul Mackerras 		return now - RTC_OFFSET;
114f6d57916SPaul Mackerras #endif /* CONFIG_ADB_PMU */
115f6d57916SPaul Mackerras 	default: ;
116f6d57916SPaul Mackerras 	}
117f6d57916SPaul Mackerras 	return 0;
118f6d57916SPaul Mackerras }
119f6d57916SPaul Mackerras 
120143a1decSPaul Mackerras void pmac_get_rtc_time(struct rtc_time *tm)
121f6d57916SPaul Mackerras {
122143a1decSPaul Mackerras 	unsigned long now;
123143a1decSPaul Mackerras 
124143a1decSPaul Mackerras 	now = pmac_get_boot_time();
125143a1decSPaul Mackerras 	to_tm(now, tm);
126143a1decSPaul Mackerras 	tm->tm_year -= 1900;
127143a1decSPaul Mackerras 	tm->tm_mon -= 1;		/* month is 0-based */
128143a1decSPaul Mackerras }
129143a1decSPaul Mackerras 
130143a1decSPaul Mackerras int pmac_set_rtc_time(struct rtc_time *tm)
131143a1decSPaul Mackerras {
132143a1decSPaul Mackerras 	unsigned long nowtime;
133f6d57916SPaul Mackerras #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
134f6d57916SPaul Mackerras 	struct adb_request req;
135f6d57916SPaul Mackerras #endif
136f6d57916SPaul Mackerras 
137143a1decSPaul Mackerras 	nowtime = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
138143a1decSPaul Mackerras 			 tm->tm_hour, tm->tm_min, tm->tm_sec);
139f6d57916SPaul Mackerras 	nowtime += RTC_OFFSET;
140f6d57916SPaul Mackerras 
141f6d57916SPaul Mackerras 	switch (sys_ctrler) {
142f6d57916SPaul Mackerras #ifdef CONFIG_ADB_CUDA
143f6d57916SPaul Mackerras 	case SYS_CTRLER_CUDA:
144f6d57916SPaul Mackerras 		if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
145143a1decSPaul Mackerras 				 nowtime >> 24, nowtime >> 16, nowtime >> 8,
146143a1decSPaul Mackerras 				 nowtime) < 0)
147f6d57916SPaul Mackerras 			return 0;
148f6d57916SPaul Mackerras 		while (!req.complete)
149f6d57916SPaul Mackerras 			cuda_poll();
150f6d57916SPaul Mackerras 		if ((req.reply_len != 3) && (req.reply_len != 7))
151f6d57916SPaul Mackerras 			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
152f6d57916SPaul Mackerras 			       req.reply_len);
153f6d57916SPaul Mackerras 		return 1;
154f6d57916SPaul Mackerras #endif /* CONFIG_ADB_CUDA */
155f6d57916SPaul Mackerras #ifdef CONFIG_ADB_PMU
156f6d57916SPaul Mackerras 	case SYS_CTRLER_PMU:
157f6d57916SPaul Mackerras 		if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
158f6d57916SPaul Mackerras 				nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
159f6d57916SPaul Mackerras 			return 0;
160f6d57916SPaul Mackerras 		while (!req.complete)
161f6d57916SPaul Mackerras 			pmu_poll();
162f6d57916SPaul Mackerras 		if (req.reply_len != 0)
163f6d57916SPaul Mackerras 			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
164f6d57916SPaul Mackerras 			       req.reply_len);
165f6d57916SPaul Mackerras 		return 1;
166f6d57916SPaul Mackerras #endif /* CONFIG_ADB_PMU */
167f6d57916SPaul Mackerras 	default:
168f6d57916SPaul Mackerras 		return 0;
169f6d57916SPaul Mackerras 	}
170f6d57916SPaul Mackerras }
171f6d57916SPaul Mackerras 
172f6d57916SPaul Mackerras /*
173f6d57916SPaul Mackerras  * Calibrate the decrementer register using VIA timer 1.
174f6d57916SPaul Mackerras  * This is used both on powermacs and CHRP machines.
175f6d57916SPaul Mackerras  */
176f6d57916SPaul Mackerras int __init
177f6d57916SPaul Mackerras via_calibrate_decr(void)
178f6d57916SPaul Mackerras {
179f6d57916SPaul Mackerras 	struct device_node *vias;
180f6d57916SPaul Mackerras 	volatile unsigned char __iomem *via;
181f6d57916SPaul Mackerras 	int count = VIA_TIMER_FREQ_6 / 100;
182f6d57916SPaul Mackerras 	unsigned int dstart, dend;
183f6d57916SPaul Mackerras 
184f6d57916SPaul Mackerras 	vias = find_devices("via-cuda");
185f6d57916SPaul Mackerras 	if (vias == 0)
186f6d57916SPaul Mackerras 		vias = find_devices("via-pmu");
187f6d57916SPaul Mackerras 	if (vias == 0)
188f6d57916SPaul Mackerras 		vias = find_devices("via");
189f6d57916SPaul Mackerras 	if (vias == 0 || vias->n_addrs == 0)
190f6d57916SPaul Mackerras 		return 0;
191f6d57916SPaul Mackerras 	via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
192f6d57916SPaul Mackerras 
193f6d57916SPaul Mackerras 	/* set timer 1 for continuous interrupts */
194f6d57916SPaul Mackerras 	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
195f6d57916SPaul Mackerras 	/* set the counter to a small value */
196f6d57916SPaul Mackerras 	out_8(&via[T1CH], 2);
197f6d57916SPaul Mackerras 	/* set the latch to `count' */
198f6d57916SPaul Mackerras 	out_8(&via[T1LL], count);
199f6d57916SPaul Mackerras 	out_8(&via[T1LH], count >> 8);
200f6d57916SPaul Mackerras 	/* wait until it hits 0 */
201f6d57916SPaul Mackerras 	while ((in_8(&via[IFR]) & T1_INT) == 0)
202f6d57916SPaul Mackerras 		;
203f6d57916SPaul Mackerras 	dstart = get_dec();
204f6d57916SPaul Mackerras 	/* clear the interrupt & wait until it hits 0 again */
205f6d57916SPaul Mackerras 	in_8(&via[T1CL]);
206f6d57916SPaul Mackerras 	while ((in_8(&via[IFR]) & T1_INT) == 0)
207f6d57916SPaul Mackerras 		;
208f6d57916SPaul Mackerras 	dend = get_dec();
209f6d57916SPaul Mackerras 
2105629d41dSPaul Mackerras 	tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100);
211f6d57916SPaul Mackerras 	tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
212f6d57916SPaul Mackerras 
213f6d57916SPaul Mackerras 	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
214f6d57916SPaul Mackerras 	       tb_ticks_per_jiffy, dstart - dend);
215f6d57916SPaul Mackerras 
216f6d57916SPaul Mackerras 	iounmap(via);
217f6d57916SPaul Mackerras 
218f6d57916SPaul Mackerras 	return 1;
219f6d57916SPaul Mackerras }
220f6d57916SPaul Mackerras 
221f6d57916SPaul Mackerras #ifdef CONFIG_PM
222f6d57916SPaul Mackerras /*
223f6d57916SPaul Mackerras  * Reset the time after a sleep.
224f6d57916SPaul Mackerras  */
225f6d57916SPaul Mackerras static int
226f6d57916SPaul Mackerras time_sleep_notify(struct pmu_sleep_notifier *self, int when)
227f6d57916SPaul Mackerras {
228f6d57916SPaul Mackerras 	static unsigned long time_diff;
229f6d57916SPaul Mackerras 	unsigned long flags;
230f6d57916SPaul Mackerras 	unsigned long seq;
231f6d57916SPaul Mackerras 
232f6d57916SPaul Mackerras 	switch (when) {
233f6d57916SPaul Mackerras 	case PBOOK_SLEEP_NOW:
234f6d57916SPaul Mackerras 		do {
235f6d57916SPaul Mackerras 			seq = read_seqbegin_irqsave(&xtime_lock, flags);
236143a1decSPaul Mackerras 			time_diff = xtime.tv_sec - pmac_get_boot_time();
237f6d57916SPaul Mackerras 		} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
238f6d57916SPaul Mackerras 		break;
239f6d57916SPaul Mackerras 	case PBOOK_WAKE:
240f6d57916SPaul Mackerras 		write_seqlock_irqsave(&xtime_lock, flags);
241f6d57916SPaul Mackerras 		xtime.tv_sec = pmac_get_rtc_time() + time_diff;
242f6d57916SPaul Mackerras 		xtime.tv_nsec = 0;
243f6d57916SPaul Mackerras 		last_rtc_update = xtime.tv_sec;
244f6d57916SPaul Mackerras 		write_sequnlock_irqrestore(&xtime_lock, flags);
245f6d57916SPaul Mackerras 		break;
246f6d57916SPaul Mackerras 	}
247f6d57916SPaul Mackerras 	return PBOOK_SLEEP_OK;
248f6d57916SPaul Mackerras }
249f6d57916SPaul Mackerras 
250f6d57916SPaul Mackerras static struct pmu_sleep_notifier time_sleep_notifier = {
251f6d57916SPaul Mackerras 	time_sleep_notify, SLEEP_LEVEL_MISC,
252f6d57916SPaul Mackerras };
253f6d57916SPaul Mackerras #endif /* CONFIG_PM */
254f6d57916SPaul Mackerras 
255f6d57916SPaul Mackerras /*
256f6d57916SPaul Mackerras  * Query the OF and get the decr frequency.
257f6d57916SPaul Mackerras  * This was taken from the pmac time_init() when merging the prep/pmac
258f6d57916SPaul Mackerras  * time functions.
259f6d57916SPaul Mackerras  */
260f6d57916SPaul Mackerras void __init
261f6d57916SPaul Mackerras pmac_calibrate_decr(void)
262f6d57916SPaul Mackerras {
263f6d57916SPaul Mackerras 	struct device_node *cpu;
264f6d57916SPaul Mackerras 	unsigned int freq, *fp;
265f6d57916SPaul Mackerras 
266f6d57916SPaul Mackerras #ifdef CONFIG_PM
267f6d57916SPaul Mackerras 	pmu_register_sleep_notifier(&time_sleep_notifier);
268f6d57916SPaul Mackerras #endif /* CONFIG_PM */
269f6d57916SPaul Mackerras 
270f6d57916SPaul Mackerras 	/* We assume MacRISC2 machines have correct device-tree
271f6d57916SPaul Mackerras 	 * calibration. That's better since the VIA itself seems
272f6d57916SPaul Mackerras 	 * to be slightly off. --BenH
273f6d57916SPaul Mackerras 	 */
274f6d57916SPaul Mackerras 	if (!machine_is_compatible("MacRISC2") &&
275f6d57916SPaul Mackerras 	    !machine_is_compatible("MacRISC3") &&
276f6d57916SPaul Mackerras 	    !machine_is_compatible("MacRISC4"))
277f6d57916SPaul Mackerras 		if (via_calibrate_decr())
278f6d57916SPaul Mackerras 			return;
279f6d57916SPaul Mackerras 
280f6d57916SPaul Mackerras 	/* Special case: QuickSilver G4s seem to have a badly calibrated
281f6d57916SPaul Mackerras 	 * timebase-frequency in OF, VIA is much better on these. We should
282f6d57916SPaul Mackerras 	 * probably implement calibration based on the KL timer on these
283f6d57916SPaul Mackerras 	 * machines anyway... -BenH
284f6d57916SPaul Mackerras 	 */
285f6d57916SPaul Mackerras 	if (machine_is_compatible("PowerMac3,5"))
286f6d57916SPaul Mackerras 		if (via_calibrate_decr())
287f6d57916SPaul Mackerras 			return;
288f6d57916SPaul Mackerras 	/*
289f6d57916SPaul Mackerras 	 * The cpu node should have a timebase-frequency property
290f6d57916SPaul Mackerras 	 * to tell us the rate at which the decrementer counts.
291f6d57916SPaul Mackerras 	 */
292f6d57916SPaul Mackerras 	cpu = find_type_devices("cpu");
293f6d57916SPaul Mackerras 	if (cpu == 0)
294f6d57916SPaul Mackerras 		panic("can't find cpu node in time_init");
295f6d57916SPaul Mackerras 	fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
296f6d57916SPaul Mackerras 	if (fp == 0)
297f6d57916SPaul Mackerras 		panic("can't get cpu timebase frequency");
298f6d57916SPaul Mackerras 	freq = *fp;
299f6d57916SPaul Mackerras 	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
300f6d57916SPaul Mackerras 	       freq/1000000, freq%1000000);
301f6d57916SPaul Mackerras 	tb_ticks_per_jiffy = freq / HZ;
302f6d57916SPaul Mackerras 	tb_to_us = mulhwu_scale_factor(freq, 1000000);
303f6d57916SPaul Mackerras }
304