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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [include/] [asm-arm/] [arch-ebsa285/] [time.h] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1276 phoenix
/*
2
 *  linux/include/asm-arm/arch-ebsa285/time.h
3
 *
4
 *  Copyright (C) 1998 Russell King.
5
 *  Copyright (C) 1998 Phil Blundell
6
 *
7
 * CATS has a real-time clock, though the evaluation board doesn't.
8
 *
9
 * Changelog:
10
 *  21-Mar-1998 RMK     Created
11
 *  27-Aug-1998 PJB     CATS support
12
 *  28-Dec-1998 APH     Made leds optional
13
 *  20-Jan-1999 RMK     Started merge of EBSA285, CATS and NetWinder
14
 *  16-Mar-1999 RMK     More support for EBSA285-like machines with RTCs in
15
 */
16
 
17
#define RTC_PORT(x)             (rtc_base+(x))
18
#define RTC_ALWAYS_BCD          0
19
 
20
#include <linux/mc146818rtc.h>
21
 
22
#include <asm/hardware/dec21285.h>
23
#include <asm/leds.h>
24
#include <asm/mach-types.h>
25
 
26
static int rtc_base;
27
 
28
#define mSEC_10_from_14 ((14318180 + 100) / 200)
29
 
30
static unsigned long isa_gettimeoffset(void)
31
{
32
        int count;
33
 
34
        static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
35
        static unsigned long jiffies_p = 0;
36
 
37
        /*
38
         * cache volatile jiffies temporarily; we have IRQs turned off.
39
         */
40
        unsigned long jiffies_t;
41
 
42
        /* timer count may underflow right here */
43
        outb_p(0x00, 0x43);     /* latch the count ASAP */
44
 
45
        count = inb_p(0x40);    /* read the latched count */
46
 
47
        /*
48
         * We do this guaranteed double memory access instead of a _p
49
         * postfix in the previous port access. Wheee, hackady hack
50
         */
51
        jiffies_t = jiffies;
52
 
53
        count |= inb_p(0x40) << 8;
54
 
55
        /* Detect timer underflows.  If we haven't had a timer tick since
56
           the last time we were called, and time is apparently going
57
           backwards, the counter must have wrapped during this routine. */
58
        if ((jiffies_t == jiffies_p) && (count > count_p))
59
                count -= (mSEC_10_from_14/6);
60
        else
61
                jiffies_p = jiffies_t;
62
 
63
        count_p = count;
64
 
65
        count = (((mSEC_10_from_14/6)-1) - count) * tick;
66
        count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
67
 
68
        return count;
69
}
70
 
71
static void isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
72
{
73
        if (machine_is_netwinder())
74
                do_leds();
75
 
76
        do_timer(regs);
77
        do_set_rtc();
78
        do_profile(regs);
79
}
80
 
81
static unsigned long __init get_isa_cmos_time(void)
82
{
83
        unsigned int year, mon, day, hour, min, sec;
84
        int i;
85
 
86
        // check to see if the RTC makes sense.....
87
        if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0)
88
                return mktime(1970, 1, 1, 0, 0, 0);
89
 
90
        /* The Linux interpretation of the CMOS clock register contents:
91
         * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
92
         * RTC registers show the second which has precisely just started.
93
         * Let's hope other operating systems interpret the RTC the same way.
94
         */
95
        /* read RTC exactly on falling edge of update flag */
96
        for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
97
                if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
98
                        break;
99
 
100
        for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
101
                if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
102
                        break;
103
 
104
        do { /* Isn't this overkill ? UIP above should guarantee consistency */
105
                sec  = CMOS_READ(RTC_SECONDS);
106
                min  = CMOS_READ(RTC_MINUTES);
107
                hour = CMOS_READ(RTC_HOURS);
108
                day  = CMOS_READ(RTC_DAY_OF_MONTH);
109
                mon  = CMOS_READ(RTC_MONTH);
110
                year = CMOS_READ(RTC_YEAR);
111
        } while (sec != CMOS_READ(RTC_SECONDS));
112
 
113
        if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
114
                BCD_TO_BIN(sec);
115
                BCD_TO_BIN(min);
116
                BCD_TO_BIN(hour);
117
                BCD_TO_BIN(day);
118
                BCD_TO_BIN(mon);
119
                BCD_TO_BIN(year);
120
        }
121
        if ((year += 1900) < 1970)
122
                year += 100;
123
        return mktime(year, mon, day, hour, min, sec);
124
}
125
 
