xref: /openbmc/linux/arch/alpha/kernel/rtc.c (revision 85d0b3a573d8b711ee0c96199ac24a0f3283ed68)
1*85d0b3a5SRichard Henderson /*
2*85d0b3a5SRichard Henderson  *  linux/arch/alpha/kernel/rtc.c
3*85d0b3a5SRichard Henderson  *
4*85d0b3a5SRichard Henderson  *  Copyright (C) 1991, 1992, 1995, 1999, 2000  Linus Torvalds
5*85d0b3a5SRichard Henderson  *
6*85d0b3a5SRichard Henderson  * This file contains date handling.
7*85d0b3a5SRichard Henderson  */
8*85d0b3a5SRichard Henderson #include <linux/errno.h>
9*85d0b3a5SRichard Henderson #include <linux/init.h>
10*85d0b3a5SRichard Henderson #include <linux/kernel.h>
11*85d0b3a5SRichard Henderson #include <linux/param.h>
12*85d0b3a5SRichard Henderson #include <linux/string.h>
13*85d0b3a5SRichard Henderson #include <linux/mc146818rtc.h>
14*85d0b3a5SRichard Henderson #include <linux/bcd.h>
15*85d0b3a5SRichard Henderson #include <linux/rtc.h>
16*85d0b3a5SRichard Henderson #include <linux/platform_device.h>
17*85d0b3a5SRichard Henderson 
18*85d0b3a5SRichard Henderson #include <asm/rtc.h>
19*85d0b3a5SRichard Henderson 
20*85d0b3a5SRichard Henderson #include "proto.h"
21*85d0b3a5SRichard Henderson 
22*85d0b3a5SRichard Henderson 
23*85d0b3a5SRichard Henderson /*
24*85d0b3a5SRichard Henderson  * Support for the RTC device.
25*85d0b3a5SRichard Henderson  *
26*85d0b3a5SRichard Henderson  * We don't want to use the rtc-cmos driver, because we don't want to support
27*85d0b3a5SRichard Henderson  * alarms, as that would be indistinguishable from timer interrupts.
28*85d0b3a5SRichard Henderson  *
29*85d0b3a5SRichard Henderson  * Further, generic code is really, really tied to a 1900 epoch.  This is
30*85d0b3a5SRichard Henderson  * true in __get_rtc_time as well as the users of struct rtc_time e.g.
31*85d0b3a5SRichard Henderson  * rtc_tm_to_time.  Thankfully all of the other epochs in use are later
32*85d0b3a5SRichard Henderson  * than 1900, and so it's easy to adjust.
33*85d0b3a5SRichard Henderson  */
34*85d0b3a5SRichard Henderson 
35*85d0b3a5SRichard Henderson static unsigned long rtc_epoch;
36*85d0b3a5SRichard Henderson 
37*85d0b3a5SRichard Henderson static int __init
38*85d0b3a5SRichard Henderson specifiy_epoch(char *str)
39*85d0b3a5SRichard Henderson {
40*85d0b3a5SRichard Henderson 	unsigned long epoch = simple_strtoul(str, NULL, 0);
41*85d0b3a5SRichard Henderson 	if (epoch < 1900)
42*85d0b3a5SRichard Henderson 		printk("Ignoring invalid user specified epoch %lu\n", epoch);
43*85d0b3a5SRichard Henderson 	else
44*85d0b3a5SRichard Henderson 		rtc_epoch = epoch;
45*85d0b3a5SRichard Henderson 	return 1;
46*85d0b3a5SRichard Henderson }
47*85d0b3a5SRichard Henderson __setup("epoch=", specifiy_epoch);
48*85d0b3a5SRichard Henderson 
49*85d0b3a5SRichard Henderson static void __init
50*85d0b3a5SRichard Henderson init_rtc_epoch(void)
51*85d0b3a5SRichard Henderson {
52*85d0b3a5SRichard Henderson 	int epoch, year, ctrl;
53*85d0b3a5SRichard Henderson 
54*85d0b3a5SRichard Henderson 	if (rtc_epoch != 0) {
55*85d0b3a5SRichard Henderson 		/* The epoch was specified on the command-line.  */
56*85d0b3a5SRichard Henderson 		return;
57*85d0b3a5SRichard Henderson 	}
58*85d0b3a5SRichard Henderson 
59*85d0b3a5SRichard Henderson 	/* Detect the epoch in use on this computer.  */
60*85d0b3a5SRichard Henderson 	ctrl = CMOS_READ(RTC_CONTROL);
61*85d0b3a5SRichard Henderson 	year = CMOS_READ(RTC_YEAR);
62*85d0b3a5SRichard Henderson 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
63*85d0b3a5SRichard Henderson 		year = bcd2bin(year);
64*85d0b3a5SRichard Henderson 
65*85d0b3a5SRichard Henderson 	/* PC-like is standard; used for year >= 70 */
66*85d0b3a5SRichard Henderson 	epoch = 1900;
67*85d0b3a5SRichard Henderson 	if (year < 20) {
68*85d0b3a5SRichard Henderson 		epoch = 2000;
69*85d0b3a5SRichard Henderson 	} else if (year >= 20 && year < 48) {
70*85d0b3a5SRichard Henderson 		/* NT epoch */
71*85d0b3a5SRichard Henderson 		epoch = 1980;
72*85d0b3a5SRichard Henderson 	} else if (year >= 48 && year < 70) {
73*85d0b3a5SRichard Henderson 		/* Digital UNIX epoch */
74*85d0b3a5SRichard Henderson 		epoch = 1952;
75*85d0b3a5SRichard Henderson 	}
76*85d0b3a5SRichard Henderson 	rtc_epoch = epoch;
77*85d0b3a5SRichard Henderson 
78*85d0b3a5SRichard Henderson 	printk(KERN_INFO "Using epoch %d for rtc year %d\n", epoch, year);
79*85d0b3a5SRichard Henderson }
80*85d0b3a5SRichard Henderson 
81*85d0b3a5SRichard Henderson static int
82*85d0b3a5SRichard Henderson alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
83*85d0b3a5SRichard Henderson {
84*85d0b3a5SRichard Henderson 	__get_rtc_time(tm);
85*85d0b3a5SRichard Henderson 
86*85d0b3a5SRichard Henderson 	/* Adjust for non-default epochs.  It's easier to depend on the
87*85d0b3a5SRichard Henderson 	   generic __get_rtc_time and adjust the epoch here than create
88*85d0b3a5SRichard Henderson 	   a copy of __get_rtc_time with the edits we need.  */
89*85d0b3a5SRichard Henderson 	if (rtc_epoch != 1900) {
90*85d0b3a5SRichard Henderson 		int year = tm->tm_year;
91*85d0b3a5SRichard Henderson 		/* Undo the century adjustment made in __get_rtc_time.  */
92*85d0b3a5SRichard Henderson 		if (year >= 100)
93*85d0b3a5SRichard Henderson 			year -= 100;
94*85d0b3a5SRichard Henderson 		year += rtc_epoch - 1900;
95*85d0b3a5SRichard Henderson 		/* Redo the century adjustment with the epoch in place.  */
96*85d0b3a5SRichard Henderson 		if (year <= 69)
97*85d0b3a5SRichard Henderson 			year += 100;
98*85d0b3a5SRichard Henderson 		tm->tm_year = year;
99*85d0b3a5SRichard Henderson 	}
100*85d0b3a5SRichard Henderson 
101*85d0b3a5SRichard Henderson 	return rtc_valid_tm(tm);
102*85d0b3a5SRichard Henderson }
103*85d0b3a5SRichard Henderson 
104*85d0b3a5SRichard Henderson static int
105*85d0b3a5SRichard Henderson alpha_rtc_set_time(struct device *dev, struct rtc_time *tm)
106*85d0b3a5SRichard Henderson {
107*85d0b3a5SRichard Henderson 	struct rtc_time xtm;
108*85d0b3a5SRichard Henderson 
109*85d0b3a5SRichard Henderson 	if (rtc_epoch != 1900) {
110*85d0b3a5SRichard Henderson 		xtm = *tm;
111*85d0b3a5SRichard Henderson 		xtm.tm_year -= rtc_epoch - 1900;
112*85d0b3a5SRichard Henderson 		tm = &xtm;
113*85d0b3a5SRichard Henderson 	}
114*85d0b3a5SRichard Henderson 
115*85d0b3a5SRichard Henderson 	return __set_rtc_time(tm);
116*85d0b3a5SRichard Henderson }
117*85d0b3a5SRichard Henderson 
118*85d0b3a5SRichard Henderson static int
119*85d0b3a5SRichard Henderson alpha_rtc_set_mmss(struct device *dev, unsigned long nowtime)
120*85d0b3a5SRichard Henderson {
121*85d0b3a5SRichard Henderson 	int retval = 0;
122*85d0b3a5SRichard Henderson 	int real_seconds, real_minutes, cmos_minutes;
123*85d0b3a5SRichard Henderson 	unsigned char save_control, save_freq_select;
124*85d0b3a5SRichard Henderson 
125*85d0b3a5SRichard Henderson 	/* Note: This code only updates minutes and seconds.  Comments
126*85d0b3a5SRichard Henderson 	   indicate this was to avoid messing with unknown time zones,
127*85d0b3a5SRichard Henderson 	   and with the epoch nonsense described above.  In order for
128*85d0b3a5SRichard Henderson 	   this to work, the existing clock cannot be off by more than
129*85d0b3a5SRichard Henderson 	   15 minutes.
130*85d0b3a5SRichard Henderson 
131*85d0b3a5SRichard Henderson 	   ??? This choice is may be out of date.  The x86 port does
132*85d0b3a5SRichard Henderson 	   not have problems with timezones, and the epoch processing has
133*85d0b3a5SRichard Henderson 	   now been fixed in alpha_set_rtc_time.
134*85d0b3a5SRichard Henderson 
135*85d0b3a5SRichard Henderson 	   In either case, one can always force a full rtc update with
136*85d0b3a5SRichard Henderson 	   the userland hwclock program, so surely 15 minute accuracy
137*85d0b3a5SRichard Henderson 	   is no real burden.  */
138*85d0b3a5SRichard Henderson 
139*85d0b3a5SRichard Henderson 	/* In order to set the CMOS clock precisely, we have to be called
140*85d0b3a5SRichard Henderson 	   500 ms after the second nowtime has started, because when
141*85d0b3a5SRichard Henderson 	   nowtime is written into the registers of the CMOS clock, it will
142*85d0b3a5SRichard Henderson 	   jump to the next second precisely 500 ms later. Check the Motorola
143*85d0b3a5SRichard Henderson 	   MC146818A or Dallas DS12887 data sheet for details.  */
144*85d0b3a5SRichard Henderson 
145*85d0b3a5SRichard Henderson 	/* irq are locally disabled here */
146*85d0b3a5SRichard Henderson 	spin_lock(&rtc_lock);
147*85d0b3a5SRichard Henderson 	/* Tell the clock it's being set */
148*85d0b3a5SRichard Henderson 	save_control = CMOS_READ(RTC_CONTROL);
149*85d0b3a5SRichard Henderson 	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
150*85d0b3a5SRichard Henderson 
151*85d0b3a5SRichard Henderson 	/* Stop and reset prescaler */
152*85d0b3a5SRichard Henderson 	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
153*85d0b3a5SRichard Henderson 	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
154*85d0b3a5SRichard Henderson 
155*85d0b3a5SRichard Henderson 	cmos_minutes = CMOS_READ(RTC_MINUTES);
156*85d0b3a5SRichard Henderson 	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
157*85d0b3a5SRichard Henderson 		cmos_minutes = bcd2bin(cmos_minutes);
158*85d0b3a5SRichard Henderson 
159*85d0b3a5SRichard Henderson 	real_seconds = nowtime % 60;
160*85d0b3a5SRichard Henderson 	real_minutes = nowtime / 60;
161*85d0b3a5SRichard Henderson 	if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) {
162*85d0b3a5SRichard Henderson 		/* correct for half hour time zone */
163*85d0b3a5SRichard Henderson 		real_minutes += 30;
164*85d0b3a5SRichard Henderson 	}
165*85d0b3a5SRichard Henderson 	real_minutes %= 60;
166*85d0b3a5SRichard Henderson 
167*85d0b3a5SRichard Henderson 	if (abs(real_minutes - cmos_minutes) < 30) {
168*85d0b3a5SRichard Henderson 		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
169*85d0b3a5SRichard Henderson 			real_seconds = bin2bcd(real_seconds);
170*85d0b3a5SRichard Henderson 			real_minutes = bin2bcd(real_minutes);
171*85d0b3a5SRichard Henderson 		}
172*85d0b3a5SRichard Henderson 		CMOS_WRITE(real_seconds,RTC_SECONDS);
173*85d0b3a5SRichard Henderson 		CMOS_WRITE(real_minutes,RTC_MINUTES);
174*85d0b3a5SRichard Henderson 	} else {
175*85d0b3a5SRichard Henderson 		printk_once(KERN_NOTICE
176*85d0b3a5SRichard Henderson 			    "set_rtc_mmss: can't update from %d to %d\n",
177*85d0b3a5SRichard Henderson 			    cmos_minutes, real_minutes);
178*85d0b3a5SRichard Henderson 		retval = -1;
179*85d0b3a5SRichard Henderson 	}
180*85d0b3a5SRichard Henderson 
181*85d0b3a5SRichard Henderson 	/* The following flags have to be released exactly in this order,
182*85d0b3a5SRichard Henderson 	 * otherwise the DS12887 (popular MC146818A clone with integrated
183*85d0b3a5SRichard Henderson 	 * battery and quartz) will not reset the oscillator and will not
184*85d0b3a5SRichard Henderson 	 * update precisely 500 ms later. You won't find this mentioned in
185*85d0b3a5SRichard Henderson 	 * the Dallas Semiconductor data sheets, but who believes data
186*85d0b3a5SRichard Henderson 	 * sheets anyway ...                           -- Markus Kuhn
187*85d0b3a5SRichard Henderson 	 */
188*85d0b3a5SRichard Henderson 	CMOS_WRITE(save_control, RTC_CONTROL);
189*85d0b3a5SRichard Henderson 	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
190*85d0b3a5SRichard Henderson 	spin_unlock(&rtc_lock);
191*85d0b3a5SRichard Henderson 
192*85d0b3a5SRichard Henderson 	return retval;
193*85d0b3a5SRichard Henderson }
194*85d0b3a5SRichard Henderson 
195*85d0b3a5SRichard Henderson static int
196*85d0b3a5SRichard Henderson alpha_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
197*85d0b3a5SRichard Henderson {
198*85d0b3a5SRichard Henderson 	switch (cmd) {
199*85d0b3a5SRichard Henderson 	case RTC_EPOCH_READ:
200*85d0b3a5SRichard Henderson 		return put_user(rtc_epoch, (unsigned long __user *)arg);
201*85d0b3a5SRichard Henderson 	case RTC_EPOCH_SET:
202*85d0b3a5SRichard Henderson 		if (arg < 1900)
203*85d0b3a5SRichard Henderson 			return -EINVAL;
204*85d0b3a5SRichard Henderson 		rtc_epoch = arg;
205*85d0b3a5SRichard Henderson 		return 0;
206*85d0b3a5SRichard Henderson 	default:
207*85d0b3a5SRichard Henderson 		return -ENOIOCTLCMD;
208*85d0b3a5SRichard Henderson 	}
209*85d0b3a5SRichard Henderson }
210*85d0b3a5SRichard Henderson 
211*85d0b3a5SRichard Henderson static const struct rtc_class_ops alpha_rtc_ops = {
212*85d0b3a5SRichard Henderson 	.read_time = alpha_rtc_read_time,
213*85d0b3a5SRichard Henderson 	.set_time = alpha_rtc_set_time,
214*85d0b3a5SRichard Henderson 	.set_mmss = alpha_rtc_set_mmss,
215*85d0b3a5SRichard Henderson 	.ioctl = alpha_rtc_ioctl,
216*85d0b3a5SRichard Henderson };
217*85d0b3a5SRichard Henderson 
218*85d0b3a5SRichard Henderson /*
219*85d0b3a5SRichard Henderson  * Similarly, except do the actual CMOS access on the boot cpu only.
220*85d0b3a5SRichard Henderson  * This requires marshalling the data across an interprocessor call.
221*85d0b3a5SRichard Henderson  */
222*85d0b3a5SRichard Henderson 
223*85d0b3a5SRichard Henderson #if defined(CONFIG_SMP) && \
224*85d0b3a5SRichard Henderson     (defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL))
225*85d0b3a5SRichard Henderson # define HAVE_REMOTE_RTC 1
226*85d0b3a5SRichard Henderson 
227*85d0b3a5SRichard Henderson union remote_data {
228*85d0b3a5SRichard Henderson 	struct rtc_time *tm;
229*85d0b3a5SRichard Henderson 	unsigned long now;
230*85d0b3a5SRichard Henderson 	long retval;
231*85d0b3a5SRichard Henderson };
232*85d0b3a5SRichard Henderson 
233*85d0b3a5SRichard Henderson static void
234*85d0b3a5SRichard Henderson do_remote_read(void *data)
235*85d0b3a5SRichard Henderson {
236*85d0b3a5SRichard Henderson 	union remote_data *x = data;
237*85d0b3a5SRichard Henderson 	x->retval = alpha_rtc_read_time(NULL, x->tm);
238*85d0b3a5SRichard Henderson }
239*85d0b3a5SRichard Henderson 
240*85d0b3a5SRichard Henderson static int
241*85d0b3a5SRichard Henderson remote_read_time(struct device *dev, struct rtc_time *tm)
242*85d0b3a5SRichard Henderson {
243*85d0b3a5SRichard Henderson 	union remote_data x;
244*85d0b3a5SRichard Henderson 	if (smp_processor_id() != boot_cpuid) {
245*85d0b3a5SRichard Henderson 		x.tm = tm;
246*85d0b3a5SRichard Henderson 		smp_call_function_single(boot_cpuid, do_remote_read, &x, 1);
247*85d0b3a5SRichard Henderson 		return x.retval;
248*85d0b3a5SRichard Henderson 	}
249*85d0b3a5SRichard Henderson 	return alpha_rtc_read_time(NULL, tm);
250*85d0b3a5SRichard Henderson }
251*85d0b3a5SRichard Henderson 
252*85d0b3a5SRichard Henderson static void
253*85d0b3a5SRichard Henderson do_remote_set(void *data)
254*85d0b3a5SRichard Henderson {
255*85d0b3a5SRichard Henderson 	union remote_data *x = data;
256*85d0b3a5SRichard Henderson 	x->retval = alpha_rtc_set_time(NULL, x->tm);
257*85d0b3a5SRichard Henderson }
258*85d0b3a5SRichard Henderson 
259*85d0b3a5SRichard Henderson static int
260*85d0b3a5SRichard Henderson remote_set_time(struct device *dev, struct rtc_time *tm)
261*85d0b3a5SRichard Henderson {
262*85d0b3a5SRichard Henderson 	union remote_data x;
263*85d0b3a5SRichard Henderson 	if (smp_processor_id() != boot_cpuid) {
264*85d0b3a5SRichard Henderson 		x.tm = tm;
265*85d0b3a5SRichard Henderson 		smp_call_function_single(boot_cpuid, do_remote_set, &x, 1);
266*85d0b3a5SRichard Henderson 		return x.retval;
267*85d0b3a5SRichard Henderson 	}
268*85d0b3a5SRichard Henderson 	return alpha_rtc_set_time(NULL, tm);
269*85d0b3a5SRichard Henderson }
270*85d0b3a5SRichard Henderson 
271*85d0b3a5SRichard Henderson static void
272*85d0b3a5SRichard Henderson do_remote_mmss(void *data)
273*85d0b3a5SRichard Henderson {
274*85d0b3a5SRichard Henderson 	union remote_data *x = data;
275*85d0b3a5SRichard Henderson 	x->retval = alpha_rtc_set_mmss(NULL, x->now);
276*85d0b3a5SRichard Henderson }
277*85d0b3a5SRichard Henderson 
278*85d0b3a5SRichard Henderson static int
279*85d0b3a5SRichard Henderson remote_set_mmss(struct device *dev, unsigned long now)
280*85d0b3a5SRichard Henderson {
281*85d0b3a5SRichard Henderson 	union remote_data x;
282*85d0b3a5SRichard Henderson 	if (smp_processor_id() != boot_cpuid) {
283*85d0b3a5SRichard Henderson 		x.now = now;
284*85d0b3a5SRichard Henderson 		smp_call_function_single(boot_cpuid, do_remote_mmss, &x, 1);
285*85d0b3a5SRichard Henderson 		return x.retval;
286*85d0b3a5SRichard Henderson 	}
287*85d0b3a5SRichard Henderson 	return alpha_rtc_set_mmss(NULL, now);
288*85d0b3a5SRichard Henderson }
289*85d0b3a5SRichard Henderson 
290*85d0b3a5SRichard Henderson static const struct rtc_class_ops remote_rtc_ops = {
291*85d0b3a5SRichard Henderson 	.read_time = remote_read_time,
292*85d0b3a5SRichard Henderson 	.set_time = remote_set_time,
293*85d0b3a5SRichard Henderson 	.set_mmss = remote_set_mmss,
294*85d0b3a5SRichard Henderson 	.ioctl = alpha_rtc_ioctl,
295*85d0b3a5SRichard Henderson };
296*85d0b3a5SRichard Henderson #endif
297*85d0b3a5SRichard Henderson 
298*85d0b3a5SRichard Henderson static int __init
299*85d0b3a5SRichard Henderson alpha_rtc_init(void)
300*85d0b3a5SRichard Henderson {
301*85d0b3a5SRichard Henderson 	const struct rtc_class_ops *ops;
302*85d0b3a5SRichard Henderson 	struct platform_device *pdev;
303*85d0b3a5SRichard Henderson 	struct rtc_device *rtc;
304*85d0b3a5SRichard Henderson 	const char *name;
305*85d0b3a5SRichard Henderson 
306*85d0b3a5SRichard Henderson 	init_rtc_epoch();
307*85d0b3a5SRichard Henderson 	name = "rtc-alpha";
308*85d0b3a5SRichard Henderson 	ops = &alpha_rtc_ops;
309*85d0b3a5SRichard Henderson 
310*85d0b3a5SRichard Henderson #ifdef HAVE_REMOTE_RTC
311*85d0b3a5SRichard Henderson 	if (alpha_mv.rtc_boot_cpu_only)
312*85d0b3a5SRichard Henderson 		ops = &remote_rtc_ops;
313*85d0b3a5SRichard Henderson #endif
314*85d0b3a5SRichard Henderson 
315*85d0b3a5SRichard Henderson 	pdev = platform_device_register_simple(name, -1, NULL, 0);
316*85d0b3a5SRichard Henderson 	rtc = devm_rtc_device_register(&pdev->dev, name, ops, THIS_MODULE);
317*85d0b3a5SRichard Henderson 	if (IS_ERR(rtc))
318*85d0b3a5SRichard Henderson 		return PTR_ERR(rtc);
319*85d0b3a5SRichard Henderson 
320*85d0b3a5SRichard Henderson 	platform_set_drvdata(pdev, rtc);
321*85d0b3a5SRichard Henderson 	return 0;
322*85d0b3a5SRichard Henderson }
323*85d0b3a5SRichard Henderson device_initcall(alpha_rtc_init);
324