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