aboutsummaryrefslogtreecommitdiffstats
path: root/arch/alpha
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2013-07-13 18:49:45 -0400
committerMatt Turner <mattst88@gmail.com>2013-11-16 19:33:16 -0500
commit85d0b3a573d8b711ee0c96199ac24a0f3283ed68 (patch)
treee3ccfb8221bac388dc44fcc068ab1b32f67839a3 /arch/alpha
parent7f3bbb82e0c371d6881129f776c90130ba66f051 (diff)
alpha: Reorganize rtc handling
Discontinue use of GENERIC_CMOS_UPDATE; rely on the RTC subsystem. The marvel platform requires that the rtc only be touched from the boot cpu. This had been partially implemented with hooks for get/set_rtc_time, but read/update_persistent_clock were not handled. Move the hooks from the machine_vec to a special rtc_class_ops struct. We had read_persistent_clock managing the epoch against which the rtc hw is based, but this didn't apply to get_rtc_time or set_rtc_time. This resulted in incorrect values when hwclock(8) gets involved. Allow the epoch to be set from the kernel command-line, overriding the autodetection, which is doomed to fail in 2020. Further, by implementing the rtc ioctl function, we can expose this epoch to userland. Elide the alarm functions that RTC_DRV_CMOS implements. This was highly questionable on Alpha, since the interrupt is used by the system timer. Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'arch/alpha')
-rw-r--r--arch/alpha/Kconfig1
-rw-r--r--arch/alpha/include/asm/machvec.h4
-rw-r--r--arch/alpha/include/asm/rtc.h11
-rw-r--r--arch/alpha/kernel/Makefile1
-rw-r--r--arch/alpha/kernel/machvec_impl.h5
-rw-r--r--arch/alpha/kernel/proto.h2
-rw-r--r--arch/alpha/kernel/rtc.c323
-rw-r--r--arch/alpha/kernel/sys_jensen.c2
-rw-r--r--arch/alpha/kernel/sys_marvel.c55
-rw-r--r--arch/alpha/kernel/time.c146
10 files changed, 328 insertions, 222 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index f9e84da49716..5d863d171b94 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -17,7 +17,6 @@ config ALPHA
17 select ARCH_HAVE_NMI_SAFE_CMPXCHG 17 select ARCH_HAVE_NMI_SAFE_CMPXCHG
18 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 18 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
19 select GENERIC_SMP_IDLE_THREAD 19 select GENERIC_SMP_IDLE_THREAD
20 select GENERIC_CMOS_UPDATE
21 select GENERIC_STRNCPY_FROM_USER 20 select GENERIC_STRNCPY_FROM_USER
22 select GENERIC_STRNLEN_USER 21 select GENERIC_STRNLEN_USER
23 select HAVE_MOD_ARCH_SPECIFIC 22 select HAVE_MOD_ARCH_SPECIFIC
diff --git a/arch/alpha/include/asm/machvec.h b/arch/alpha/include/asm/machvec.h
index 4ac90167d346..75cb3641ed2f 100644
--- a/arch/alpha/include/asm/machvec.h
+++ b/arch/alpha/include/asm/machvec.h
@@ -33,6 +33,7 @@ struct alpha_machine_vector
33 33
34 int nr_irqs; 34 int nr_irqs;
35 int rtc_port; 35 int rtc_port;
36 int rtc_boot_cpu_only;
36 unsigned int max_asn; 37 unsigned int max_asn;
37 unsigned long max_isa_dma_address; 38 unsigned long max_isa_dma_address;
38 unsigned long irq_probe_mask; 39 unsigned long irq_probe_mask;
@@ -95,9 +96,6 @@ struct alpha_machine_vector
95 96
96 struct _alpha_agp_info *(*agp_info)(void); 97 struct _alpha_agp_info *(*agp_info)(void);
97 98
98 unsigned int (*rtc_get_time)(struct rtc_time *);
99 int (*rtc_set_time)(struct rtc_time *);
100
101 const char *vector_name; 99 const char *vector_name;
102 100
103 /* NUMA information */ 101 /* NUMA information */
diff --git a/arch/alpha/include/asm/rtc.h b/arch/alpha/include/asm/rtc.h
index d70408d36677..f71c3b0ed360 100644
--- a/arch/alpha/include/asm/rtc.h
+++ b/arch/alpha/include/asm/rtc.h
@@ -1,12 +1 @@
1#ifndef _ALPHA_RTC_H
2#define _ALPHA_RTC_H
3
4#if defined(CONFIG_ALPHA_MARVEL) && defined(CONFIG_SMP) \
5 || defined(CONFIG_ALPHA_GENERIC)
6# define get_rtc_time alpha_mv.rtc_get_time
7# define set_rtc_time alpha_mv.rtc_set_time
8#endif
9
10#include <asm-generic/rtc.h> #include <asm-generic/rtc.h>
11
12#endif
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 84ec46b38f7d..0d54650e78fc 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_PCI) += pci.o pci_iommu.o pci-sysfs.o
16obj-$(CONFIG_SRM_ENV) += srm_env.o 16obj-$(CONFIG_SRM_ENV) += srm_env.o
17obj-$(CONFIG_MODULES) += module.o 17obj-$(CONFIG_MODULES) += module.o
18obj-$(CONFIG_PERF_EVENTS) += perf_event.o 18obj-$(CONFIG_PERF_EVENTS) += perf_event.o
19obj-$(CONFIG_RTC_DRV_ALPHA) += rtc.o
19 20
20ifdef CONFIG_ALPHA_GENERIC 21ifdef CONFIG_ALPHA_GENERIC
21 22
diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h
index 7fa62488bd16..f54bdf658cd0 100644
--- a/arch/alpha/kernel/machvec_impl.h
+++ b/arch/alpha/kernel/machvec_impl.h
@@ -43,10 +43,7 @@
43#define CAT1(x,y) x##y 43#define CAT1(x,y) x##y
44#define CAT(x,y) CAT1(x,y) 44#define CAT(x,y) CAT1(x,y)
45 45
46#define DO_DEFAULT_RTC \ 46#define DO_DEFAULT_RTC .rtc_port = 0x70
47 .rtc_port = 0x70, \
48 .rtc_get_time = common_get_rtc_time, \
49 .rtc_set_time = common_set_rtc_time
50 47
51#define DO_EV4_MMU \ 48#define DO_EV4_MMU \
52 .max_asn = EV4_MAX_ASN, \ 49 .max_asn = EV4_MAX_ASN, \
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index d3e52d3fd592..3b250fa5f2c1 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -144,8 +144,6 @@ extern void smp_percpu_timer_interrupt(struct pt_regs *);
144extern irqreturn_t timer_interrupt(int irq, void *dev); 144extern irqreturn_t timer_interrupt(int irq, void *dev);
145extern void common_init_rtc(void); 145extern void common_init_rtc(void);
146extern unsigned long est_cycle_freq; 146extern unsigned long est_cycle_freq;
147extern unsigned int common_get_rtc_time(struct rtc_time *time);
148extern int common_set_rtc_time(struct rtc_time *time);
149 147
150/* smc37c93x.c */ 148/* smc37c93x.c */
151extern void SMC93x_Init(void); 149extern void SMC93x_Init(void);
diff --git a/arch/alpha/kernel/rtc.c b/arch/alpha/kernel/rtc.c
new file mode 100644
index 000000000000..c8d284d8521f
--- /dev/null
+++ b/arch/alpha/kernel/rtc.c
@@ -0,0 +1,323 @@
1/*
2 * linux/arch/alpha/kernel/rtc.c
3 *
4 * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds
5 *
6 * This file contains date handling.
7 */
8#include <linux/errno.h>
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/param.h>
12#include <linux/string.h>
13#include <linux/mc146818rtc.h>
14#include <linux/bcd.h>
15#include <linux/rtc.h>
16#include <linux/platform_device.h>
17
18#include <asm/rtc.h>
19
20#include "proto.h"
21
22
23/*
24 * Support for the RTC device.
25 *
26 * We don't want to use the rtc-cmos driver, because we don't want to support
27 * alarms, as that would be indistinguishable from timer interrupts.
28 *
29 * Further, generic code is really, really tied to a 1900 epoch. This is
30 * true in __get_rtc_time as well as the users of struct rtc_time e.g.
31 * rtc_tm_to_time. Thankfully all of the other epochs in use are later
32 * than 1900, and so it's easy to adjust.
33 */
34
35static unsigned long rtc_epoch;
36
37static int __init
38specifiy_epoch(char *str)
39{
40 unsigned long epoch = simple_strtoul(str, NULL, 0);
41 if (epoch < 1900)
42 printk("Ignoring invalid user specified epoch %lu\n", epoch);
43 else
44 rtc_epoch = epoch;
45 return 1;
46}
47__setup("epoch=", specifiy_epoch);
48
49static void __init
50init_rtc_epoch(void)
51{
52 int epoch, year, ctrl;
53
54 if (rtc_epoch != 0) {
55 /* The epoch was specified on the command-line. */
56 return;
57 }
58
59 /* Detect the epoch in use on this computer. */
60 ctrl = CMOS_READ(RTC_CONTROL);
61 year = CMOS_READ(RTC_YEAR);
62 if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
63 year = bcd2bin(year);
64
65 /* PC-like is standard; used for year >= 70 */
66 epoch = 1900;
67 if (year < 20) {
68 epoch = 2000;
69 } else if (year >= 20 && year < 48) {
70 /* NT epoch */
71 epoch = 1980;
72 } else if (year >= 48 && year < 70) {
73 /* Digital UNIX epoch */
74 epoch = 1952;
75 }
76 rtc_epoch = epoch;
77
78 printk(KERN_INFO "Using epoch %d for rtc year %d\n", epoch, year);
79}
80
81static int
82alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
83{
84 __get_rtc_time(tm);
85
86 /* Adjust for non-default epochs. It's easier to depend on the
87 generic __get_rtc_time and adjust the epoch here than create
88 a copy of __get_rtc_time with the edits we need. */
89 if (rtc_epoch != 1900) {
90 int year = tm->tm_year;
91 /* Undo the century adjustment made in __get_rtc_time. */
92 if (year >= 100)
93 year -= 100;
94 year += rtc_epoch - 1900;
95 /* Redo the century adjustment with the epoch in place. */
96 if (year <= 69)
97 year += 100;
98 tm->tm_year = year;
99 }
100
101 return rtc_valid_tm(tm);
102}
103
104static int
105alpha_rtc_set_time(struct device *dev, struct rtc_time *tm)
106{
107 struct rtc_time xtm;
108
109 if (rtc_epoch != 1900) {
110 xtm = *tm;
111 xtm.tm_year -= rtc_epoch - 1900;
112 tm = &xtm;
113 }
114
115 return __set_rtc_time(tm);
116}
117
118static int
119alpha_rtc_set_mmss(struct device *dev, unsigned long nowtime)
120{
121 int retval = 0;
122 int real_seconds, real_minutes, cmos_minutes;
123 unsigned char save_control, save_freq_select;
124
125 /* Note: This code only updates minutes and seconds. Comments
126 indicate this was to avoid messing with unknown time zones,
127 and with the epoch nonsense described above. In order for
128 this to work, the existing clock cannot be off by more than
129 15 minutes.
130
131 ??? This choice is may be out of date. The x86 port does
132 not have problems with timezones, and the epoch processing has
133 now been fixed in alpha_set_rtc_time.
134
135 In either case, one can always force a full rtc update with
136 the userland hwclock program, so surely 15 minute accuracy
137 is no real burden. */
138
139 /* In order to set the CMOS clock precisely, we have to be called
140 500 ms after the second nowtime has started, because when
141 nowtime is written into the registers of the CMOS clock, it will
142 jump to the next second precisely 500 ms later. Check the Motorola
143 MC146818A or Dallas DS12887 data sheet for details. */
144
145 /* irq are locally disabled here */
146 spin_lock(&rtc_lock);
147 /* Tell the clock it's being set */
148 save_control = CMOS_READ(RTC_CONTROL);
149 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
150
151 /* Stop and reset prescaler */
152 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
153 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
154
155 cmos_minutes = CMOS_READ(RTC_MINUTES);
156 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
157 cmos_minutes = bcd2bin(cmos_minutes);
158
159 real_seconds = nowtime % 60;
160 real_minutes = nowtime / 60;
161 if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) {
162 /* correct for half hour time zone */
163 real_minutes += 30;
164 }
165 real_minutes %= 60;
166
167 if (abs(real_minutes - cmos_minutes) < 30) {
168 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
169 real_seconds = bin2bcd(real_seconds);
170 real_minutes = bin2bcd(real_minutes);
171 }
172 CMOS_WRITE(real_seconds,RTC_SECONDS);
173 CMOS_WRITE(real_minutes,RTC_MINUTES);
174 } else {
175 printk_once(KERN_NOTICE
176 "set_rtc_mmss: can't update from %d to %d\n",
177 cmos_minutes, real_minutes);
178 retval = -1;
179 }
180
181 /* The following flags have to be released exactly in this order,
182 * otherwise the DS12887 (popular MC146818A clone with integrated
183 * battery and quartz) will not reset the oscillator and will not
184 * update precisely 500 ms later. You won't find this mentioned in
185 * the Dallas Semiconductor data sheets, but who believes data
186 * sheets anyway ... -- Markus Kuhn
187 */
188 CMOS_WRITE(save_control, RTC_CONTROL);
189 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
190 spin_unlock(&rtc_lock);
191
192 return retval;
193}
194
195static int
196alpha_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
197{
198 switch (cmd) {
199 case RTC_EPOCH_READ:
200 return put_user(rtc_epoch, (unsigned long __user *)arg);
201 case RTC_EPOCH_SET:
202 if (arg < 1900)
203 return -EINVAL;
204 rtc_epoch = arg;
205 return 0;
206 default:
207 return -ENOIOCTLCMD;
208 }
209}
210
211static const struct rtc_class_ops alpha_rtc_ops = {
212 .read_time = alpha_rtc_read_time,
213 .set_time = alpha_rtc_set_time,
214 .set_mmss = alpha_rtc_set_mmss,
215 .ioctl = alpha_rtc_ioctl,
216};
217
218/*
219 * Similarly, except do the actual CMOS access on the boot cpu only.
220 * This requires marshalling the data across an interprocessor call.
221 */
222
223#if defined(CONFIG_SMP) && \
224 (defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL))
225# define HAVE_REMOTE_RTC 1
226
227union remote_data {
228 struct rtc_time *tm;
229 unsigned long now;
230 long retval;
231};
232
233static void
234do_remote_read(void *data)
235{
236 union remote_data *x = data;
237 x->retval = alpha_rtc_read_time(NULL, x->tm);
238}
239
240static int
241remote_read_time(struct device *dev, struct rtc_time *tm)
242{
243 union remote_data x;
244 if (smp_processor_id() != boot_cpuid) {
245 x.tm = tm;
246 smp_call_function_single(boot_cpuid, do_remote_read, &x, 1);
247 return x.retval;
248 }
249 return alpha_rtc_read_time(NULL, tm);
250}
251
252static void
253do_remote_set(void *data)
254{
255 union remote_data *x = data;
256 x->retval = alpha_rtc_set_time(NULL, x->tm);
257}
258
259static int
260remote_set_time(struct device *dev, struct rtc_time *tm)
261{
262 union remote_data x;
263 if (smp_processor_id() != boot_cpuid) {
264 x.tm = tm;
265 smp_call_function_single(boot_cpuid, do_remote_set, &x, 1);
266 return x.retval;
267 }
268 return alpha_rtc_set_time(NULL, tm);
269}
270
271static void
272do_remote_mmss(void *data)
273{
274 union remote_data *x = data;
275 x->retval = alpha_rtc_set_mmss(NULL, x->now);
276}
277
278static int
279remote_set_mmss(struct device *dev, unsigned long now)
280{
281 union remote_data x;
282 if (smp_processor_id() != boot_cpuid) {
283 x.now = now;
284 smp_call_function_single(boot_cpuid, do_remote_mmss, &x, 1);
285 return x.retval;
286 }
287 return alpha_rtc_set_mmss(NULL, now);
288}
289
290static const struct rtc_class_ops remote_rtc_ops = {
291 .read_time = remote_read_time,
292 .set_time = remote_set_time,
293 .set_mmss = remote_set_mmss,
294 .ioctl = alpha_rtc_ioctl,
295};
296#endif
297
298static int __init
299alpha_rtc_init(void)
300{
301 const struct rtc_class_ops *ops;
302 struct platform_device *pdev;
303 struct rtc_device *rtc;
304 const char *name;
305
306 init_rtc_epoch();
307 name = "rtc-alpha";
308 ops = &alpha_rtc_ops;
309
310#ifdef HAVE_REMOTE_RTC
311 if (alpha_mv.rtc_boot_cpu_only)
312 ops = &remote_rtc_ops;
313#endif
314
315 pdev = platform_device_register_simple(name, -1, NULL, 0);
316 rtc = devm_rtc_device_register(&pdev->dev, name, ops, THIS_MODULE);
317 if (IS_ERR(rtc))
318 return PTR_ERR(rtc);
319
320 platform_set_drvdata(pdev, rtc);
321 return 0;
322}
323device_initcall(alpha_rtc_init);
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
index 5a0af11b3a61..608f2a7fa0a3 100644
--- a/arch/alpha/kernel/sys_jensen.c
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -224,8 +224,6 @@ struct alpha_machine_vector jensen_mv __initmv = {
224 .machine_check = jensen_machine_check, 224 .machine_check = jensen_machine_check,
225 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 225 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
226 .rtc_port = 0x170, 226 .rtc_port = 0x170,
227 .rtc_get_time = common_get_rtc_time,
228 .rtc_set_time = common_set_rtc_time,
229 227
230 .nr_irqs = 16, 228 .nr_irqs = 16,
231 .device_interrupt = jensen_device_interrupt, 229 .device_interrupt = jensen_device_interrupt,
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index c92e389ff219..f21d61fab678 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -22,7 +22,6 @@
22#include <asm/hwrpb.h> 22#include <asm/hwrpb.h>
23#include <asm/tlbflush.h> 23#include <asm/tlbflush.h>
24#include <asm/vga.h> 24#include <asm/vga.h>
25#include <asm/rtc.h>
26 25
27#include "proto.h" 26#include "proto.h"
28#include "err_impl.h" 27#include "err_impl.h"
@@ -400,57 +399,6 @@ marvel_init_rtc(void)
400 init_rtc_irq(); 399 init_rtc_irq();
401} 400}
402 401
403struct marvel_rtc_time {
404 struct rtc_time *time;
405 int retval;
406};
407
408#ifdef CONFIG_SMP
409static void
410smp_get_rtc_time(void *data)
411{
412 struct marvel_rtc_time *mrt = data;
413 mrt->retval = __get_rtc_time(mrt->time);
414}
415
416static void
417smp_set_rtc_time(void *data)
418{
419 struct marvel_rtc_time *mrt = data;
420 mrt->retval = __set_rtc_time(mrt->time);
421}
422#endif
423
424static unsigned int
425marvel_get_rtc_time(struct rtc_time *time)
426{
427#ifdef CONFIG_SMP
428 struct marvel_rtc_time mrt;
429
430 if (smp_processor_id() != boot_cpuid) {
431 mrt.time = time;
432 smp_call_function_single(boot_cpuid, smp_get_rtc_time, &mrt, 1);
433 return mrt.retval;
434 }
435#endif
436 return __get_rtc_time(time);
437}
438
439static int
440marvel_set_rtc_time(struct rtc_time *time)
441{
442#ifdef CONFIG_SMP
443 struct marvel_rtc_time mrt;
444
445 if (smp_processor_id() != boot_cpuid) {
446 mrt.time = time;
447 smp_call_function_single(boot_cpuid, smp_set_rtc_time, &mrt, 1);
448 return mrt.retval;
449 }
450#endif
451 return __set_rtc_time(time);
452}
453
454static void 402static void
455marvel_smp_callin(void) 403marvel_smp_callin(void)
456{ 404{
@@ -492,8 +440,7 @@ struct alpha_machine_vector marvel_ev7_mv __initmv = {
492 .vector_name = "MARVEL/EV7", 440 .vector_name = "MARVEL/EV7",
493 DO_EV7_MMU, 441 DO_EV7_MMU,
494 .rtc_port = 0x70, 442 .rtc_port = 0x70,
495 .rtc_get_time = marvel_get_rtc_time, 443 .rtc_boot_cpu_only = 1,
496 .rtc_set_time = marvel_set_rtc_time,
497 DO_MARVEL_IO, 444 DO_MARVEL_IO,
498 .machine_check = marvel_machine_check, 445 .machine_check = marvel_machine_check,
499 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 446 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index a6bcb3113d81..4c6c0fe47a7b 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -3,13 +3,7 @@
3 * 3 *
4 * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds 4 * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds
5 * 5 *
6 * This file contains the PC-specific time handling details: 6 * This file contains the clocksource time handling.
7 * reading the RTC at bootup, etc..
8 * 1994-07-02 Alan Modra
9 * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
10 * 1995-03-26 Markus Kuhn
11 * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
12 * precision CMOS clock update
13 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 7 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
14 * "A Kernel Model for Precision Timekeeping" by Dave Mills 8 * "A Kernel Model for Precision Timekeeping" by Dave Mills
15 * 1997-01-09 Adrian Sun 9 * 1997-01-09 Adrian Sun
@@ -21,9 +15,6 @@
21 * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net) 15 * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net)
22 * fixed algorithm in do_gettimeofday() for calculating the precise time 16 * fixed algorithm in do_gettimeofday() for calculating the precise time
23 * from processor cycle counter (now taking lost_ticks into account) 17 * from processor cycle counter (now taking lost_ticks into account)
24 * 2000-08-13 Jan-Benedict Glaw <jbglaw@lug-owl.de>
25 * Fixed time_init to be aware of epoches != 1900. This prevents
26 * booting up in 2048 for me;) Code is stolen from rtc.c.
27 * 2003-06-03 R. Scott Bailey <scott.bailey@eds.com> 18 * 2003-06-03 R. Scott Bailey <scott.bailey@eds.com>
28 * Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM 19 * Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM
29 */ 20 */
@@ -46,7 +37,6 @@
46#include <asm/uaccess.h> 37#include <asm/uaccess.h>
47#include <asm/io.h> 38#include <asm/io.h>
48#include <asm/hwrpb.h> 39#include <asm/hwrpb.h>
49#include <asm/rtc.h>
50 40
51#include <linux/mc146818rtc.h> 41#include <linux/mc146818rtc.h>
52#include <linux/time.h> 42#include <linux/time.h>
@@ -56,8 +46,6 @@
56#include "proto.h" 46#include "proto.h"
57#include "irq_impl.h" 47#include "irq_impl.h"
58 48
59static int set_rtc_mmss(unsigned long);
60
61DEFINE_SPINLOCK(rtc_lock); 49DEFINE_SPINLOCK(rtc_lock);
62EXPORT_SYMBOL(rtc_lock); 50EXPORT_SYMBOL(rtc_lock);
63 51
@@ -108,53 +96,6 @@ static inline __u32 rpcc(void)
108 return __builtin_alpha_rpcc(); 96 return __builtin_alpha_rpcc();
109} 97}
110 98
111int update_persistent_clock(struct timespec now)
112{
113 return set_rtc_mmss(now.tv_sec);
114}
115
116void read_persistent_clock(struct timespec *ts)
117{
118 unsigned int year, mon, day, hour, min, sec, epoch;
119
120 sec = CMOS_READ(RTC_SECONDS);
121 min = CMOS_READ(RTC_MINUTES);
122 hour = CMOS_READ(RTC_HOURS);
123 day = CMOS_READ(RTC_DAY_OF_MONTH);
124 mon = CMOS_READ(RTC_MONTH);
125 year = CMOS_READ(RTC_YEAR);
126
127 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
128 sec = bcd2bin(sec);
129 min = bcd2bin(min);
130 hour = bcd2bin(hour);
131 day = bcd2bin(day);
132 mon = bcd2bin(mon);
133 year = bcd2bin(year);
134 }
135
136 /* PC-like is standard; used for year >= 70 */
137 epoch = 1900;
138 if (year < 20)
139 epoch = 2000;
140 else if (year >= 20 && year < 48)
141 /* NT epoch */
142 epoch = 1980;
143 else if (year >= 48 && year < 70)
144 /* Digital UNIX epoch */
145 epoch = 1952;
146
147 printk(KERN_INFO "Using epoch = %d\n", epoch);
148
149 if ((year += epoch) < 1970)
150 year += 100;
151
152 ts->tv_sec = mktime(year, mon, day, hour, min, sec);
153 ts->tv_nsec = 0;
154}
155
156
157
158/* 99/*
159 * timer_interrupt() needs to keep up the real-time clock, 100 * timer_interrupt() needs to keep up the real-time clock,
160 * as well as call the "xtime_update()" routine every clocktick 101 * as well as call the "xtime_update()" routine every clocktick
@@ -243,16 +184,6 @@ common_init_rtc(void)
243 init_rtc_irq(); 184 init_rtc_irq();
244} 185}
245 186
246unsigned int common_get_rtc_time(struct rtc_time *time)
247{
248 return __get_rtc_time(time);
249}
250
251int common_set_rtc_time(struct rtc_time *time)
252{
253 return __set_rtc_time(time);
254}
255
256/* Validate a computed cycle counter result against the known bounds for 187/* Validate a computed cycle counter result against the known bounds for
257 the given processor core. There's too much brokenness in the way of 188 the given processor core. There's too much brokenness in the way of
258 timing hardware for any one method to work everywhere. :-( 189 timing hardware for any one method to work everywhere. :-(
@@ -453,78 +384,3 @@ time_init(void)
453 /* Startup the timer source. */ 384 /* Startup the timer source. */
454 alpha_mv.init_rtc(); 385 alpha_mv.init_rtc();
455} 386}
456
457/*
458 * In order to set the CMOS clock precisely, set_rtc_mmss has to be
459 * called 500 ms after the second nowtime has started, because when
460 * nowtime is written into the registers of the CMOS clock, it will
461 * jump to the next second precisely 500 ms later. Check the Motorola
462 * MC146818A or Dallas DS12887 data sheet for details.
463 *
464 * BUG: This routine does not handle hour overflow properly; it just
465 * sets the minutes. Usually you won't notice until after reboot!
466 */
467
468
469static int
470set_rtc_mmss(unsigned long nowtime)
471{
472 int retval = 0;
473 int real_seconds, real_minutes, cmos_minutes;
474 unsigned char save_control, save_freq_select;
475
476 /* irq are locally disabled here */
477 spin_lock(&rtc_lock);
478 /* Tell the clock it's being set */
479 save_control = CMOS_READ(RTC_CONTROL);
480 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
481
482 /* Stop and reset prescaler */
483 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
484 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
485
486 cmos_minutes = CMOS_READ(RTC_MINUTES);
487 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
488 cmos_minutes = bcd2bin(cmos_minutes);
489
490 /*
491 * since we're only adjusting minutes and seconds,
492 * don't interfere with hour overflow. This avoids
493 * messing with unknown time zones but requires your
494 * RTC not to be off by more than 15 minutes
495 */
496 real_seconds = nowtime % 60;
497 real_minutes = nowtime / 60;
498 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) {
499 /* correct for half hour time zone */
500 real_minutes += 30;
501 }
502 real_minutes %= 60;
503
504 if (abs(real_minutes - cmos_minutes) < 30) {
505 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
506 real_seconds = bin2bcd(real_seconds);
507 real_minutes = bin2bcd(real_minutes);
508 }
509 CMOS_WRITE(real_seconds,RTC_SECONDS);
510 CMOS_WRITE(real_minutes,RTC_MINUTES);
511 } else {
512 printk_once(KERN_NOTICE
513 "set_rtc_mmss: can't update from %d to %d\n",
514 cmos_minutes, real_minutes);
515 retval = -1;
516 }
517
518 /* The following flags have to be released exactly in this order,
519 * otherwise the DS12887 (popular MC146818A clone with integrated
520 * battery and quartz) will not reset the oscillator and will not
521 * update precisely 500 ms later. You won't find this mentioned in
522 * the Dallas Semiconductor data sheets, but who believes data
523 * sheets anyway ... -- Markus Kuhn
524 */
525 CMOS_WRITE(save_control, RTC_CONTROL);
526 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
527 spin_unlock(&rtc_lock);
528
529 return retval;
530}