File: /usr/src/linux/arch/arm/kernel/time.c
1 /*
2 * linux/arch/arm/kernel/time.c
3 *
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5 * Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This file contains the ARM-specific time handling details:
12 * reading the RTC at bootup, etc...
13 *
14 * 1994-07-02 Alan Modra
15 * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
16 * 1998-12-20 Updated NTP code according to technical memorandum Jan '96
17 * "A Kernel Model for Precision Timekeeping" by Dave Mills
18 */
19 #include <linux/config.h>
20 #include <linux/module.h>
21 #include <linux/sched.h>
22 #include <linux/kernel.h>
23 #include <linux/interrupt.h>
24 #include <linux/time.h>
25 #include <linux/init.h>
26 #include <linux/smp.h>
27
28 #include <asm/uaccess.h>
29 #include <asm/io.h>
30 #include <asm/irq.h>
31
32 #include <linux/timex.h>
33 #include <asm/hardware.h>
34
35 extern int setup_arm_irq(int, struct irqaction *);
36 extern void setup_timer(void);
37 extern rwlock_t xtime_lock;
38 extern unsigned long wall_jiffies;
39
40 /* change this if you have some constant time drift */
41 #define USECS_PER_JIFFY (1000000/HZ)
42
43 #ifndef BCD_TO_BIN
44 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
45 #endif
46
47 #ifndef BIN_TO_BCD
48 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
49 #endif
50
51 static int dummy_set_rtc(void)
52 {
53 return 0;
54 }
55
56 /*
57 * hook for setting the RTC's idea of the current time.
58 */
59 int (*set_rtc)(void) = dummy_set_rtc;
60
61 static unsigned long dummy_gettimeoffset(void)
62 {
63 return 0;
64 }
65
66 /*
67 * hook for getting the time offset. Note that it is
68 * always called with interrupts disabled.
69 */
70 unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset;
71
72 /*
73 * Handle kernel profile stuff...
74 */
75 static inline void do_profile(struct pt_regs *regs)
76 {
77 if (!user_mode(regs) &&
78 prof_buffer &&
79 current->pid) {
80 unsigned long pc = instruction_pointer(regs);
81 extern int _stext;
82
83 pc -= (unsigned long)&_stext;
84
85 pc >>= prof_shift;
86
87 if (pc >= prof_len)
88 pc = prof_len - 1;
89
90 prof_buffer[pc] += 1;
91 }
92 }
93
94 static long next_rtc_update;
95
96 /*
97 * If we have an externally synchronized linux clock, then update
98 * CMOS clock accordingly every ~11 minutes. set_rtc() has to be
99 * called as close as possible to 500 ms before the new second
100 * starts.
101 */
102 static inline void do_set_rtc(void)
103 {
104 if (time_status & STA_UNSYNC || set_rtc == NULL)
105 return;
106
107 if (next_rtc_update &&
108 time_before(xtime.tv_sec, next_rtc_update))
109 return;
110
111 if (xtime.tv_usec < 50000 - (tick >> 1) &&
112 xtime.tv_usec >= 50000 + (tick >> 1))
113 return;
114
115 if (set_rtc())
116 /*
117 * rtc update failed. Try again in 60s
118 */
119 next_rtc_update = xtime.tv_sec + 60;
120 else
121 next_rtc_update = xtime.tv_sec + 660;
122 }
123
124 #ifdef CONFIG_LEDS
125
126 #include <asm/leds.h>
127
128 static void dummy_leds_event(led_event_t evt)
129 {
130 }
131
132 void (*leds_event)(led_event_t) = dummy_leds_event;
133
134 #ifdef CONFIG_MODULES
135 EXPORT_SYMBOL(leds_event);
136 #endif
137 #endif
138
139 #ifdef CONFIG_LEDS_TIMER
140 static void do_leds(void)
141 {
142 static unsigned int count = 50;
143
144 if (--count == 0) {
145 count = 50;
146 leds_event(led_timer);
147 }
148 }
149 #else
150 #define do_leds()
151 #endif
152
153 void do_gettimeofday(struct timeval *tv)
154 {
155 unsigned long flags;
156 unsigned long usec, sec;
157
158 read_lock_irqsave(&xtime_lock, flags);
159 usec = gettimeoffset();
160 {
161 unsigned long lost = jiffies - wall_jiffies;
162
163 if (lost)
164 usec += lost * USECS_PER_JIFFY;
165 }
166 sec = xtime.tv_sec;
167 usec += xtime.tv_usec;
168 read_unlock_irqrestore(&xtime_lock, flags);
169
170 /* usec may have gone up a lot: be safe */
171 while (usec >= 1000000) {
172 usec -= 1000000;
173 sec++;
174 }
175
176 tv->tv_sec = sec;
177 tv->tv_usec = usec;
178 }
179
180 void do_settimeofday(struct timeval *tv)
181 {
182 write_lock_irq(&xtime_lock);
183 /* This is revolting. We need to set the xtime.tv_usec
184 * correctly. However, the value in this location is
185 * is value at the last tick.
186 * Discover what correction gettimeofday
187 * would have done, and then undo it!
188 */
189 tv->tv_usec -= gettimeoffset();
190 tv->tv_usec -= (jiffies - wall_jiffies) * USECS_PER_JIFFY;
191
192 while (tv->tv_usec < 0) {
193 tv->tv_usec += 1000000;
194 tv->tv_sec--;
195 }
196
197 xtime = *tv;
198 time_adjust = 0; /* stop active adjtime() */
199 time_status |= STA_UNSYNC;
200 time_maxerror = NTP_PHASE_LIMIT;
201 time_esterror = NTP_PHASE_LIMIT;
202 write_unlock_irq(&xtime_lock);
203 }
204
205 static struct irqaction timer_irq = {
206 name: "timer",
207 };
208
209 /*
210 * Include architecture specific code
211 */
212 #include <asm/arch/time.h>
213
214 /*
215 * This must cause the timer to start ticking.
216 * It doesn't have to set the current time though
217 * from an RTC - it can be done later once we have
218 * some buses initialised.
219 */
220 void __init time_init(void)
221 {
222 xtime.tv_usec = 0;
223 xtime.tv_sec = 0;
224
225 setup_timer();
226 }
227