OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [mips/] [kernel/] [time.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1624 jcastillo
/*
2
 *  linux/arch/mips/kernel/time.c
3
 *
4
 *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
5
 *
6
 * This file contains the time handling details for PC-style clocks as
7
 * found in some MIPS systems.
8
 */
9
#include <linux/errno.h>
10
#include <linux/sched.h>
11
#include <linux/kernel.h>
12
#include <linux/param.h>
13
#include <linux/string.h>
14
#include <linux/mm.h>
15
 
16
#include <asm/segment.h>
17
#include <asm/io.h>
18
 
19
#include <linux/mc146818rtc.h>
20
#include <linux/timex.h>
21
 
22
#define TIMER_IRQ 0
23
 
24
/* This function must be called with interrupts disabled
25
 * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
26
 *
27
 * However, the pc-audio speaker driver changes the divisor so that
28
 * it gets interrupted rather more often - it loads 64 into the
29
 * counter rather than 11932! This has an adverse impact on
30
 * do_gettimeoffset() -- it stops working! What is also not
31
 * good is that the interval that our timer function gets called
32
 * is no longer 10.0002 ms, but 9.9767 ms. To get around this
33
 * would require using a different timing source. Maybe someone
34
 * could use the RTC - I know that this can interrupt at frequencies
35
 * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
36
 * it so that at startup, the timer code in sched.c would select
37
 * using either the RTC or the 8253 timer. The decision would be
38
 * based on whether there was any other device around that needed
39
 * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
40
 * and then do some jiggery to have a version of do_timer that
41
 * advanced the clock by 1/1024 s. Every time that reached over 1/100
42
 * of a second, then do all the old code. If the time was kept correct
43
 * then do_gettimeoffset could just return 0 - there is no low order
44
 * divider that can be accessed.
45
 *
46
 * Ideally, you would be able to use the RTC for the speaker driver,
47
 * but it appears that the speaker driver really needs interrupt more
48
 * often than every 120 us or so.
49
 *
50
 * Anyway, this needs more thought....          pjsg (1993-08-28)
51
 *
52
 * If you are really that interested, you should be reading
53
 * comp.protocols.time.ntp!
54
 */
55
 
56
#define TICK_SIZE tick
57
 
58
static unsigned long do_slow_gettimeoffset(void)
59
{
60
        int count;
61
        unsigned long offset = 0;
62
 
63
        /* timer count may underflow right here */
64
        outb_p(0x00, 0x43);     /* latch the count ASAP */
65
        count = inb_p(0x40);    /* read the latched count */
66
        count |= inb(0x40) << 8;
67
        /* we know probability of underflow is always MUCH less than 1% */
68
        if (count > (LATCH - LATCH/100)) {
69
                /* check for pending timer interrupt */
70
                outb_p(0x0a, 0x20);
71
                if (inb(0x20) & 1)
72
                        offset = TICK_SIZE;
73
        }
74
        count = ((LATCH-1) - count) * TICK_SIZE;
75
        count = (count + LATCH/2) / LATCH;
76
        return offset + count;
77
}
78
 
79
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
80
 
81
/*
82
 * This version of gettimeofday has near microsecond resolution.
83
 */
84
void do_gettimeofday(struct timeval *tv)
85
{
86
        unsigned long flags;
87
 
88
        save_flags(flags);
89
        cli();
90
        *tv = xtime;
91
        tv->tv_usec += do_gettimeoffset();
92
        if (tv->tv_usec >= 1000000) {
93
                tv->tv_usec -= 1000000;
94
                tv->tv_sec++;
95
        }
96
        restore_flags(flags);
97
}
98
 
99
void do_settimeofday(struct timeval *tv)
100
{
101
        cli();
102
        /* This is revolting. We need to set the xtime.tv_usec
103
         * correctly. However, the value in this location is
104
         * is value at the last tick.
105
         * Discover what correction gettimeofday
106
         * would have done, and then undo it!
107
         */
108
        tv->tv_usec -= do_gettimeoffset();
109
 
110
        if (tv->tv_usec < 0) {
111
                tv->tv_usec += 1000000;
112
                tv->tv_sec--;
113
        }
114
 
115
        xtime = *tv;
116
        time_state = TIME_BAD;
117
        time_maxerror = 0x70000000;
118
        time_esterror = 0x70000000;
119
        sti();
120
}
121
 
122
/*
123
 * In order to set the CMOS clock precisely, set_rtc_mmss has to be
124
 * called 500 ms after the second nowtime has started, because when
125
 * nowtime is written into the registers of the CMOS clock, it will
126
 * jump to the next second precisely 500 ms later. Check the Motorola
127
 * MC146818A or Dallas DS12887 data sheet for details.
128
 */
129
static int set_rtc_mmss(unsigned long nowtime)
130
{
131
        int retval = 0;
132
        int real_seconds, real_minutes, cmos_minutes;
133
        unsigned char save_control, save_freq_select;
134
 
135
        save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
136
        CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
137
 
138
        save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
139
        CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
140
 
141
        cmos_minutes = CMOS_READ(RTC_MINUTES);
142
        if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
143
                BCD_TO_BIN(cmos_minutes);
144
 
145
        /*
146
         * since we're only adjusting minutes and seconds,
147
         * don't interfere with hour overflow. This avoids
148
         * messing with unknown time zones but requires your
149
         * RTC not to be off by more than 15 minutes
150
         */
151
        real_seconds = nowtime % 60;
152
        real_minutes = nowtime / 60;
153
        if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
154
                real_minutes += 30;             /* correct for half hour time zone */
155
        real_minutes %= 60;
156
 
157
        if (abs(real_minutes - cmos_minutes) < 30) {
158
                if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
159
                        BIN_TO_BCD(real_seconds);
160
                        BIN_TO_BCD(real_minutes);
161
                }
162
                CMOS_WRITE(real_seconds,RTC_SECONDS);
163
                CMOS_WRITE(real_minutes,RTC_MINUTES);
164
        } else
165
                retval = -1;
166
 
167
        /* The following flags have to be released exactly in this order,
168
         * otherwise the DS12887 (popular MC146818A clone with integrated
169
         * battery and crystal) will not reset the oscillator and will not
170
         * update precisely 500 ms later. You won't find this mentioned in
171
         * the Dallas Semiconductor data sheets, but who believes data
172
         * sheets anyway ...                           -- Markus Kuhn
173
         */
174
        CMOS_WRITE(save_control, RTC_CONTROL);
175
        CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
176
 
177
        return retval;
178
}
179
 
