xref: /netbsd/sys/arch/sh3/sh3/clock.c (revision bf9ec67e)
1 /*	$NetBSD: clock.c,v 1.25 2002/04/28 17:10:38 uch Exp $	*/
2 
3 /*-
4  * Copyright (c) 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_pclock.h"
40 #include "wdog.h"
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 
47 #include <dev/clock_subr.h>
48 
49 #include <sh3/clock.h>
50 #include <sh3/exception.h>
51 #include <sh3/rtcreg.h>
52 #include <sh3/tmureg.h>
53 #include <sh3/wdogvar.h>
54 #include <sh3/wdtreg.h>
55 
56 #include <machine/intr.h>
57 
58 #ifndef HZ
59 #define	HZ		64
60 #endif
61 #define	MINYEAR		2002	/* "today" */
62 #define	SH_RTC_CLOCK	16384	/* Hz */
63 
64 /*
65  * NetBSD/sh3 clock module
66  *  + default 64Hz
67  *  + use TMU channel 0 as clock interrupt source.
68  *  + use TMU channel 1 and 2 as emulated software interrupt soruce.
69  *  + If RTC module is active, TMU channel 0 input source is RTC output.
70  *    (1.6384kHz)
71  */
72 struct {
73 	/* Hard clock */
74 	u_int32_t hz_cnt;	/* clock interrupt interval count */
75 	u_int32_t cpucycle_1us;	/* calibrated loop variable (1 us) */
76 	u_int32_t tmuclk;	/* source clock of TMU0 (Hz) */
77 
78 	/* RTC ops holder. default SH RTC module */
79 	struct rtc_ops rtc;
80 	int rtc_initialized;
81 
82 	u_int32_t pclock;	/* PCLOCK */
83 	u_int32_t cpuclock;	/* CPU clock */
84 	int flags;
85 } sh_clock = {
86 #ifdef PCLOCK
87 	.pclock = PCLOCK,
88 #endif
89 	.rtc = {
90 		/* SH RTC module to default RTC */
91 		.init	= sh_rtc_init,
92 		.get	= sh_rtc_get,
93 		.set	= sh_rtc_set
94 	}
95 };
96 
97 u_int32_t maxwdog;
98 
99 /* TMU */
100 /* interrupt handler is timing critical. prepared for each. */
101 int sh3_clock_intr(void *);
102 int sh4_clock_intr(void *);
103 
104 /*
105  * Estimate CPU and Peripheral clock.
106  */
107 #define	TMU_START(x)							\
108 do {									\
109 	_reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) & ~TSTR_STR##x);	\
110 	_reg_write_4(SH_(TCNT ## x), 0xffffffff);			\
111 	_reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) | TSTR_STR##x);	\
112 } while (/*CONSTCOND*/0)
113 #define	TMU_ELAPSED(x)							\
114 	(0xffffffff - _reg_read_4(SH_(TCNT ## x)))
115 void
116 sh_clock_init(int flags, struct rtc_ops *rtc)
117 {
118 	u_int32_t s, t0, t1 __attribute__((__unused__));
119 
120 	sh_clock.flags = flags;
121 	if (rtc != NULL)
122 		sh_clock.rtc = *rtc;	/* structure copy */
123 
124 	/* Initialize TMU */
125 	_reg_write_2(SH_(TCR0), 0);
126 	_reg_write_2(SH_(TCR1), 0);
127 	_reg_write_2(SH_(TCR2), 0);
128 
129 	/* Reset RTC alarm and interrupt */
130 	_reg_write_1(SH_(RCR1), 0);
131 
132 	/* Stop all counter */
133 	_reg_write_1(SH_(TSTR), 0);
134 
135 	/*
136 	 * Estimate CPU clock.
137 	 */
138 	if (sh_clock.flags & SH_CLOCK_NORTC) {
139 		/* Set TMU channel 0 source to PCLOCK / 16 */
140 		_reg_write_2(SH_(TCR0), TCR_TPSC_P16);
141 		sh_clock.tmuclk = sh_clock.pclock / 16;
142 	} else {
143 		/* Set TMU channel 0 source to RTC counter clock (16.384kHz) */
144 		_reg_write_2(SH_(TCR0),
145 		    CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC);
146 		sh_clock.tmuclk = SH_RTC_CLOCK;
147 	}
148 
149 	s = _cpu_exception_suspend();
150 	_cpu_spin(1);	/* load function on cache. */
151 	TMU_START(0);
152 	_cpu_spin(10000000);
153 	t0 = TMU_ELAPSED(0);
154 	_cpu_exception_resume(s);
155 
156 	sh_clock.cpuclock = ((10000000 * 10) / t0) * sh_clock.tmuclk;
157 	sh_clock.cpucycle_1us = (sh_clock.tmuclk * 10) / t0;
158 
159 	if (CPU_IS_SH4)
160 		sh_clock.cpuclock >>= 1;	/* two-issue */
161 
162 	/*
163 	 * Estimate PCLOCK
164 	 */
165 	if (sh_clock.pclock == 0) {
166 		/* set TMU channel 1 source to PCLOCK / 4 */
167 		_reg_write_2(SH_(TCR1), TCR_TPSC_P4);
168 		s = _cpu_exception_suspend();
169 		_cpu_spin(1);	/* load function on cache. */
170 		TMU_START(0);
171 		TMU_START(1);
172 		_cpu_spin(sh_clock.cpucycle_1us * 1000000);	/* 1 sec. */
173 		t0 = TMU_ELAPSED(0);
174 		t1 = TMU_ELAPSED(1);
175 		_cpu_exception_resume(s);
176 
177 		sh_clock.pclock = ((t1 * 4)/ t0) * SH_RTC_CLOCK;
178 	}
179 
180 	/* Stop all counter */
181 	_reg_write_1(SH_(TSTR), 0);
182 
183 #undef TMU_START
184 #undef TMU_ELAPSED
185 }
186 
187 int
188 sh_clock_get_cpuclock()
189 {
190 
191 	return (sh_clock.cpuclock);
192 }
193 
194 int
195 sh_clock_get_pclock()
196 {
197 
198 	return (sh_clock.pclock);
199 }
200 
201 void
202 setstatclockrate(int newhz)
203 {
204 	/* XXX not yet */
205 }
206 
207 /*
208  * Return the best possible estimate of the time in the timeval to
209  * which tv points.
210  */
211 void
212 microtime(struct timeval *tv)
213 {
214 	static struct timeval lasttime;
215 	int s;
216 
217 	s = splclock();
218 	*tv = time;
219 	splx(s);
220 
221 	tv->tv_usec += ((sh_clock.hz_cnt - _reg_read_4(SH_(TCNT0)))
222 	    * 1000000) / sh_clock.tmuclk;
223 	while (tv->tv_usec >= 1000000) {
224 		tv->tv_usec -= 1000000;
225 		tv->tv_sec++;
226 	}
227 
228 	if (tv->tv_sec == lasttime.tv_sec &&
229 	    tv->tv_usec <= lasttime.tv_usec &&
230 	    (tv->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
231 		tv->tv_usec -= 1000000;
232 		tv->tv_sec++;
233 	}
234 	lasttime = *tv;
235 }
236 
237 /*
238  *  Wait at least `n' usec.
239  */
240 void
241 delay(int n)
242 {
243 
244 	_cpu_spin(sh_clock.cpucycle_1us * n);
245 }
246 
247 /*
248  * Start the clock interrupt.
249  */
250 void
251 cpu_initclocks()
252 {
253 
254 	if (sh_clock.pclock == 0)
255 		panic("No PCLOCK information.");
256 
257 	/* Set global variables. */
258 	hz = HZ;
259 	tick = 1000000 / hz;
260 
261 	/*
262 	 * Use TMU channel 0 as hard clock
263 	 */
264 	_reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) & ~TSTR_STR0);
265 
266 	if (sh_clock.flags & SH_CLOCK_NORTC) {
267 		/* use PCLOCK/16 as TMU0 source */
268 		_reg_write_2(SH_(TCR0), TCR_UNIE | TCR_TPSC_P16);
269 	} else {
270 		/* use RTC clock as TMU0 source */
271 		_reg_write_2(SH_(TCR0), TCR_UNIE |
272 		    (CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC));
273 	}
274 	sh_clock.hz_cnt = sh_clock.tmuclk / hz - 1;
275 
276 	_reg_write_4(SH_(TCOR0), sh_clock.hz_cnt);
277 	_reg_write_4(SH_(TCNT0), sh_clock.hz_cnt);
278 
279 	intc_intr_establish(SH_INTEVT_TMU0_TUNI0, IST_LEVEL, IPL_CLOCK,
280 	    CPU_IS_SH3 ? sh3_clock_intr : sh4_clock_intr, 0);
281 	/* start hardclock */
282 	_reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) | TSTR_STR0);
283 
284 	/*
285 	 * TMU channel 1, 2 are one shot timer.
286 	 */
287 	_reg_write_2(SH_(TCR1), TCR_UNIE | TCR_TPSC_P4);
288 	_reg_write_4(SH_(TCOR1), 0xffffffff);
289 	_reg_write_2(SH_(TCR2), TCR_UNIE | TCR_TPSC_P4);
290 	_reg_write_4(SH_(TCOR2), 0xffffffff);
291 
292 	/* Make sure to start RTC */
293 	sh_clock.rtc.init(sh_clock.rtc._cookie);
294 }
295 
296 void
297 inittodr(time_t base)
298 {
299 	struct clock_ymdhms dt;
300 	time_t rtc;
301 	int s;
302 
303 	if (!sh_clock.rtc_initialized)
304 		sh_clock.rtc_initialized = 1;
305 
306 	sh_clock.rtc.get(sh_clock.rtc._cookie, base, &dt);
307 	rtc = clock_ymdhms_to_secs(&dt);
308 
309 #ifdef DEBUG
310 	printf("inittodr: %d/%d/%d/%d/%d/%d(%d)\n", dt.dt_year,
311 	    dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec,
312 	    dt.dt_wday);
313 #endif
314 
315 	if (!(sh_clock.flags & SH_CLOCK_NOINITTODR) &&
316 	    (rtc < base ||
317 		dt.dt_year < MINYEAR || dt.dt_year > 2037 ||
318 		dt.dt_mon < 1 || dt.dt_mon > 12 ||
319 		dt.dt_wday > 6 ||
320 		dt.dt_day < 1 || dt.dt_day > 31 ||
321 		dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 59)) {
322 		/*
323 		 * Believe the time in the file system for lack of
324 		 * anything better, resetting the RTC.
325 		 */
326 		s = splclock();
327 		time.tv_sec = base;
328 		time.tv_usec = 0;
329 		splx(s);
330 		printf("WARNING: preposterous clock chip time\n");
331 		resettodr();
332 		printf(" -- CHECK AND RESET THE DATE!\n");
333 		return;
334 	}
335 
336 	s = splclock();
337 	time.tv_sec = rtc + rtc_offset * 60;
338 	time.tv_usec = 0;
339 	splx(s);
340 
341 	return;
342 }
343 
344 void
345 resettodr()
346 {
347 	struct clock_ymdhms dt;
348 	int s;
349 
350 	if (!sh_clock.rtc_initialized)
351 		return;
352 
353 	s = splclock();
354 	clock_secs_to_ymdhms(time.tv_sec - rtc_offset * 60, &dt);
355 	splx(s);
356 
357 	sh_clock.rtc.set(sh_clock.rtc._cookie, &dt);
358 #ifdef DEBUG
359         printf("%s: %d/%d/%d/%d/%d/%d(%d) rtc_offset %d\n", __FUNCTION__,
360 	    dt.dt_year, dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec,
361 	    dt.dt_wday, rtc_offset);
362 #endif
363 }
364 
365 #ifdef SH3
366 int
367 sh3_clock_intr(void *arg) /* trap frame */
368 {
369 #if (NWDOG > 0)
370 	u_int32_t i;
371 
372 	i = (u_int32_t)SHREG_WTCNT_R;
373 	if (i > maxwdog)
374 		maxwdog = i;
375 	wdog_wr_cnt(0);			/* reset to zero */
376 #endif
377 	/* clear underflow status */
378 	_reg_write_2(SH3_TCR0, _reg_read_2(SH3_TCR0) & ~TCR_UNF);
379 
380 	hardclock(arg);
381 
382 	return (1);
383 }
384 #endif /* SH3 */
385 #ifdef SH4
386 int
387 sh4_clock_intr(void *arg) /* trap frame */
388 {
389 #if (NWDOG > 0)
390 	u_int32_t i;
391 
392 	i = (u_int32_t)SHREG_WTCNT_R;
393 	if (i > maxwdog)
394 		maxwdog = i;
395 	wdog_wr_cnt(0);			/* reset to zero */
396 #endif
397 	/* clear underflow status */
398 	_reg_write_2(SH4_TCR0, _reg_read_2(SH4_TCR0) & ~TCR_UNF);
399 
400 	hardclock(arg);
401 
402 	return (1);
403 }
404 #endif /* SH4 */
405 
406 /*
407  * SH3 RTC module ops.
408  */
409 
410 void
411 sh_rtc_init(void *cookie)
412 {
413 
414 	/* Make sure to start RTC */
415 	_reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
416 }
417 
418 void
419 sh_rtc_get(void *cookie, time_t base, struct clock_ymdhms *dt)
420 {
421 	int retry = 8;
422 
423 	/* disable carry interrupt */
424 	_reg_write_1(SH_(RCR1), _reg_read_1(SH_(RCR1)) & ~SH_RCR1_CIE);
425 
426 	do {
427 		u_int8_t r = _reg_read_1(SH_(RCR1));
428 		r &= ~SH_RCR1_CF;
429 		r |= SH_RCR1_AF; /* don't clear alarm flag */
430 		_reg_write_1(SH_(RCR1), r);
431 
432 		if (CPU_IS_SH3)
433 			dt->dt_year = FROMBCD(_reg_read_1(SH3_RYRCNT));
434 		else
435 			dt->dt_year = FROMBCD(_reg_read_2(SH4_RYRCNT) & 0x00ff);
436 
437 		/* read counter */
438 #define	RTCGET(x, y)	dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT)))
439 		RTCGET(mon, MON);
440 		RTCGET(wday, WK);
441 		RTCGET(day, DAY);
442 		RTCGET(hour, HR);
443 		RTCGET(min, MIN);
444 		RTCGET(sec, SEC);
445 #undef RTCGET
446 	} while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
447 
448 	if (retry == 0) {
449 		printf("rtc_gettime: couldn't read RTC register.\n");
450 		memset(dt, sizeof(*dt), 0);
451 		return;
452 	}
453 
454 	dt->dt_year = (dt->dt_year % 100) + 1900;
455 	if (dt->dt_year < 1970)
456 		dt->dt_year += 100;
457 }
458 
459 void
460 sh_rtc_set(void *cookie, struct clock_ymdhms *dt)
461 {
462 	u_int8_t r;
463 
464 	/* stop clock */
465 	r = _reg_read_1(SH_(RCR2));
466 	r |= SH_RCR2_RESET;
467 	r &= ~SH_RCR2_START;
468 	_reg_write_1(SH_(RCR2), r);
469 
470 	/* set time */
471 	if (CPU_IS_SH3)
472 		_reg_write_1(SH3_RYRCNT, TOBCD(dt->dt_year % 100));
473 	else
474 		_reg_write_2(SH4_RYRCNT, TOBCD(dt->dt_year % 100));
475 #define	RTCSET(x, y)	_reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y))
476 	RTCSET(MON, mon);
477 	RTCSET(WK, wday);
478 	RTCSET(DAY, day);
479 	RTCSET(HR, hour);
480 	RTCSET(MIN, min);
481 	RTCSET(SEC, sec);
482 #undef RTCSET
483 	/* start clock */
484 	_reg_write_1(SH_(RCR2), r | SH_RCR2_START);
485 }
486 
487