Annotation of sys/arch/sh/sh/clock.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: clock.c,v 1.4 2007/06/21 04:43:33 miod Exp $ */
2: /* $NetBSD: clock.c,v 1.32 2006/09/05 11:09:36 uwe Exp $ */
3:
4: /*-
5: * Copyright (c) 2002 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by UCHIYAMA Yasushi.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/kernel.h>
43: #include <sys/device.h>
44:
45: #include <dev/clock_subr.h>
46:
47: #include <sh/clock.h>
48: #include <sh/trap.h>
49: #include <sh/rtcreg.h>
50: #include <sh/tmureg.h>
51:
52: #include <machine/intr.h>
53:
54: #define NWDOG 0
55:
56: #ifndef HZ
57: #define HZ 64
58: #endif
59: #define MINYEAR 2002 /* "today" */
60: #define SH_RTC_CLOCK 16384 /* Hz */
61:
62: /*
63: * OpenBSD/sh clock module
64: * + default 64Hz
65: * + use TMU channel 0 as clock interrupt source.
66: * + use TMU channel 1 and 2 as emulated software interrupt soruce.
67: * + If RTC module is active, TMU channel 0 input source is RTC output.
68: * (1.6384kHz)
69: */
70: struct {
71: /* Hard clock */
72: uint32_t hz_cnt; /* clock interrupt interval count */
73: uint32_t cpucycle_1us; /* calibrated loop variable (1 us) */
74: uint32_t tmuclk; /* source clock of TMU0 (Hz) */
75:
76: /* RTC ops holder. default SH RTC module */
77: struct rtc_ops rtc;
78: int rtc_initialized;
79:
80: uint32_t pclock; /* PCLOCK */
81: uint32_t cpuclock; /* CPU clock */
82: int flags;
83: } sh_clock = {
84: #ifdef PCLOCK
85: .pclock = PCLOCK,
86: #endif
87: .rtc = {
88: /* SH RTC module to default RTC */
89: .init = sh_rtc_init,
90: .get = sh_rtc_get,
91: .set = sh_rtc_set
92: }
93: };
94:
95: uint32_t maxwdog;
96:
97: /* TMU */
98: /* interrupt handler is timing critical. prepared for each. */
99: int sh3_clock_intr(void *);
100: int sh4_clock_intr(void *);
101:
102: /*
103: * Estimate CPU and Peripheral clock.
104: */
105: #define TMU_START(x) \
106: do { \
107: _reg_bclr_1(SH_(TSTR), TSTR_STR##x); \
108: _reg_write_4(SH_(TCNT ## x), 0xffffffff); \
109: _reg_bset_1(SH_(TSTR), TSTR_STR##x); \
110: } while (/*CONSTCOND*/0)
111: #define TMU_ELAPSED(x) \
112: (0xffffffff - _reg_read_4(SH_(TCNT ## x)))
113:
114: void
115: sh_clock_init(int flags, struct rtc_ops *rtc)
116: {
117: uint32_t s, t0, t1 __attribute__((__unused__));
118:
119: sh_clock.flags = flags;
120: if (rtc != NULL)
121: sh_clock.rtc = *rtc; /* structure copy */
122:
123: /* Initialize TMU */
124: _reg_write_2(SH_(TCR0), 0);
125: _reg_write_2(SH_(TCR1), 0);
126: _reg_write_2(SH_(TCR2), 0);
127:
128: /* Reset RTC alarm and interrupt */
129: _reg_write_1(SH_(RCR1), 0);
130:
131: /* Stop all counter */
132: _reg_write_1(SH_(TSTR), 0);
133:
134: /*
135: * Estimate CPU clock.
136: */
137: if (sh_clock.flags & SH_CLOCK_NORTC) {
138: /* Set TMU channel 0 source to PCLOCK / 16 */
139: _reg_write_2(SH_(TCR0), TCR_TPSC_P16);
140: sh_clock.tmuclk = sh_clock.pclock / 16;
141: } else {
142: /* Set TMU channel 0 source to RTC counter clock (16.384kHz) */
143: _reg_write_2(SH_(TCR0),
144: CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC);
145: sh_clock.tmuclk = SH_RTC_CLOCK;
146: }
147:
148: s = _cpu_exception_suspend();
149: _cpu_spin(1); /* load function on cache. */
150: TMU_START(0);
151: _cpu_spin(10000000);
152: t0 = TMU_ELAPSED(0);
153: _cpu_exception_resume(s);
154:
155: sh_clock.cpuclock = ((10000000 * 10) / t0) * sh_clock.tmuclk;
156: sh_clock.cpucycle_1us = (sh_clock.tmuclk * 10) / t0;
157:
158: if (CPU_IS_SH4)
159: sh_clock.cpuclock >>= 1; /* two-issue */
160:
161: /*
162: * Estimate PCLOCK
163: */
164: if (sh_clock.pclock == 0) {
165: /* set TMU channel 1 source to PCLOCK / 4 */
166: _reg_write_2(SH_(TCR1), TCR_TPSC_P4);
167: s = _cpu_exception_suspend();
168: _cpu_spin(1); /* load function on cache. */
169: TMU_START(0);
170: TMU_START(1);
171: _cpu_spin(sh_clock.cpucycle_1us * 1000000); /* 1 sec. */
172: t0 = TMU_ELAPSED(0);
173: t1 = TMU_ELAPSED(1);
174: _cpu_exception_resume(s);
175:
176: sh_clock.pclock = ((t1 * 4)/ t0) * SH_RTC_CLOCK;
177: }
178:
179: /* Stop all counter */
180: _reg_write_1(SH_(TSTR), 0);
181:
182: #undef TMU_START
183: #undef TMU_ELAPSED
184: }
185:
186: int
187: sh_clock_get_cpuclock()
188: {
189: return (sh_clock.cpuclock);
190: }
191:
192: int
193: sh_clock_get_pclock()
194: {
195: return (sh_clock.pclock);
196: }
197:
198: void
199: setstatclockrate(int newhz)
200: {
201: /* XXX not yet */
202: }
203:
204: /*
205: * Return the best possible estimate of the time in the timeval to
206: * which tv points.
207: */
208: void
209: microtime(struct timeval *tv)
210: {
211: static struct timeval lasttime;
212: u_int32_t tcnt0;
213: int s;
214:
215: s = splclock();
216: *tv = time;
217: tcnt0 = _reg_read_4(SH_(TCNT0));
218: splx(s);
219:
220: tv->tv_usec += ((sh_clock.hz_cnt - tcnt0) * 1000000) / sh_clock.tmuclk;
221: while (tv->tv_usec >= 1000000) {
222: tv->tv_usec -= 1000000;
223: tv->tv_sec++;
224: }
225:
226: if (tv->tv_sec == lasttime.tv_sec &&
227: tv->tv_usec <= lasttime.tv_usec &&
228: (tv->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
229: tv->tv_usec -= 1000000;
230: tv->tv_sec++;
231: }
232: lasttime = *tv;
233: }
234:
235: /*
236: * Wait at least `n' usec.
237: */
238: void
239: delay(int n)
240: {
241: _cpu_spin(sh_clock.cpucycle_1us * n);
242: }
243:
244: /*
245: * Start the clock interrupt.
246: */
247: void
248: cpu_initclocks()
249: {
250: if (sh_clock.pclock == 0)
251: panic("No PCLOCK information.");
252:
253: /* Set global variables. */
254: hz = HZ;
255: tick = 1000000 / hz;
256:
257: /*
258: * Use TMU channel 0 as hard clock
259: */
260: _reg_bclr_1(SH_(TSTR), TSTR_STR0);
261:
262: if (sh_clock.flags & SH_CLOCK_NORTC) {
263: /* use PCLOCK/16 as TMU0 source */
264: _reg_write_2(SH_(TCR0), TCR_UNIE | TCR_TPSC_P16);
265: } else {
266: /* use RTC clock as TMU0 source */
267: _reg_write_2(SH_(TCR0), TCR_UNIE |
268: (CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC));
269: }
270: sh_clock.hz_cnt = sh_clock.tmuclk / hz - 1;
271:
272: _reg_write_4(SH_(TCOR0), sh_clock.hz_cnt);
273: _reg_write_4(SH_(TCNT0), sh_clock.hz_cnt);
274:
275: intc_intr_establish(SH_INTEVT_TMU0_TUNI0, IST_LEVEL, IPL_CLOCK,
276: CPU_IS_SH3 ? sh3_clock_intr : sh4_clock_intr, NULL, "clock");
277: /* start hardclock */
278: _reg_bset_1(SH_(TSTR), TSTR_STR0);
279:
280: /*
281: * TMU channel 1, 2 are one shot timer.
282: */
283: _reg_write_2(SH_(TCR1), TCR_UNIE | TCR_TPSC_P4);
284: _reg_write_4(SH_(TCOR1), 0xffffffff);
285: _reg_write_2(SH_(TCR2), TCR_UNIE | TCR_TPSC_P4);
286: _reg_write_4(SH_(TCOR2), 0xffffffff);
287:
288: /* Make sure to start RTC */
289: if (sh_clock.rtc.init != NULL)
290: sh_clock.rtc.init(sh_clock.rtc._cookie);
291: }
292:
293: void
294: inittodr(time_t base)
295: {
296: struct clock_ymdhms dt;
297: time_t rtc;
298: int s;
299:
300: if (!sh_clock.rtc_initialized)
301: sh_clock.rtc_initialized = 1;
302:
303: sh_clock.rtc.get(sh_clock.rtc._cookie, base, &dt);
304: rtc = clock_ymdhms_to_secs(&dt);
305:
306: #ifdef DEBUG
307: printf("inittodr: %d/%d/%d/%d/%d/%d(%d)\n", dt.dt_year,
308: dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec,
309: dt.dt_wday);
310: #endif
311:
312: if (!(sh_clock.flags & SH_CLOCK_NOINITTODR) &&
313: (rtc < base ||
314: dt.dt_year < MINYEAR || dt.dt_year > 2037 ||
315: dt.dt_mon < 1 || dt.dt_mon > 12 ||
316: dt.dt_wday > 6 ||
317: dt.dt_day < 1 || dt.dt_day > 31 ||
318: dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 59)) {
319: /*
320: * Believe the time in the file system for lack of
321: * anything better, resetting the RTC.
322: */
323: s = splclock();
324: time.tv_sec = base;
325: time.tv_usec = 0;
326: splx(s);
327: printf("WARNING: preposterous clock chip time\n");
328: resettodr();
329: printf(" -- CHECK AND RESET THE DATE!\n");
330: return;
331: }
332:
333: s = splclock();
334: time.tv_sec = rtc;
335: time.tv_usec = 0;
336: splx(s);
337:
338: return;
339: }
340:
341: void
342: resettodr()
343: {
344: struct clock_ymdhms dt;
345: int s;
346:
347: if (!sh_clock.rtc_initialized)
348: return;
349:
350: s = splclock();
351: clock_secs_to_ymdhms(time.tv_sec, &dt);
352: splx(s);
353:
354: sh_clock.rtc.set(sh_clock.rtc._cookie, &dt);
355: #ifdef DEBUG
356: printf("%s: %d/%d/%d/%d/%d/%d(%d)\n", __FUNCTION__,
357: dt.dt_year, dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec,
358: dt.dt_wday);
359: #endif
360: }
361:
362: #ifdef SH3
363: int
364: sh3_clock_intr(void *arg) /* trap frame */
365: {
366: #if (NWDOG > 0)
367: uint32_t i;
368:
369: i = (uint32_t)SHREG_WTCNT_R;
370: if (i > maxwdog)
371: maxwdog = i;
372: wdog_wr_cnt(0); /* reset to zero */
373: #endif
374: /* clear underflow status */
375: _reg_bclr_2(SH3_TCR0, TCR_UNF);
376:
377: hardclock(arg);
378:
379: return (1);
380: }
381: #endif /* SH3 */
382:
383: #ifdef SH4
384: int
385: sh4_clock_intr(void *arg) /* trap frame */
386: {
387: #if (NWDOG > 0)
388: uint32_t i;
389:
390: i = (uint32_t)SHREG_WTCNT_R;
391: if (i > maxwdog)
392: maxwdog = i;
393: wdog_wr_cnt(0); /* reset to zero */
394: #endif
395: /* clear underflow status */
396: _reg_bclr_2(SH4_TCR0, TCR_UNF);
397:
398: hardclock(arg);
399:
400: return (1);
401: }
402: #endif /* SH4 */
403:
404: /*
405: * SH3 RTC module ops.
406: */
407:
408: void
409: sh_rtc_init(void *cookie)
410: {
411: /* Make sure to start RTC */
412: _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
413: }
414:
415: void
416: sh_rtc_get(void *cookie, time_t base, struct clock_ymdhms *dt)
417: {
418: int retry = 8;
419:
420: /* disable carry interrupt */
421: _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE);
422:
423: do {
424: uint8_t r = _reg_read_1(SH_(RCR1));
425: r &= ~SH_RCR1_CF;
426: r |= SH_RCR1_AF; /* don't clear alarm flag */
427: _reg_write_1(SH_(RCR1), r);
428:
429: if (CPU_IS_SH3)
430: dt->dt_year = FROMBCD(_reg_read_1(SH3_RYRCNT));
431: else
432: dt->dt_year = FROMBCD(_reg_read_2(SH4_RYRCNT) & 0x00ff);
433:
434: /* read counter */
435: #define RTCGET(x, y) dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT)))
436: RTCGET(mon, MON);
437: RTCGET(wday, WK);
438: RTCGET(day, DAY);
439: RTCGET(hour, HR);
440: RTCGET(min, MIN);
441: RTCGET(sec, SEC);
442: #undef RTCGET
443: } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
444:
445: if (retry == 0) {
446: printf("rtc_gettime: couldn't read RTC register.\n");
447: memset(dt, 0, sizeof(*dt));
448: return;
449: }
450:
451: dt->dt_year = (dt->dt_year % 100) + 1900;
452: if (dt->dt_year < 1970)
453: dt->dt_year += 100;
454: }
455:
456: void
457: sh_rtc_set(void *cookie, struct clock_ymdhms *dt)
458: {
459: uint8_t r;
460:
461: /* stop clock */
462: r = _reg_read_1(SH_(RCR2));
463: r |= SH_RCR2_RESET;
464: r &= ~SH_RCR2_START;
465: _reg_write_1(SH_(RCR2), r);
466:
467: /* set time */
468: if (CPU_IS_SH3)
469: _reg_write_1(SH3_RYRCNT, TOBCD(dt->dt_year % 100));
470: else
471: _reg_write_2(SH4_RYRCNT, TOBCD(dt->dt_year % 100));
472: #define RTCSET(x, y) _reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y))
473: RTCSET(MON, mon);
474: RTCSET(WK, wday);
475: RTCSET(DAY, day);
476: RTCSET(HR, hour);
477: RTCSET(MIN, min);
478: RTCSET(SEC, sec);
479: #undef RTCSET
480: /* start clock */
481: _reg_write_1(SH_(RCR2), r | SH_RCR2_START);
482: }
CVSweb