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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [mips/] [vr41xx/] [common/] [rtc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  rtc.c, RTC(has only timer function) routines for NEC VR4100 series.
3
 *
4
 *  Copyright (C) 2003  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
#include <linux/init.h>
21
#include <linux/irq.h>
22
#include <linux/types.h>
23
 
24
#include <asm/io.h>
25
#include <asm/time.h>
26
#include <asm/vr41xx/vr41xx.h>
27
 
28
static uint32_t rtc1_base;
29
static uint32_t rtc2_base;
30
 
31
static uint64_t previous_elapsedtime;
32
static unsigned int remainder_per_sec;
33
static unsigned int cycles_per_sec;
34
static unsigned int cycles_per_jiffy;
35
static unsigned long epoch_time;
36
 
37
#define CLOCK_TICK_RATE         32768   /* 32.768kHz */
38
 
39
#define CYCLES_PER_JIFFY        (CLOCK_TICK_RATE / HZ)
40
#define REMAINDER_PER_SEC       (CLOCK_TICK_RATE - (CYCLES_PER_JIFFY * HZ))
41
#define CYCLES_PER_100USEC      ((CLOCK_TICK_RATE + (10000 / 2)) / 10000)
42
 
43
#define ETIMELREG_TYPE1         KSEG1ADDR(0x0b0000c0)
44
#define TCLKLREG_TYPE1          KSEG1ADDR(0x0b0001c0)
45
 
46
#define ETIMELREG_TYPE2         KSEG1ADDR(0x0f000100)
47
#define TCLKLREG_TYPE2          KSEG1ADDR(0x0f000120)
48
 
49
/* RTC 1 registers */
50
#define ETIMELREG               0x00
51
#define ETIMEMREG               0x02
52
#define ETIMEHREG               0x04
53
/* RFU */
54
#define ECMPLREG                0x08
55
#define ECMPMREG                0x0a
56
#define ECMPHREG                0x0c
57
/* RFU */
58
#define RTCL1LREG               0x10
59
#define RTCL1HREG               0x12
60
#define RTCL1CNTLREG            0x14
61
#define RTCL1CNTHREG            0x16
62
#define RTCL2LREG               0x18
63
#define RTCL2HREG               0x1a
64
#define RTCL2CNTLREG            0x1c
65
#define RTCL2CNTHREG            0x1e
66
 
67
/* RTC 2 registers */
68
#define TCLKLREG                0x00
69
#define TCLKHREG                0x02
70
#define TCLKCNTLREG             0x04
71
#define TCLKCNTHREG             0x06
72
/* RFU */
73
#define RTCINTREG               0x1e
74
 #define TCLOCK_INT             0x08
75
 #define RTCLONG2_INT           0x04
76
 #define RTCLONG1_INT           0x02
77
 #define ELAPSEDTIME_INT        0x01
78
 
79
#define read_rtc1(offset)       readw(rtc1_base + (offset))
80
#define write_rtc1(val, offset) writew((val), rtc1_base + (offset))
81
 
82
#define read_rtc2(offset)       readw(rtc2_base + (offset))
83
#define write_rtc2(val, offset) writew((val), rtc2_base + (offset))
84
 
85
static inline uint64_t read_elapsedtime_counter(void)
86
{
87
        uint64_t first, second;
88
        uint32_t first_mid, first_low;
89
        uint32_t second_mid, second_low;
90
 
91
        do {
92
                first_low = (uint32_t)read_rtc1(ETIMELREG);
93
                first_mid = (uint32_t)read_rtc1(ETIMEMREG);
94
                first = (uint64_t)read_rtc1(ETIMEHREG);
95
                second_low = (uint32_t)read_rtc1(ETIMELREG);
96
                second_mid = (uint32_t)read_rtc1(ETIMEMREG);
97
                second = (uint64_t)read_rtc1(ETIMEHREG);
98
        } while (first_low != second_low || first_mid != second_mid ||
99
                 first != second);
100
 
101
        return (first << 32) | (uint64_t)((first_mid << 16) | first_low);
102
}
103
 
104
static inline void write_elapsedtime_counter(uint64_t time)
105
{
106
        write_rtc1((uint16_t)time, ETIMELREG);
107
        write_rtc1((uint16_t)(time >> 16), ETIMEMREG);
108
        write_rtc1((uint16_t)(time >> 32), ETIMEHREG);
109
}
110
 
111
static inline void write_elapsedtime_compare(uint64_t time)
112
{
113
        write_rtc1((uint16_t)time, ECMPLREG);
114
        write_rtc1((uint16_t)(time >> 16), ECMPMREG);
115
        write_rtc1((uint16_t)(time >> 32), ECMPHREG);
116
}
117
 
118
void vr41xx_set_rtclong1_cycle(uint32_t cycles)
119
{
120
        write_rtc1((uint16_t)cycles, RTCL1LREG);
121
        write_rtc1((uint16_t)(cycles >> 16), RTCL1HREG);
122
}
123
 
124
uint32_t vr41xx_read_rtclong1_counter(void)
125
{
126
        uint32_t first_high, first_low;
127
        uint32_t second_high, second_low;
128
 
129
        do {
130
                first_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
131
                first_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
132
                second_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
133
                second_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
134
        } while (first_low != second_low || first_high != second_high);
135
 
136
        return (first_high << 16) | first_low;
137
}
138
 
139
void vr41xx_set_rtclong2_cycle(uint32_t cycles)
140
{
141
        write_rtc1((uint16_t)cycles, RTCL2LREG);
142
        write_rtc1((uint16_t)(cycles >> 16), RTCL2HREG);
143
}
144
 
145
uint32_t vr41xx_read_rtclong2_counter(void)
146
{
147
        uint32_t first_high, first_low;
148
        uint32_t second_high, second_low;
149
 
150
        do {
151
                first_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
152
                first_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
153
                second_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
154
                second_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
155
        } while (first_low != second_low || first_high != second_high);
156
 
157
        return (first_high << 16) | first_low;
158
}
159
 
160
void vr41xx_set_tclock_cycle(uint32_t cycles)
161
{
162
        write_rtc2((uint16_t)cycles, TCLKLREG);
163
        write_rtc2((uint16_t)(cycles >> 16), TCLKHREG);
164
}
165
 
166
uint32_t vr41xx_read_tclock_counter(void)
167
{
168
        uint32_t first_high, first_low;
169
        uint32_t second_high, second_low;
170
 
171
        do {
172
                first_low = (uint32_t)read_rtc2(TCLKCNTLREG);
173
                first_high = (uint32_t)read_rtc2(TCLKCNTHREG);
174
                second_low = (uint32_t)read_rtc2(TCLKCNTLREG);
175
                second_high = (uint32_t)read_rtc2(TCLKCNTHREG);
176
        } while (first_low != second_low || first_high != second_high);
177
 
178
        return (first_high << 16) | first_low;
179
}
180
 
181
static void vr41xx_timer_ack(void)
182
{
183
        uint64_t cur;
184
 
185
        write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
186
 
187
        previous_elapsedtime += (uint64_t)cycles_per_jiffy;
188
        cycles_per_sec += cycles_per_jiffy;
189
 
190
        if (cycles_per_sec >= CLOCK_TICK_RATE) {
191
                cycles_per_sec = 0;
192
                remainder_per_sec = REMAINDER_PER_SEC;
193
        }
194
 
195
        cycles_per_jiffy = 0;
196
 
197
        do {
198
                cycles_per_jiffy += CYCLES_PER_JIFFY;
199
                if (remainder_per_sec > 0) {
200
                        cycles_per_jiffy++;
201
                        remainder_per_sec--;
202
                }
203
 
204
                cur = read_elapsedtime_counter();
205
        } while (cur >= previous_elapsedtime + (uint64_t)cycles_per_jiffy);
206
 
207
        write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
208
}
209
 
210
static void vr41xx_hpt_init(unsigned int count)
211
{
212
}
213
 
214
static unsigned int vr41xx_hpt_read(void)
215
{
216
        uint64_t cur;
217
 
218
        cur = read_elapsedtime_counter();
219
 
220
        return (unsigned int)cur;
221
}
222
 
223
static unsigned long vr41xx_gettimeoffset(void)
224
{
225
        uint64_t cur;
226
        unsigned long gap;
227
 
228
        cur = read_elapsedtime_counter();
229
        gap = (unsigned long)(cur - previous_elapsedtime);
230
        gap = gap / CYCLES_PER_100USEC * 100;   /* usec */
231
 
232
        return gap;
233
}
234
 
235
static unsigned long vr41xx_get_time(void)
236
{
237
        uint64_t counts;
238
 
239
        counts = read_elapsedtime_counter();
240
        counts >>= 15;
241
 
242
        return epoch_time + (unsigned long)counts;
243
 
244
}
245
 
246
static int vr41xx_set_time(unsigned long sec)
247
{
248
        if (sec < epoch_time)
249
                return -EINVAL;
250
 
251
        sec -= epoch_time;
252
 
253
        write_elapsedtime_counter((uint64_t)sec << 15);
254
 
255
        return 0;
256
}
257
 
258
void vr41xx_set_epoch_time(unsigned long time)
259
{
260
        epoch_time = time;
261
}
262
 
263
void __init vr41xx_time_init(void)
264
{
265
        switch (current_cpu_data.cputype) {
266
        case CPU_VR4111:
267
        case CPU_VR4121:
268
                rtc1_base = ETIMELREG_TYPE1;
269
                rtc2_base = TCLKLREG_TYPE1;
270
                break;
271
        case CPU_VR4122:
272
        case CPU_VR4131:
273
        case CPU_VR4133:
274
                rtc1_base = ETIMELREG_TYPE2;
275
                rtc2_base = TCLKLREG_TYPE2;
276
                break;
277
        default:
278
                panic("Unexpected CPU of NEC VR4100 series");
279
                break;
280
        }
281
 
282
        mips_timer_ack = vr41xx_timer_ack;
283
 
284
        mips_hpt_init = vr41xx_hpt_init;
285
        mips_hpt_read = vr41xx_hpt_read;
286
        mips_hpt_frequency = CLOCK_TICK_RATE;
287
 
288
        if (epoch_time == 0)
289
                epoch_time = mktime(1970, 1, 1, 0, 0, 0);
290
 
291
        rtc_get_time = vr41xx_get_time;
292
        rtc_set_time = vr41xx_set_time;
293
}
294
 
295
void __init vr41xx_timer_setup(struct irqaction *irq)
296
{
297
        do_gettimeoffset = vr41xx_gettimeoffset;
298
 
299
        remainder_per_sec = REMAINDER_PER_SEC;
300
        cycles_per_jiffy = CYCLES_PER_JIFFY;
301
 
302
        if (remainder_per_sec > 0) {
303
                cycles_per_jiffy++;
304
                remainder_per_sec--;
305
        }
306
 
307
        previous_elapsedtime = read_elapsedtime_counter();
308
        write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
309
        write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
310
 
311
        setup_irq(ELAPSEDTIME_IRQ, irq);
312
}

powered by: WebSVN 2.1.0

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