tx39clock.c revision 1.5 1 /* $NetBSD: tx39clock.c,v 1.5 2000/01/03 18:24:04 uch Exp $ */
2
3 /*
4 * Copyright (c) 1999, 2000 by UCHIYAMA Yasushi
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the developer may NOT be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28 #include "opt_tx39_debug.h"
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34
35 #include <dev/clock_subr.h>
36
37 #include <machine/bus.h>
38 #include <machine/clock_machdep.h>
39 #include <machine/cpu.h>
40
41 #include <hpcmips/tx/tx39var.h>
42 #include <hpcmips/tx/tx39icureg.h>
43 #include <hpcmips/tx/tx39clockvar.h>
44 #include <hpcmips/tx/tx39clockreg.h>
45 #include <hpcmips/tx/tx39timerreg.h>
46
47 #include <dev/dec/clockvar.h>
48
49 #ifdef TX39CLKDEBUG
50 #define DPRINTF(arg) printf arg
51 #else
52 #define DPRINTF(arg)
53 #endif
54
55 #define ISSETPRINT(r, m) __is_set_print(r, TX39_CLOCK_EN##m##CLK, #m)
56
57 void tx39clock_init __P((struct device*));
58 void tx39clock_get __P((struct device*, time_t, struct clocktime*));
59 void tx39clock_set __P((struct device*, struct clocktime*));
60
61 const struct clockfns tx39clockfns = {
62 tx39clock_init, tx39clock_get, tx39clock_set,
63 };
64
65 struct txtime {
66 u_int32_t t_hi;
67 u_int32_t t_lo;
68 };
69
70 struct tx39clock_softc {
71 struct device sc_dev;
72 tx_chipset_tag_t sc_tc;
73
74 int sc_alarm;
75
76 int sc_enabled;
77 int sc_year;
78 struct clocktime sc_epoch;
79 };
80
81 int tx39clock_match __P((struct device*, struct cfdata*, void*));
82 void tx39clock_attach __P((struct device*, struct device*, void*));
83 void tx39clock_dump __P((tx_chipset_tag_t));
84
85 void tx39clock_cpuspeed __P((int*, int*));
86
87 void __tx39timer_rtcfreeze __P((tx_chipset_tag_t));
88 void __tx39timer_rtcreset __P((tx_chipset_tag_t));
89 __inline void __tx39timer_rtcget __P((struct txtime*));
90 __inline time_t __tx39timer_rtc2sec __P((struct txtime*));
91
92 struct cfattach tx39clock_ca = {
93 sizeof(struct tx39clock_softc), tx39clock_match, tx39clock_attach
94 };
95
96 int
97 tx39clock_match(parent, cf, aux)
98 struct device *parent;
99 struct cfdata *cf;
100 void *aux;
101 {
102 return 2; /* 1st attach group of txsim */
103 }
104
105 void
106 tx39clock_attach(parent, self, aux)
107 struct device *parent;
108 struct device *self;
109 void *aux;
110 {
111 struct txsim_attach_args *ta = aux;
112 struct tx39clock_softc *sc = (void*)self;
113 tx_chipset_tag_t tc;
114 txreg_t reg;
115
116 tc = sc->sc_tc = ta->ta_tc;
117 tx_conf_register_clock(tc, self);
118
119 /* Reset timer module */
120 tx_conf_write(tc, TX39_TIMERCONTROL_REG, 0);
121
122 /* Enable periodic timer */
123 reg = tx_conf_read(tc, TX39_TIMERCONTROL_REG);
124 reg |= TX39_TIMERCONTROL_ENPERTIMER;
125 tx_conf_write(tc, TX39_TIMERCONTROL_REG, reg);
126
127 sc->sc_enabled = 0;
128 /*
129 * RTC and ALARM
130 * RTCINT ... INTR5 bit 31 (roll over)
131 * ALARMINT ... INTR5 bit 30
132 * PERINT ... INTR5 bit 29
133 */
134
135 clockattach(self, &tx39clockfns);
136
137 #ifdef TX39CLKDEBUG
138 tx39clock_dump(tc);
139 #endif /* TX39CLKDEBUG */
140 }
141
142 /*
143 * cpuclock ... CPU clock (Hz)
144 * cpuspeed ... instructions-per-microsecond
145 */
146 void
147 tx39clock_cpuspeed(cpuclock, cpuspeed)
148 int *cpuclock;
149 int *cpuspeed;
150 {
151 struct txtime t0, t1;
152 int elapsed;
153
154 __tx39timer_rtcget(&t0);
155 __asm __volatile("
156 .set noreorder;
157 li $8, 10000000;
158 1: nop;
159 nop;
160 nop;
161 nop;
162 nop;
163 nop;
164 nop;
165 add $8, $8, -1;
166 bnez $8, 1b;
167 nop;
168 .set reorder;
169 ");
170 __tx39timer_rtcget(&t1);
171
172 elapsed = t1.t_lo - t0.t_lo;
173
174 *cpuclock = (100000000 / elapsed) * TX39_RTCLOCK;
175 *cpuspeed = *cpuclock / 1000000;
176
177 }
178
179 void
180 __tx39timer_rtcfreeze(tc)
181 tx_chipset_tag_t tc;
182 {
183 txreg_t reg;
184
185 reg = tx_conf_read(tc, TX39_TIMERCONTROL_REG);
186
187 /* Freeze RTC */
188 reg |= TX39_TIMERCONTROL_FREEZEPRE; /* Upper 8bit */
189 reg |= TX39_TIMERCONTROL_FREEZERTC; /* Lower 32bit */
190
191 /* Freeze periodic timer */
192 reg |= TX39_TIMERCONTROL_FREEZETIMER;
193 reg &= ~TX39_TIMERCONTROL_ENPERTIMER;
194 tx_conf_write(tc, TX39_TIMERCONTROL_REG, reg);
195 }
196
197 __inline time_t
198 __tx39timer_rtc2sec(t)
199 struct txtime *t;
200 {
201 /* This rely on RTC is 32.768kHz */
202 return (t->t_lo >> 15) | (t->t_hi << 17);
203 }
204
205 __inline void
206 __tx39timer_rtcget(t)
207 struct txtime *t;
208 {
209 tx_chipset_tag_t tc;
210 txreg_t reghi, reglo, oreghi, oreglo;
211 int retry;
212
213 tc = tx_conf_get_tag();
214
215 retry = 10;
216
217 do {
218 oreglo = tx_conf_read(tc, TX39_TIMERRTCLO_REG);
219 reglo = tx_conf_read(tc, TX39_TIMERRTCLO_REG);
220
221 oreghi = tx_conf_read(tc, TX39_TIMERRTCHI_REG);
222 reghi = tx_conf_read(tc, TX39_TIMERRTCHI_REG);
223 } while ((reghi != oreghi || reglo != oreglo) && (--retry > 0));
224
225 if (retry < 0) {
226 printf("RTC timer read error.\n");
227 }
228
229 t->t_hi = TX39_TIMERRTCHI(reghi);
230 t->t_lo = reglo;
231 }
232
233 void
234 __tx39timer_rtcreset(tc)
235 tx_chipset_tag_t tc;
236 {
237 txreg_t reg;
238
239 reg = tx_conf_read(tc, TX39_TIMERCONTROL_REG);
240
241 /* Reset counter and stop */
242 reg |= TX39_TIMERCONTROL_RTCCLR;
243 tx_conf_write(tc, TX39_TIMERCONTROL_REG, reg);
244
245 /* Count again */
246 reg &= ~TX39_TIMERCONTROL_RTCCLR;
247 tx_conf_write(tc, TX39_TIMERCONTROL_REG, reg);
248 }
249
250
251 void
252 tx39clock_init(dev)
253 struct device *dev;
254 {
255 struct tx39clock_softc *sc = (void*)dev;
256 tx_chipset_tag_t tc = sc->sc_tc;
257 txreg_t reg;
258 int pcnt;
259
260 /*
261 * Setup periodic timer (interrupting hz times per second.)
262 */
263 pcnt = TX39_TIMERCLK / hz - 1;
264 reg = tx_conf_read(tc, TX39_TIMERPERIODIC_REG);
265 TX39_TIMERPERIODIC_PERVAL_CLR(reg);
266 reg = TX39_TIMERPERIODIC_PERVAL_SET(reg, pcnt);
267 tx_conf_write(tc, TX39_TIMERPERIODIC_REG, reg);
268
269 /*
270 * Enable periodic timer
271 */
272 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG);
273 reg |= TX39_INTRPRI13_TIMER_PERIODIC_BIT;
274 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg);
275
276 /*
277 * number of microseconds between interrupts
278 */
279 tick = 1000000 / hz;
280 }
281
282 void
283 tx39clock_get(dev, base, ct)
284 struct device *dev;
285 time_t base;
286 struct clocktime *ct;
287 {
288 struct clock_ymdhms dt;
289 struct tx39clock_softc *sc = (void*)dev;
290 struct txtime tt;
291 time_t sec;
292
293 __tx39timer_rtcget(&tt);
294 sec = __tx39timer_rtc2sec(&tt);
295
296 if (!sc->sc_enabled) {
297 DPRINTF(("bootstrap: %d sec from previous reboot\n",
298 (int)sec));
299
300 sc->sc_enabled = 1;
301 base += sec;
302 } else {
303 dt.dt_year = sc->sc_year;
304 dt.dt_mon = sc->sc_epoch.mon;
305 dt.dt_day = sc->sc_epoch.day;
306 dt.dt_hour = sc->sc_epoch.hour;
307 dt.dt_min = sc->sc_epoch.min;
308 dt.dt_sec = sc->sc_epoch.sec;
309 dt.dt_wday = sc->sc_epoch.dow;
310 base = sec + clock_ymdhms_to_secs(&dt);
311 }
312
313 clock_secs_to_ymdhms(base, &dt);
314
315 ct->year = dt.dt_year % 100;
316 ct->mon = dt.dt_mon;
317 ct->day = dt.dt_day;
318 ct->hour = dt.dt_hour;
319 ct->min = dt.dt_min;
320 ct->sec = dt.dt_sec;
321 ct->dow = dt.dt_wday;
322
323 sc->sc_year = dt.dt_year;
324 }
325
326 void
327 tx39clock_set(dev, ct)
328 struct device *dev;
329 struct clocktime *ct;
330 {
331 struct tx39clock_softc *sc = (void*)dev;
332
333 if (sc->sc_enabled) {
334 sc->sc_epoch = *ct;
335 /* Reset RTC counter */
336 __tx39timer_rtcreset(sc->sc_tc);
337 }
338 }
339
340 int
341 tx39clock_alarm_set(tc, msec)
342 tx_chipset_tag_t tc;
343 int msec;
344 {
345 struct tx39clock_softc *sc = tc->tc_clockt;
346
347 sc->sc_alarm = TX39_MSEC2RTC(msec);
348 tx39clock_alarm_refill(tc);
349
350 return 0;
351 }
352
353 void
354 tx39clock_alarm_refill(tc)
355 tx_chipset_tag_t tc;
356 {
357 struct tx39clock_softc *sc = tc->tc_clockt;
358 struct txtime t;
359
360 __tx39timer_rtcget(&t);
361
362 tx_conf_write(tc, TX39_TIMERALARMHI_REG, t.t_hi); /* XXX */
363 tx_conf_write(tc, TX39_TIMERALARMLO_REG, t.t_lo + sc->sc_alarm);
364
365 }
366
367 void
368 tx39clock_dump(tc)
369 tx_chipset_tag_t tc;
370 {
371 txreg_t reg;
372
373 reg = tx_conf_read(tc, TX39_CLOCKCTRL_REG);
374
375 printf(" ");
376 ISSETPRINT(reg, CHIM);
377 #ifdef TX391X
378 ISSETPRINT(reg, VID);
379 ISSETPRINT(reg, MBUS);
380 #endif /* TX391X */
381 #ifdef TX392X
382 ISSETPRINT(reg, IRDA);
383 #endif /* TX392X */
384 ISSETPRINT(reg, SPI);
385 ISSETPRINT(reg, TIMER);
386 ISSETPRINT(reg, FASTTIMER);
387 #ifdef TX392X
388 ISSETPRINT(reg, C48MOUT);
389 #endif /* TX392X */
390 ISSETPRINT(reg, SIBM);
391 ISSETPRINT(reg, CSER);
392 ISSETPRINT(reg, IR);
393 ISSETPRINT(reg, UARTA);
394 ISSETPRINT(reg, UARTB);
395 printf("\n");
396 }
397