rtc.c revision 1.5 1 /* $NetBSD: rtc.c,v 1.5 2001/05/17 05:25:32 enami 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 "opt_vr41xx.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 #include <sys/reboot.h>
44
45 #include <machine/bus.h>
46 #include <machine/clock_machdep.h>
47 #include <machine/cpu.h>
48
49 #include <hpcmips/vr/vr.h>
50 #include <hpcmips/vr/vrcpudef.h>
51 #include <hpcmips/vr/vripvar.h>
52 #include <hpcmips/vr/rtcreg.h>
53 #include <dev/dec/clockvar.h>
54
55 /*
56 * for debugging definitions
57 * VRRTCDEBUG print rtc debugging infomation
58 * VRRTC_HEARTBEAT print HEARTBEAT (too many print...)
59 */
60 #ifdef VRRTCDEBUG
61 #ifndef VRRTCDEBUG_CONF
62 #define VRRTCDEBUG_CONF 0
63 #endif
64 int vrrtc_debug = VRRTCDEBUG_CONF;
65 #define DPRINTF(arg) if (vrrtc_debug) printf arg;
66 #define DDUMP_REGS(arg) if (vrrtc_debug) vrrtc_dump_regs(arg);
67 #else /* VRRTCDEBUG */
68 #define DPRINTF(arg)
69 #define DDUMP_REGS(arg)
70 #endif /* VRRTCDEBUG */
71
72 struct vrrtc_softc {
73 struct device sc_dev;
74 bus_space_tag_t sc_iot;
75 bus_space_handle_t sc_ioh;
76 void *sc_ih;
77 };
78
79 void clock_init __P((struct device *));
80 void clock_get __P((struct device *, time_t, struct clocktime *));
81 void clock_set __P((struct device *, struct clocktime *));
82
83 static const struct clockfns clockfns = {
84 clock_init, clock_get, clock_set,
85 };
86
87 int vrrtc_match __P((struct device *, struct cfdata *, void *));
88 void vrrtc_attach __P((struct device *, struct device *, void *));
89 int vrrtc_intr __P((void*, u_int32_t, u_int32_t));
90 void vrrtc_dump_regs __P((struct vrrtc_softc *));
91
92 struct cfattach vrrtc_ca = {
93 sizeof(struct vrrtc_softc), vrrtc_match, vrrtc_attach
94 };
95
96 void vrrtc_write __P((struct vrrtc_softc *, int, unsigned short));
97 unsigned short vrrtc_read __P((struct vrrtc_softc *, int));
98 void cvt_timehl_ct __P((u_long, u_long, struct clocktime *));
99
100 extern int rtc_offset;
101
102 int
103 vrrtc_match(parent, cf, aux)
104 struct device *parent;
105 struct cfdata *cf;
106 void *aux;
107 {
108 return(1);
109 }
110
111 inline void
112 vrrtc_write(sc, port, val)
113 struct vrrtc_softc *sc;
114 int port;
115 unsigned short val;
116 {
117 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
118 }
119
120 inline unsigned short
121 vrrtc_read(sc, port)
122 struct vrrtc_softc *sc;
123 int port;
124 {
125 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
126 }
127
128 void
129 vrrtc_attach(parent, self, aux)
130 struct device *parent;
131 struct device *self;
132 void *aux;
133 {
134 struct vrip_attach_args *va = aux;
135 struct vrrtc_softc *sc = (void*)self;
136
137 sc->sc_iot = va->va_iot;
138 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
139 0 /* no flags */, &sc->sc_ioh)) {
140 printf("vrrtc_attach: can't map i/o space\n");
141 return;
142 }
143 /* RTC interrupt handler is directly dispatched from CPU intr */
144 vr_intr_establish(VR_INTR1, vrrtc_intr, sc);
145 /* But need to set level 1 interupt mask register,
146 * so regsiter fake interrurpt handler
147 */
148 if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_intr,
149 IPL_CLOCK, 0, 0))) {
150 printf (":can't map interrupt.\n");
151 return;
152 }
153 /*
154 * Rtc is attached to call this routine
155 * before cpu_initclock() calls clock_init().
156 * So we must disable all interrupt for now.
157 */
158 /*
159 * Disable all rtc interrupts
160 */
161 /* Disable Elapse compare intr */
162 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W, 0);
163 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W, 0);
164 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W, 0);
165 /* Disable RTC Long1 intr */
166 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0);
167 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W, 0);
168 /* Disable RTC Long2 intr */
169 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W, 0);
170 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W, 0);
171 /* Disable RTC TCLK intr */
172 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W, 0);
173 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W, 0);
174 /*
175 * Clear all rtc intrrupts.
176 */
177 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL);
178
179 clockattach(&sc->sc_dev, &clockfns);
180 }
181
182 int
183 vrrtc_intr(arg, pc, statusReg)
184 void *arg;
185 u_int32_t pc;
186 u_int32_t statusReg;
187 {
188 struct vrrtc_softc *sc = arg;
189 struct clockframe cf;
190
191 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL);
192 cf.pc = pc;
193 cf.sr = statusReg;
194 hardclock(&cf);
195 intrcnt[HARDCLOCK]++;
196
197 #ifdef VRRTC_HEARTBEAT
198 if ((intrcnt[HARDCLOCK] % (CLOCK_RATE * 5)) == 0) {
199 struct clocktime ct;
200 clock_get((struct device *)sc, NULL, &ct);
201 printf("%s(%d): rtc_intr: %2d.%2d.%2d %02d:%02d:%02d\n",
202 __FILE__, __LINE__,
203 ct.year, ct.mon, ct.day,
204 ct.hour, ct.min, ct.sec);
205 }
206 #endif
207 return 0;
208 }
209
210 void
211 vrrtc_dump_regs(sc)
212 struct vrrtc_softc *sc;
213 {
214 int timeh;
215 int timel;
216
217 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W);
218 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W);
219 timel = (timel << 16)
220 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W);
221 printf("clock_init() Elapse Time %04x%04x\n", timeh, timel);
222
223 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W);
224 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W);
225 timel = (timel << 16)
226 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W);
227 printf("clock_init() Elapse Compare %04x%04x\n", timeh, timel);
228
229 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W);
230 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W);
231 printf("clock_init() LONG1 %04x%04x\n", timeh, timel);
232
233 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_H_REG_W);
234 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_L_REG_W);
235 printf("clock_init() LONG1 CNTL %04x%04x\n", timeh, timel);
236
237 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W);
238 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W);
239 printf("clock_init() LONG2 %04x%04x\n", timeh, timel);
240
241 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_H_REG_W);
242 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_L_REG_W);
243 printf("clock_init() LONG2 CNTL %04x%04x\n", timeh, timel);
244
245 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W);
246 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W);
247 printf("clock_init() TCLK %04x%04x\n", timeh, timel);
248
249 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_H_REG_W);
250 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_L_REG_W);
251 printf("clock_init() TCLK CNTL %04x%04x\n", timeh, timel);
252 }
253
254 void
255 clock_init(dev)
256 struct device *dev;
257 {
258 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev;
259
260 DDUMP_REGS(sc);
261 /*
262 * Set tick (CLOCK_RATE)
263 */
264 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0);
265 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
266 RTCL1_L_REG_W, RTCL1_L_HZ/CLOCK_RATE);
267 }
268
269 static int m2d[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
270
271 void
272 cvt_timehl_ct(timeh, timel, ct)
273 u_long timeh; /* 2 sec */
274 u_long timel; /* 1/32768 sec */
275 struct clocktime *ct;
276 {
277 u_long year, month, date, hour, min, sec, sec2;
278
279 timeh -= EPOCHOFF;
280
281 timeh += (rtc_offset*SEC2MIN);
282
283 year = EPOCHYEAR;
284 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
285 while (timeh > sec2) {
286 year++;
287 timeh -= sec2;
288 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
289 }
290
291 DPRINTF(("cvt_timehl_ct: timeh %08lx year %ld yrref %ld\n",
292 timeh, year, sec2));
293
294 month = 0; /* now month is 0..11 */
295 sec2 = SEC2DAY * m2d[month];
296 while (timeh > sec2) {
297 timeh -= sec2;
298 month++;
299 sec2 = SEC2DAY * m2d[month];
300 if (month == 1 && LEAPYEAR4(year)) /* feb. and leapyear */
301 sec2 += SEC2DAY;
302 }
303 month +=1; /* now month is 1..12 */
304
305 DPRINTF(("cvt_timehl_ct: timeh %08lx month %ld mref %ld\n",
306 timeh, month, sec2));
307
308 sec2 = SEC2DAY;
309 date = timeh/sec2+1; /* date is 1..31 */
310 timeh -= (date-1)*sec2;
311
312 DPRINTF(("cvt_timehl_ct: timeh %08lx date %ld dref %ld\n",
313 timeh, date, sec2));
314
315 sec2 = SEC2HOUR;
316 hour = timeh/sec2;
317 timeh -= hour*sec2;
318
319 sec2 = SEC2MIN;
320 min = timeh/sec2;
321 timeh -= min*sec2;
322
323 sec = timeh*2 + timel/ETIME_L_HZ;
324
325 DPRINTF(("cvt_timehl_ct: hour %ld min %ld sec %ld\n", hour, min, sec));
326
327 if (ct) {
328 ct->year = year - YBASE; /* base 1900 */
329 ct->mon = month;
330 ct->day = date;
331 ct->hour = hour;
332 ct->min = min;
333 ct->sec = sec;
334 }
335 }
336
337 void
338 clock_get(dev, base, ct)
339 struct device *dev;
340 time_t base;
341 struct clocktime *ct;
342 {
343
344 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev;
345 u_long timeh; /* elapse time (2*timeh sec) */
346 u_long timel; /* timel/32768 sec */
347
348 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W);
349 timeh = (timeh << 16)
350 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W);
351 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W);
352
353 DPRINTF(("clock_get: timeh %08lx timel %08lx\n", timeh, timel));
354
355 cvt_timehl_ct(timeh, timel, ct);
356
357 DPRINTF(("clock_get: %d/%d/%d/%d/%d/%d\n",
358 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec));
359 }
360
361
362 void
363 clock_set(dev, ct)
364 struct device *dev;
365 struct clocktime *ct;
366 {
367 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev;
368 u_long timeh; /* elapse time (2*timeh sec) */
369 u_long timel; /* timel/32768 sec */
370 int year, month, sec2;
371
372 timeh = 0;
373 timel = 0;
374
375 DPRINTF(("clock_set: %d/%d/%d/%d/%d/%d\n",
376 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec));
377
378 ct->year += YBASE;
379
380 DPRINTF(("clock_set: %d/%d/%d/%d/%d/%d\n",
381 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec));
382
383 year = EPOCHYEAR;
384 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
385 while (year < ct->year) {
386 year++;
387 timeh += sec2;
388 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR;
389 }
390 month = 1; /* now month is 1..12 */
391 sec2 = SEC2DAY * m2d[month-1];
392 while (month < ct->mon) {
393 month++;
394 timeh += sec2;
395 sec2 = SEC2DAY * m2d[month-1];
396 if (month == 2 && LEAPYEAR4(year)) /* feb. and leapyear */
397 sec2 += SEC2DAY;
398 }
399
400 timeh += (ct->day - 1)*SEC2DAY;
401
402 timeh += ct->hour*SEC2HOUR;
403
404 timeh += ct->min*SEC2MIN;
405
406 timeh += ct->sec/2;
407 timel += (ct->sec%2)*ETIME_L_HZ;
408
409 timeh += EPOCHOFF;
410 timeh -= (rtc_offset*SEC2MIN);
411
412 #ifdef VRRTCDEBUG
413 cvt_timehl_ct(timeh, timel, NULL);
414 #endif /* RTCDEBUG */
415
416 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
417 ETIME_H_REG_W, (timeh>>16)&0xffff);
418 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W, timeh&0xffff);
419 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W, timel);
420
421 }
422
423