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