180
/* last time the cmos clock got updated */
181
static long last_rtc_update = 0;
182
 
183
/*
184
 * timer_interrupt() needs to keep up the real-time clock,
185
 * as well as call the "do_timer()" routine every clocktick
186
 */
187
static void timer_interrupt(int irq, struct pt_regs * regs)
188
{
189
        do_timer(regs);
190
 
191
        /*
192
         * If we have an externally synchronized Linux clock, then update
193
         * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
194
         * called as close as possible to 500 ms before the new second starts.
195
         */
196
        if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
197
            xtime.tv_usec > 500000 - (tick >> 1) &&
198
            xtime.tv_usec < 500000 + (tick >> 1))
199
          if (set_rtc_mmss(xtime.tv_sec) == 0)
200
            last_rtc_update = xtime.tv_sec;
201
          else
202
            last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
203
        /* As we return to user mode fire off the other CPU schedulers.. this is
204
           basically because we don't yet share IRQ's around. This message is
205
           rigged to be safe on the 386 - basically it's a hack, so don't look
206
           closely for now.. */
207
        smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
208
}
209
 
210
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
211
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
212
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
213
 *
214
 * [For the Julian calendar (which was used in Russia before 1917,
215
 * Britain & colonies before 1752, anywhere else before 1582,
216
 * and is still in use by some communities) leave out the
217
 * -year/100+year/400 terms, and add 10.]
218
 *
219
 * This algorithm was first published by Gauss (I think).
220
 *
221
 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
222
 * machines were long is 32-bit! (However, as time_t is signed, we
223
 * will already get problems at other places on 2038-01-19 03:14:08)
224
 */
225
static inline unsigned long mktime(unsigned int year, unsigned int mon,
226
        unsigned int day, unsigned int hour,
227
        unsigned int min, unsigned int sec)
228
{
229
        if (0 >= (int) (mon -= 2)) {     /* 1..12 -> 11,12,1..10 */
230
                mon += 12;      /* Puts Feb last since it has leap day */
231
                year -= 1;
232
        }
233
        return (((
234
            (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
235
              year*365 - 719499
236
            )*24 + hour /* now have hours */
237
           )*60 + min /* now have minutes */
238
          )*60 + sec; /* finally seconds */
239
}
240
 
241
void time_init(void)
242
{
243
        void (*irq_handler)(int, struct pt_regs *);
244
        unsigned int year, mon, day, hour, min, sec;
245
        int i;
246
 
247
        /* The Linux interpretation of the CMOS clock register contents:
248
         * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
249
         * RTC registers show the second which has precisely just started.
250
         * Let's hope other operating systems interpret the RTC the same way.
251
         */
252
        /* read RTC exactly on falling edge of update flag */
253
        for (i = 0 ; i < 1000000 ; i++)  /* may take up to 1 second... */
254
                if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
255
                        break;
256
        for (i = 0 ; i < 1000000 ; i++)  /* must try at least 2.228 ms */
257
                if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
258
                        break;
259
        do { /* Isn't this overkill ? UIP above should guarantee consistency */
260
                sec = CMOS_READ(RTC_SECONDS);
261
                min = CMOS_READ(RTC_MINUTES);
262
                hour = CMOS_READ(RTC_HOURS);
263
                day = CMOS_READ(RTC_DAY_OF_MONTH);
264
                mon = CMOS_READ(RTC_MONTH);
265
                year = CMOS_READ(RTC_YEAR);
266
        } while (sec != CMOS_READ(RTC_SECONDS));
267
        if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
268
          {
269
            BCD_TO_BIN(sec);
270
            BCD_TO_BIN(min);
271
            BCD_TO_BIN(hour);
272
            BCD_TO_BIN(day);
273
            BCD_TO_BIN(mon);
274
            BCD_TO_BIN(year);
275
          }
276
        if ((year += 1900) < 1970)
277
                year += 100;
278
        xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
279
        xtime.tv_usec = 0;
280
 
281
        /* FIXME: If we have the CPU hardware time counters, use them */
282
        irq_handler = timer_interrupt;
283
 
284
        if (request_irq(TIMER_IRQ, irq_handler, 0, "timer") != 0)
285
                panic("Could not allocate timer IRQ!");
286
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.