rtc.c revision 1.3 1 /* $NetBSD: rtc.c,v 1.3 2000/01/17 04:06:06 sato Exp $ */
2
3 /*-
4 * Copyright (c) 1999 Shin Takemura. All rights reserved.
5 * Copyright (c) 1999 SATO Kazumi. All rights reserved.
6 * Copyright (c) 1999 PocketBSD Project. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the PocketBSD project
19 * and its contributors.
20 * 4. Neither the name of the project nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/reboot.h>
42
43 #include <machine/bus.h>
44 #include <machine/clock_machdep.h>
45 #include <machine/cpu.h>
46
47 #include <hpcmips/vr/vr.h>
48 #include <hpcmips/vr/vripvar.h>
49 #include <hpcmips/vr/rtcreg.h>
50 #include <dev/dec/clockvar.h>
51
52 /*
53 * for debugging definitions
54 * RTCDEBUG print rtc debugging infomation
55 * RTC_HEARTBEAT print HEARTBEAT (too many print...)
56 */
57
58 struct vrrtc_softc {
59 struct device sc_dev;
60 bus_space_tag_t sc_iot;
61 bus_space_handle_t sc_ioh;
62 void *sc_ih;
63 };
64
65 void clock_init __P((struct device *));
66 void clock_get __P((struct device *, time_t, struct clocktime *));
67 void clock_set __P((struct device *, struct clocktime *));
68
69 static const struct clockfns clockfns = {
70 clock_init, clock_get, clock_set,
71 };
72
73 int vrrtc_match __P((struct device *, struct cfdata *, void *));
74 void vrrtc_attach __P((struct device *, struct device *, void *));
75 int vrrtc_intr __P((void*, u_int32_t, u_int32_t));
76
77 struct cfattach vrrtc_ca = {
78 sizeof(struct vrrtc_softc), vrrtc_match, vrrtc_attach
79 };
80
81 void vrrtc_write __P((struct vrrtc_softc *, int, unsigned short));
82 unsigned short vrrtc_read __P((struct vrrtc_softc *, int));
83 void cvt_timehl_ct __P((u_long, u_long, struct clocktime *));
84
85 extern int rtc_offset;
86
87 int
88 vrrtc_match(parent, cf, aux)
89 struct device *parent;
90 struct cfdata *cf;
91 void *aux;
92 {
93 return(1);
94 }
95
96 inline void
97 vrrtc_write(sc, port, val)
98 struct vrrtc_softc *sc;
99 int port;
100 unsigned short val;
101 {
102 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
103 }
104
105 inline unsigned short
106 vrrtc_read(sc, port)
107 struct vrrtc_softc *sc;
108 int port;
109 {
110 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
111 }
112
113 void
114 vrrtc_attach(parent, self, aux)
115 struct device *parent;
116 struct device *self;
117 void *aux;
118 {
119 struct vrip_attach_args *va = aux;
120 struct vrrtc_softc *sc = (void*)self;
121
122 sc->sc_iot = va->va_iot;
123 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
124 0 /* no flags */, &sc->sc_ioh)) {
125 printf("vrrtc_attach: can't map i/o space\n");
126 return;
127 }
128 /* RTC interrupt handler is directly dispatched from CPU intr */
129 vr_intr_establish(VR_INTR1, vrrtc_intr, sc);
130 /* But need to set level 1 interupt mask register,
131 * so regsiter fake interrurpt handler
132 */
133 if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_intr,
134 IPL_CLOCK, 0, 0))) {
135 printf (":can't map interrupt.\n");
136 return;
137 }
138 /*
139 * Rtc is attached to call this routine
140 * before cpu_initclock() calls clock_init().
141 * So we must disable all interrupt for now.
142 */
143 /*
144 * Disable all rtc interrupts
145 */
146 /* Disable Elapse compare intr */
147 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W, 0);
148 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W, 0);
149 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W, 0);
150 /* Disable RTC Long1 intr */
151 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0);
152 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W, 0);
153 /* Disable RTC Long2 intr */
154 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W, 0);
155 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W, 0);
156 /* Disable RTC TCLK intr */
157 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W, 0);
158 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W, 0);
159 /*
160 * Clear all rtc intrrupts.
161 */
162 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL);
163
164 clockattach(&sc->sc_dev, &clockfns);
165 }
166
167 int
168 vrrtc_intr(arg, pc, statusReg)
169 void *arg;
170 u_int32_t pc;
171 u_int32_t statusReg;
172 {
173 struct vrrtc_softc *sc = arg;
174 struct clockframe cf;
175
176 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL);
177 cf.pc = pc;
178 cf.sr = statusReg;
179 hardclock(&cf);
180 intrcnt[HARDCLOCK]++;
181
182 #ifdef RTC_HEARTBEAT
183 if ((intrcnt[HARDCLOCK] % (CLOCK_RATE * 5)) == 0) {
184 struct clocktime ct;
185 clock_get((struct device *)sc, NULL, &ct);
186 printf("%s(%d): rtc_intr: %2d.%2d.%2d %02d:%02d:%02d\n",
187 __FILE__, __LINE__,
188 ct.year, ct.mon, ct.day,
189 ct.hour, ct.min, ct.sec);
190 }
191 #endif
192 return 0;
193 }
194
195 void
196 clock_init(dev)
197 struct device *dev;
198 {
199 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev;
200 #ifdef RTCDEBUG
201 int timeh;
202 int timel;
203
204 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W);
205 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W);
206 timel = (timel << 16)
207 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W);
208 printf("clock_init() Elapse Time %04x%04x\n", timeh, timel);
209
210 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W);
211 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W);
212 timel = (timel << 16)
213 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W);
214 printf("clock_init() Elapse Compare %04x%04x\n", timeh, timel);
215
216 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W);
217 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W);
218 printf("clock_init() LONG1 %04x%04x\n", timeh, timel);
219
220 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_H_REG_W);
221 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_L_REG_W);
222 printf("clock_init() LONG1 CNTL %04x%04x\n", timeh, timel);
223
224 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W);
225 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W);
226 printf("clock_init() LONG2 %04x%04x\n", timeh, timel);
227
228 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_H_REG_W);
229 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_L_REG_W);
230 printf("clock_init() LONG2 CNTL %04x%04x\n", timeh, timel);
231
232 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W);
233 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W);
234 printf("clock_init() TCLK %04x%04x\n", timeh, timel);
235
236 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_H_REG_W);
237 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_L_REG_W);
238 printf("clock_init() TCLK CNTL %04x%04x\n", timeh, timel);
239 #endif /* RTCDEBUG */
240 /*
241 * Set tick (CLOCK_RATE)
242 */
243 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0);
244 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
245 RTCL1_L_REG_W, RTCL1_L_HZ/CLOCK_RATE);
246 }
247
248 static int m2d[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
249
250 void
251 cvt_timehl_ct(timeh, timel, ct)
252 u_long timeh; /* 2 sec */
253 u_long timel; /* 1/32768 sec */
254 struct clocktime *ct;
255 {
256 u_long year, month, date, hour, min, sec, sec2;
257
258 timeh -= EPOCHOFF;
259
260 timeh += (rtc_offset*SEC2MIN);
261
262 year = EPOCHYEAR;
263 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
264 while (timeh > sec2) {
265 year++;
266 timeh -= sec2;
267 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
268 }
269
270 #ifdef RTCDEBUG
271 printf("cvt_timehl_ct: timeh %08lx year %ld yrref %ld\n",
272 timeh, year, sec2);
273 #endif /* RTCDEBUG */
274
275 month = 0; /* now month is 0..11 */
276 sec2 = SEC2DAY * m2d[month];
277 while (timeh > sec2) {
278 timeh -= sec2;
279 month++;
280 sec2 = SEC2DAY * m2d[month];
281 if (month == 1 && LEAPYEAR4(year)) /* feb. and leapyear */
282 sec2 += SEC2DAY;
283 }
284 month +=1; /* now month is 1..12 */
285
286 #ifdef RTCDEBUG
287 printf("cvt_timehl_ct: timeh %08lx month %ld mref %ld\n",
288 timeh, month, sec2);
289 #endif /* RTCDEBUG */
290
291 sec2 = SEC2DAY;
292 date = timeh/sec2+1; /* date is 1..31 */
293 timeh -= (date-1)*sec2;
294
295 #ifdef RTCDEBUG
296 printf("cvt_timehl_ct: timeh %08lx date %ld dref %ld\n",
297 timeh, date, sec2);
298 #endif /* RTCDEBUG */
299
300 sec2 = SEC2HOUR;
301 hour = timeh/sec2;
302 timeh -= hour*sec2;
303
304 sec2 = SEC2MIN;
305 min = timeh/sec2;
306 timeh -= min*sec2;
307
308 sec = timeh*2 + timel/ETIME_L_HZ;
309
310 #ifdef RTCDEBUG
311 printf("cvt_timehl_ct: hour %ld min %ld sec %ld\n", hour, min, sec);
312 #endif /* RTCDEBUG */
313
314 if (ct) {
315 ct->year = year - YBASE; /* base 1900 */
316 ct->mon = month;
317 ct->day = date;
318 ct->hour = hour;
319 ct->min = min;
320 ct->sec = sec;
321 }
322 }
323
324 void
325 clock_get(dev, base, ct)
326 struct device *dev;
327 time_t base;
328 struct clocktime *ct;
329 {
330
331 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev;
332 u_long timeh; /* elapse time (2*timeh sec) */
333 u_long timel; /* timel/32768 sec */
334
335 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W);
336 timeh = (timeh << 16)
337 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W);
338 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W);
339
340 #ifdef RTCDEBUG
341 printf("clock_get: timeh %08lx timel %08lx\n", timeh, timel);
342 #endif /* RTCDEBUG */
343
344 cvt_timehl_ct(timeh, timel, ct);
345
346 #ifdef RTCDEBUG
347 printf("clock_get: %d/%d/%d/%d/%d/%d\n",
348 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec);
349 #endif /* RTCDEBUG */
350 }
351
352
353 void
354 clock_set(dev, ct)
355 struct device *dev;
356 struct clocktime *ct;
357 {
358 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev;
359 u_long timeh; /* elapse time (2*timeh sec) */
360 u_long timel; /* timel/32768 sec */
361 int year, month, sec2;
362
363 timeh = 0;
364 timel = 0;
365
366 #ifdef RTCDEBUG
367 printf("clock_set: %d/%d/%d/%d/%d/%d\n",
368 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec);
369 #endif /* RTCDEBUG */
370 ct->year += YBASE;
371 #ifdef RTCDEBUG
372 printf("clock_set: %d/%d/%d/%d/%d/%d\n",
373 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec);
374 #endif /* RTCDEBUG */
375 year = EPOCHYEAR;
376 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
377 while (year < ct->year) {
378 year++;
379 timeh += sec2;
380 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
381 }
382 month = 1; /* now month is 1..12 */
383 sec2 = SEC2DAY * m2d[month-1];
384 while (month < ct->mon) {
385 month++;
386 timeh += sec2;
387 sec2 = SEC2DAY * m2d[month-1];
388 if (month == 2 && LEAPYEAR4(year)) /* feb. and leapyear */
389 sec2 += SEC2DAY;
390 }
391
392 timeh += (ct->day - 1)*SEC2DAY;
393
394 timeh += ct->hour*SEC2HOUR;
395
396 timeh += ct->min*SEC2MIN;
397
398 timeh += ct->sec/2;
399 timel += (ct->sec%2)*ETIME_L_HZ;
400
401 timeh += EPOCHOFF;
402 timeh -= (rtc_offset*SEC2MIN);
403
404 #ifdef RTCDEBUG
405 cvt_timehl_ct(timeh, timel, NULL);
406 #endif /* RTCDEBUG */
407
408 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
409 ETIME_H_REG_W, (timeh>>16)&0xffff);
410 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W, timeh&0xffff);
411 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W, timel);
412
413 }
414
415