xref: /openbsd/sys/arch/sh/sh/clock.c (revision 0ed1bf01)
1 /*	$OpenBSD: clock.c,v 1.17 2023/09/17 14:50:51 cheloha 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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/clockintr.h>
37 #include <sys/device.h>
38 #include <sys/timetc.h>
39 
40 #include <dev/clock_subr.h>
41 
42 #include <sh/clock.h>
43 #include <sh/trap.h>
44 #include <sh/rtcreg.h>
45 #include <sh/tmureg.h>
46 
47 #include <machine/intr.h>
48 
49 #define	NWDOG 0
50 
51 #define	MINYEAR		2002	/* "today" */
52 #define	SH_RTC_CLOCK	16384	/* Hz */
53 
54 /*
55  * OpenBSD/sh clock module
56  *  + default 64Hz
57  *  + use TMU channel 0 as clock interrupt source.
58  *  + use TMU channel 1 as emulated software interrupt source.
59  *  + use TMU channel 2 as freerunning counter for timecounter.
60  *  + If RTC module is active, TMU channel 0 input source is RTC output.
61  *    (1.6384kHz)
62  */
63 struct {
64 	/* Hard clock */
65 	uint32_t hz_cnt;	/* clock interrupt interval count */
66 	uint32_t cpucycle_1us;	/* calibrated loop variable (1 us) */
67 	uint32_t tmuclk;	/* source clock of TMU0 (Hz) */
68 
69 	/* RTC ops holder. default SH RTC module */
70 	struct rtc_ops rtc;
71 	int rtc_initialized;
72 
73 	uint32_t pclock;	/* PCLOCK */
74 	uint32_t cpuclock;	/* CPU clock */
75 	int flags;
76 
77 	struct timecounter tc;
78 } sh_clock = {
79 #ifdef PCLOCK
80 	.pclock = PCLOCK,
81 #endif
82 	.rtc = {
83 		/* SH RTC module to default RTC */
84 		.init	= sh_rtc_init,
85 		.get	= sh_rtc_get,
86 		.set	= sh_rtc_set
87 	}
88 };
89 
90 uint32_t maxwdog;
91 
92 /* TMU */
93 /* interrupt handler is timing critical. prepared for each. */
94 int sh3_clock_intr(void *);
95 int sh4_clock_intr(void *);
96 u_int sh_timecounter_get(struct timecounter *);
97 
98 /*
99  * Estimate CPU and Peripheral clock.
100  */
101 #define	TMU_START(x)							\
102 do {									\
103 	_reg_bclr_1(SH_(TSTR), TSTR_STR##x);				\
104 	_reg_write_4(SH_(TCNT ## x), 0xffffffff);			\
105 	_reg_bset_1(SH_(TSTR), TSTR_STR##x);				\
106 } while (/*CONSTCOND*/0)
107 
108 #define	TMU_ELAPSED(x)							\
109 	(0xffffffff - _reg_read_4(SH_(TCNT ## x)))
110 
111 void
sh_clock_init(int flags,struct rtc_ops * rtc)112 sh_clock_init(int flags, struct rtc_ops *rtc)
113 {
114 	uint32_t s, t0, cnt_1s;
115 
116 	sh_clock.flags = flags;
117 	if (rtc != NULL)
118 		sh_clock.rtc = *rtc;	/* structure copy */
119 
120 	/* Initialize TMU */
121 	_reg_write_2(SH_(TCR0), 0);
122 	_reg_write_2(SH_(TCR1), 0);
123 	_reg_write_2(SH_(TCR2), 0);
124 
125 	/* Reset RTC alarm and interrupt */
126 	_reg_write_1(SH_(RCR1), 0);
127 
128 	/* Stop all counter */
129 	_reg_write_1(SH_(TSTR), 0);
130 
131 	/*
132 	 * Estimate CPU clock.
133 	 */
134 	if (sh_clock.flags & SH_CLOCK_NORTC) {
135 		/* Set TMU channel 0 source to PCLOCK / 16 */
136 		_reg_write_2(SH_(TCR0), TCR_TPSC_P16);
137 		sh_clock.tmuclk = sh_clock.pclock / 16;
138 	} else {
139 		/* Set TMU channel 0 source to RTC counter clock (16.384kHz) */
140 		_reg_write_2(SH_(TCR0),
141 		    CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC);
142 		sh_clock.tmuclk = SH_RTC_CLOCK;
143 
144 		/* Make sure RTC oscillator is enabled */
145 		_reg_bset_1(SH_(RCR2), SH_RCR2_ENABLE);
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.cpucycle_1us = (sh_clock.tmuclk * 10) / t0;
156 
157 	cnt_1s = ((uint64_t)sh_clock.tmuclk * 10000000 * 10 + t0 / 2) / t0;
158 	if (CPU_IS_SH4)
159 		sh_clock.cpuclock = cnt_1s / 2;	/* two-issue */
160 	else
161 		sh_clock.cpuclock = cnt_1s;
162 
163 	/*
164 	 * Estimate PCLOCK
165 	 */
166 	if (sh_clock.pclock == 0) {
167 		uint32_t t1;
168 
169 		/* set TMU channel 1 source to PCLOCK / 4 */
170 		_reg_write_2(SH_(TCR1), TCR_TPSC_P4);
171 		s = _cpu_exception_suspend();
172 		_cpu_spin(1);	/* load function on cache. */
173 		TMU_START(0);
174 		TMU_START(1);
175 		_cpu_spin(cnt_1s); /* 1 sec. */
176 		t0 = TMU_ELAPSED(0);
177 		t1 = TMU_ELAPSED(1);
178 		_cpu_exception_resume(s);
179 
180 		sh_clock.pclock =
181 		    ((uint64_t)t1 * 4 * SH_RTC_CLOCK + t0 / 2) / t0;
182 	}
183 
184 	/* Stop all counters */
185 	_reg_write_1(SH_(TSTR), 0);
186 
187 #undef TMU_START
188 #undef TMU_ELAPSED
189 }
190 
191 int
sh_clock_get_cpuclock(void)192 sh_clock_get_cpuclock(void)
193 {
194 	return (sh_clock.cpuclock);
195 }
196 
197 int
sh_clock_get_pclock(void)198 sh_clock_get_pclock(void)
199 {
200 	return (sh_clock.pclock);
201 }
202 
203 void
setstatclockrate(int newhz)204 setstatclockrate(int newhz)
205 {
206 }
207 
208 u_int
sh_timecounter_get(struct timecounter * tc)209 sh_timecounter_get(struct timecounter *tc)
210 {
211 	return 0xffffffff - _reg_read_4(SH_(TCNT2));
212 }
213 
214 /*
215  *  Wait at least `n' usec.
216  */
217 void
delay(int n)218 delay(int n)
219 {
220 	_cpu_spin(sh_clock.cpucycle_1us * n);
221 }
222 
223 extern todr_chip_handle_t todr_handle;
224 struct todr_chip_handle rtc_todr;
225 
226 int
rtc_gettime(struct todr_chip_handle * handle,struct timeval * tv)227 rtc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
228 {
229 	struct clock_ymdhms dt;
230 
231 	sh_clock.rtc.get(sh_clock.rtc._cookie, tv->tv_sec, &dt);
232 	tv->tv_sec = clock_ymdhms_to_secs(&dt);
233 	tv->tv_usec = 0;
234 	return 0;
235 }
236 
237 int
rtc_settime(struct todr_chip_handle * handle,struct timeval * tv)238 rtc_settime(struct todr_chip_handle *handle, struct timeval *tv)
239 {
240 	struct clock_ymdhms dt;
241 
242 	clock_secs_to_ymdhms(tv->tv_sec, &dt);
243 	sh_clock.rtc.set(sh_clock.rtc._cookie, &dt);
244 	return 0;
245 }
246 
247 /*
248  * Start the clock interrupt.
249  */
250 void
cpu_initclocks(void)251 cpu_initclocks(void)
252 {
253 	if (sh_clock.pclock == 0)
254 		panic("No PCLOCK information.");
255 
256 	/* Set global variables. */
257 	tick = 1000000 / hz;
258 	tick_nsec = 1000000000 / hz;
259 
260 	stathz = hz;
261 	profhz = stathz;
262 }
263 
264 void
cpu_startclock(void)265 cpu_startclock(void)
266 {
267 	clockintr_cpu_init(NULL);
268 
269 	/*
270 	 * Use TMU channel 0 as hard clock
271 	 */
272 	_reg_bclr_1(SH_(TSTR), TSTR_STR0);
273 
274 	if (sh_clock.flags & SH_CLOCK_NORTC) {
275 		/* use PCLOCK/16 as TMU0 source */
276 		_reg_write_2(SH_(TCR0), TCR_UNIE | TCR_TPSC_P16);
277 	} else {
278 		/* use RTC clock as TMU0 source */
279 		_reg_write_2(SH_(TCR0), TCR_UNIE |
280 		    (CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC));
281 	}
282 	sh_clock.hz_cnt = sh_clock.tmuclk / hz - 1;
283 
284 	_reg_write_4(SH_(TCOR0), sh_clock.hz_cnt);
285 	_reg_write_4(SH_(TCNT0), sh_clock.hz_cnt);
286 
287 	intc_intr_establish(SH_INTEVT_TMU0_TUNI0, IST_LEVEL, IPL_CLOCK,
288 	    CPU_IS_SH3 ? sh3_clock_intr : sh4_clock_intr, NULL, "clock");
289 	/* start hardclock */
290 	_reg_bset_1(SH_(TSTR), TSTR_STR0);
291 
292 	/*
293 	 * TMU channel 1 is one shot timer for soft interrupts.
294 	 */
295 	_reg_write_2(SH_(TCR1), TCR_UNIE | TCR_TPSC_P4);
296 	_reg_write_4(SH_(TCOR1), 0xffffffff);
297 
298 	/*
299 	 * TMU channel 2 is freerunning counter for timecounter.
300 	 */
301 	_reg_write_2(SH_(TCR2), TCR_TPSC_P4);
302 	_reg_write_4(SH_(TCOR2), 0xffffffff);
303 
304 	/*
305 	 * Start and initialize timecounter.
306 	 */
307 	_reg_bset_1(SH_(TSTR), TSTR_STR2);
308 
309 	sh_clock.tc.tc_get_timecount = sh_timecounter_get;
310 	sh_clock.tc.tc_frequency = sh_clock.pclock / 4;
311 	sh_clock.tc.tc_name = "tmu_pclock_4";
312 	sh_clock.tc.tc_quality = 100;
313 	sh_clock.tc.tc_counter_mask = 0xffffffff;
314 	tc_init(&sh_clock.tc);
315 
316 	/* Make sure to start RTC */
317 	if (sh_clock.rtc.init != NULL)
318 		sh_clock.rtc.init(sh_clock.rtc._cookie);
319 
320 	rtc_todr.todr_gettime = rtc_gettime;
321 	rtc_todr.todr_settime = rtc_settime;
322 	todr_handle = &rtc_todr;
323 }
324 
325 #ifdef SH3
326 int
sh3_clock_intr(void * arg)327 sh3_clock_intr(void *arg) /* trap frame */
328 {
329 #if (NWDOG > 0)
330 	uint32_t i;
331 
332 	i = (uint32_t)SHREG_WTCNT_R;
333 	if (i > maxwdog)
334 		maxwdog = i;
335 	wdog_wr_cnt(0);			/* reset to zero */
336 #endif
337 	/* clear underflow status */
338 	_reg_bclr_2(SH3_TCR0, TCR_UNF);
339 
340 	clockintr_dispatch(arg);
341 
342 	return (1);
343 }
344 #endif /* SH3 */
345 
346 #ifdef SH4
347 int
sh4_clock_intr(void * arg)348 sh4_clock_intr(void *arg) /* trap frame */
349 {
350 #if (NWDOG > 0)
351 	uint32_t i;
352 
353 	i = (uint32_t)SHREG_WTCNT_R;
354 	if (i > maxwdog)
355 		maxwdog = i;
356 	wdog_wr_cnt(0);			/* reset to zero */
357 #endif
358 	/* clear underflow status */
359 	_reg_bclr_2(SH4_TCR0, TCR_UNF);
360 
361 	clockintr_dispatch(arg);
362 
363 	return (1);
364 }
365 #endif /* SH4 */
366 
367 /*
368  * SH3 RTC module ops.
369  */
370 
371 void
sh_rtc_init(void * cookie)372 sh_rtc_init(void *cookie)
373 {
374 	/* Make sure to start RTC */
375 	_reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
376 }
377 
378 void
sh_rtc_get(void * cookie,time_t base,struct clock_ymdhms * dt)379 sh_rtc_get(void *cookie, time_t base, struct clock_ymdhms *dt)
380 {
381 	int retry = 8;
382 
383 	/* disable carry interrupt */
384 	_reg_bclr_1(SH_(RCR1), SH_RCR1_CIE);
385 
386 	do {
387 		uint8_t r = _reg_read_1(SH_(RCR1));
388 		r &= ~SH_RCR1_CF;
389 		r |= SH_RCR1_AF; /* don't clear alarm flag */
390 		_reg_write_1(SH_(RCR1), r);
391 
392 		if (CPU_IS_SH3)
393 			dt->dt_year = FROMBCD(_reg_read_1(SH3_RYRCNT));
394 		else
395 			dt->dt_year = FROMBCD(_reg_read_2(SH4_RYRCNT) & 0x00ff);
396 
397 		/* read counter */
398 #define	RTCGET(x, y)	dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT)))
399 		RTCGET(mon, MON);
400 		RTCGET(wday, WK);
401 		RTCGET(day, DAY);
402 		RTCGET(hour, HR);
403 		RTCGET(min, MIN);
404 		RTCGET(sec, SEC);
405 #undef RTCGET
406 	} while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
407 
408 	if (retry == 0) {
409 		printf("rtc_gettime: couldn't read RTC register.\n");
410 		memset(dt, 0, sizeof(*dt));
411 		return;
412 	}
413 
414 	dt->dt_year = (dt->dt_year % 100) + 1900;
415 	if (dt->dt_year < 1970)
416 		dt->dt_year += 100;
417 }
418 
419 void
sh_rtc_set(void * cookie,struct clock_ymdhms * dt)420 sh_rtc_set(void *cookie, struct clock_ymdhms *dt)
421 {
422 	uint8_t r;
423 
424 	/* stop clock */
425 	r = _reg_read_1(SH_(RCR2));
426 	r |= SH_RCR2_RESET;
427 	r &= ~SH_RCR2_START;
428 	_reg_write_1(SH_(RCR2), r);
429 
430 	/* set time */
431 	if (CPU_IS_SH3)
432 		_reg_write_1(SH3_RYRCNT, TOBCD(dt->dt_year % 100));
433 	else
434 		_reg_write_2(SH4_RYRCNT, TOBCD(dt->dt_year % 100));
435 #define	RTCSET(x, y)	_reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y))
436 	RTCSET(MON, mon);
437 	RTCSET(WK, wday);
438 	RTCSET(DAY, day);
439 	RTCSET(HR, hour);
440 	RTCSET(MIN, min);
441 	RTCSET(SEC, sec);
442 #undef RTCSET
443 	/* start clock */
444 	_reg_write_1(SH_(RCR2), r | SH_RCR2_START);
445 }
446