126
static int
127
set_isa_cmos_time(void)
128
{
129
        int retval = 0;
130
        int real_seconds, real_minutes, cmos_minutes;
131
        unsigned char save_control, save_freq_select;
132
        unsigned long nowtime = xtime.tv_sec;
133
 
134
        save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
135
        CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
136
 
137
        save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
138
        CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
139
 
140
        cmos_minutes = CMOS_READ(RTC_MINUTES);
141
        if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
142
                BCD_TO_BIN(cmos_minutes);
143
 
144
        /*
145
         * since we're only adjusting minutes and seconds,
146
         * don't interfere with hour overflow. This avoids
147
         * messing with unknown time zones but requires your
148
         * RTC not to be off by more than 15 minutes
149
         */
150
        real_seconds = nowtime % 60;
151
        real_minutes = nowtime / 60;
152
        if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
153
                real_minutes += 30;             /* correct for half hour time zone */
154
        real_minutes %= 60;
155
 
156
        if (abs(real_minutes - cmos_minutes) < 30) {
157
                if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
158
                        BIN_TO_BCD(real_seconds);
159
                        BIN_TO_BCD(real_minutes);
160
                }
161
                CMOS_WRITE(real_seconds,RTC_SECONDS);
162
                CMOS_WRITE(real_minutes,RTC_MINUTES);
163
        } else
164
                retval = -1;
165
 
166
        /* The following flags have to be released exactly in this order,
167
         * otherwise the DS12887 (popular MC146818A clone with integrated
168
         * battery and quartz) will not reset the oscillator and will not
169
         * update precisely 500 ms later. You won't find this mentioned in
170
         * the Dallas Semiconductor data sheets, but who believes data
171
         * sheets anyway ...                           -- Markus Kuhn
172
         */
173
        CMOS_WRITE(save_control, RTC_CONTROL);
174
        CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
175
 
176
        return retval;
177
}
178
 
179
 
180
 
181
static unsigned long timer1_gettimeoffset (void)
182
{
183
        unsigned long value = LATCH - *CSR_TIMER1_VALUE;
184
 
185
        return (tick * value) / LATCH;
186
}
187
 
188
static void timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
189
{
190
        *CSR_TIMER1_CLR = 0;
191
 
192
        /* Do the LEDs things */
193
        do_leds();
194
        do_timer(regs);
195
        do_set_rtc();
196
        do_profile(regs);
197
}
198
 
199
/*
200
 * Set up timer interrupt.
201
 */
202
static inline void setup_timer(void)
203
{
204
        int irq;
205
 
206
        if (machine_is_co285() ||
207
            machine_is_personal_server())
208
                /*
209
                 * Add-in 21285s shouldn't access the RTC
210
                 */
211
                rtc_base = 0;
212
        else
213
                rtc_base = 0x70;
214
 
215
        if (rtc_base) {
216
                int reg_d, reg_b;
217
 
218
                /*
219
                 * Probe for the RTC.
220
                 */
221
                reg_d = CMOS_READ(RTC_REG_D);
222
 
223
                /*
224
                 * make sure the divider is set
225
                 */
226
                CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_REG_A);
227
 
228
                /*
229
                 * Set control reg B
230
                 *   (24 hour mode, update enabled)
231
                 */
232
                reg_b = CMOS_READ(RTC_REG_B) & 0x7f;
233
                reg_b |= 2;
234
                CMOS_WRITE(reg_b, RTC_REG_B);
235
 
236
                if ((CMOS_READ(RTC_REG_A) & 0x7f) == RTC_REF_CLCK_32KHZ &&
237
                    CMOS_READ(RTC_REG_B) == reg_b) {
238
 
239
                        /*
240
                         * We have a RTC.  Check the battery
241
                         */
242
                        if ((reg_d & 0x80) == 0)
243
                                printk(KERN_WARNING "RTC: *** warning: CMOS battery bad\n");
244
 
245
                        xtime.tv_sec = get_isa_cmos_time();
246
                        set_rtc = set_isa_cmos_time;
247
                } else
248
                        rtc_base = 0;
249
        }
250
 
251
        if (machine_is_ebsa285() ||
252
            machine_is_co285() ||
253
            machine_is_personal_server()) {
254
                gettimeoffset = timer1_gettimeoffset;
255
 
256
                *CSR_TIMER1_CLR  = 0;
257
                *CSR_TIMER1_LOAD = LATCH;
258
                *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
259
 
260
                timer_irq.handler = timer1_interrupt;
261
                irq = IRQ_TIMER1;
262
        } else {
263
                /* enable PIT timer */
264
                /* set for periodic (4) and LSB/MSB write (0x30) */
265
                outb(0x34, 0x43);
266
                outb((mSEC_10_from_14/6) & 0xFF, 0x40);
267
                outb((mSEC_10_from_14/6) >> 8, 0x40);
268
 
269
                gettimeoffset = isa_gettimeoffset;
270
                timer_irq.handler = isa_timer_interrupt;
271
                irq = IRQ_ISA_TIMER;
272
        }
273
        setup_arm_irq(irq, &timer_irq);
274
}

powered by: WebSVN 2.1.0

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