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 rwlock_t xtime_lock;
37 extern unsigned long wall_jiffies;
38
39 /* change this if you have some constant time drift */
40 #define USECS_PER_JIFFY (1000000/HZ)
41
42 #ifndef BCD_TO_BIN
43 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
44 #endif
45
46 #ifndef BIN_TO_BCD
47 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
48 #endif
49
dummy_set_rtc(void)50 static int dummy_set_rtc(void)
51 {
52 return 0;
53 }
54
55 /*
56 * hook for setting the RTC's idea of the current time.
57 */
58 int (*set_rtc)(void) = dummy_set_rtc;
59
dummy_gettimeoffset(void)60 static unsigned long dummy_gettimeoffset(void)
61 {
62 return 0;
63 }
64
65 /*
66 * hook for getting the time offset. Note that it is
67 * always called with interrupts disabled.
68 */
69 unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset;
70
71 /*
72 * Handle kernel profile stuff...
73 */
do_profile(struct pt_regs * regs)74 static inline void do_profile(struct pt_regs *regs)
75 {
76 if (!user_mode(regs) &&
77 prof_buffer &&
78 current->pid) {
79 unsigned long pc = instruction_pointer(regs);
80 extern int _stext;
81
82 pc -= (unsigned long)&_stext;
83
84 pc >>= prof_shift;
85
86 if (pc >= prof_len)
87 pc = prof_len - 1;
88
89 prof_buffer[pc] += 1;
90 }
91 }
92
93 static long next_rtc_update;
94
95 /*
96 * If we have an externally synchronized linux clock, then update
97 * CMOS clock accordingly every ~11 minutes. set_rtc() has to be
98 * called as close as possible to 500 ms before the new second
99 * starts.
100 */
do_set_rtc(void)101 static inline void do_set_rtc(void)
102 {
103 if (time_status & STA_UNSYNC || set_rtc == NULL)
104 return;
105
106 if (next_rtc_update &&
107 time_before(xtime.tv_sec, next_rtc_update))
108 return;
109
110 if (xtime.tv_usec < 50000 - (tick >> 1) &&
111 xtime.tv_usec >= 50000 + (tick >> 1))
112 return;
113
114 if (set_rtc())
115 /*
116 * rtc update failed. Try again in 60s
117 */
118 next_rtc_update = xtime.tv_sec + 60;
119 else
120 next_rtc_update = xtime.tv_sec + 660;
121 }
122
123 #ifdef CONFIG_LEDS
124
125 #include <asm/leds.h>
126
dummy_leds_event(led_event_t evt)127 static void dummy_leds_event(led_event_t evt)
128 {
129 }
130
131 void (*leds_event)(led_event_t) = dummy_leds_event;
132
133 #ifdef CONFIG_MODULES
134 EXPORT_SYMBOL(leds_event);
135 #endif
136 #endif
137
138 #ifdef CONFIG_LEDS_TIMER
do_leds(void)139 static void do_leds(void)
140 {
141 static unsigned int count = 50;
142
143 if (--count == 0) {
144 count = 50;
145 leds_event(led_timer);
146 }
147 }
148 #else
149 #define do_leds()
150 #endif
151
do_gettimeofday(struct timeval * tv)152 void do_gettimeofday(struct timeval *tv)
153 {
154 unsigned long flags;
155 unsigned long usec, sec;
156
157 read_lock_irqsave(&xtime_lock, flags);
158 usec = gettimeoffset();
159 {
160 unsigned long lost = jiffies - wall_jiffies;
161
162 if (lost)
163 usec += lost * USECS_PER_JIFFY;
164 }
165 sec = xtime.tv_sec;
166 usec += xtime.tv_usec;
167 read_unlock_irqrestore(&xtime_lock, flags);
168
169 /* usec may have gone up a lot: be safe */
170 while (usec >= 1000000) {
171 usec -= 1000000;
172 sec++;
173 }
174
175 tv->tv_sec = sec;
176 tv->tv_usec = usec;
177 }
178
do_settimeofday(struct timeval * tv)179 void do_settimeofday(struct timeval *tv)
180 {
181 write_lock_irq(&xtime_lock);
182 /* This is revolting. We need to set the xtime.tv_usec
183 * correctly. However, the value in this location is
184 * is value at the last tick.
185 * Discover what correction gettimeofday
186 * would have done, and then undo it!
187 */
188 tv->tv_usec -= gettimeoffset();
189 tv->tv_usec -= (jiffies - wall_jiffies) * USECS_PER_JIFFY;
190
191 while (tv->tv_usec < 0) {
192 tv->tv_usec += 1000000;
193 tv->tv_sec--;
194 }
195
196 xtime = *tv;
197 time_adjust = 0; /* stop active adjtime() */
198 time_status |= STA_UNSYNC;
199 time_maxerror = NTP_PHASE_LIMIT;
200 time_esterror = NTP_PHASE_LIMIT;
201 write_unlock_irq(&xtime_lock);
202 }
203
204 static struct irqaction timer_irq = {
205 .name = "timer",
206 .flags = SA_INTERRUPT,
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 */
time_init(void)220 void __init time_init(void)
221 {
222 xtime.tv_usec = 0;
223 xtime.tv_sec = 0;
224
225 setup_timer();
226 }
227