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