xref: /openbsd/sys/arch/sh/sh/clock.c (revision 0ed1bf01)
1*0ed1bf01Scheloha /*	$OpenBSD: clock.c,v 1.17 2023/09/17 14:50:51 cheloha Exp $	*/
295c7671fSmiod /*	$NetBSD: clock.c,v 1.32 2006/09/05 11:09:36 uwe Exp $	*/
395c7671fSmiod 
495c7671fSmiod /*-
595c7671fSmiod  * Copyright (c) 2002 The NetBSD Foundation, Inc.
695c7671fSmiod  * All rights reserved.
795c7671fSmiod  *
895c7671fSmiod  * This code is derived from software contributed to The NetBSD Foundation
995c7671fSmiod  * by UCHIYAMA Yasushi.
1095c7671fSmiod  *
1195c7671fSmiod  * Redistribution and use in source and binary forms, with or without
1295c7671fSmiod  * modification, are permitted provided that the following conditions
1395c7671fSmiod  * are met:
1495c7671fSmiod  * 1. Redistributions of source code must retain the above copyright
1595c7671fSmiod  *    notice, this list of conditions and the following disclaimer.
1695c7671fSmiod  * 2. Redistributions in binary form must reproduce the above copyright
1795c7671fSmiod  *    notice, this list of conditions and the following disclaimer in the
1895c7671fSmiod  *    documentation and/or other materials provided with the distribution.
1995c7671fSmiod  *
2095c7671fSmiod  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2195c7671fSmiod  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2295c7671fSmiod  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2395c7671fSmiod  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2495c7671fSmiod  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2595c7671fSmiod  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2695c7671fSmiod  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2795c7671fSmiod  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2895c7671fSmiod  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2995c7671fSmiod  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3095c7671fSmiod  * POSSIBILITY OF SUCH DAMAGE.
3195c7671fSmiod  */
3295c7671fSmiod 
3395c7671fSmiod #include <sys/param.h>
3495c7671fSmiod #include <sys/systm.h>
3595c7671fSmiod #include <sys/kernel.h>
36a2953de3Scheloha #include <sys/clockintr.h>
3795c7671fSmiod #include <sys/device.h>
3854a9edacSmiod #include <sys/timetc.h>
3995c7671fSmiod 
4095c7671fSmiod #include <dev/clock_subr.h>
4195c7671fSmiod 
4295c7671fSmiod #include <sh/clock.h>
4395c7671fSmiod #include <sh/trap.h>
4495c7671fSmiod #include <sh/rtcreg.h>
4595c7671fSmiod #include <sh/tmureg.h>
4695c7671fSmiod 
4795c7671fSmiod #include <machine/intr.h>
4895c7671fSmiod 
4995c7671fSmiod #define	NWDOG 0
5095c7671fSmiod 
5195c7671fSmiod #define	MINYEAR		2002	/* "today" */
5295c7671fSmiod #define	SH_RTC_CLOCK	16384	/* Hz */
5395c7671fSmiod 
5495c7671fSmiod /*
5595c7671fSmiod  * OpenBSD/sh clock module
5695c7671fSmiod  *  + default 64Hz
5795c7671fSmiod  *  + use TMU channel 0 as clock interrupt source.
5854a9edacSmiod  *  + use TMU channel 1 as emulated software interrupt source.
599bec9e43Sjsg  *  + use TMU channel 2 as freerunning counter for timecounter.
6095c7671fSmiod  *  + If RTC module is active, TMU channel 0 input source is RTC output.
6195c7671fSmiod  *    (1.6384kHz)
6295c7671fSmiod  */
6395c7671fSmiod struct {
6495c7671fSmiod 	/* Hard clock */
6595c7671fSmiod 	uint32_t hz_cnt;	/* clock interrupt interval count */
6695c7671fSmiod 	uint32_t cpucycle_1us;	/* calibrated loop variable (1 us) */
6795c7671fSmiod 	uint32_t tmuclk;	/* source clock of TMU0 (Hz) */
6895c7671fSmiod 
6995c7671fSmiod 	/* RTC ops holder. default SH RTC module */
7095c7671fSmiod 	struct rtc_ops rtc;
7195c7671fSmiod 	int rtc_initialized;
7295c7671fSmiod 
7395c7671fSmiod 	uint32_t pclock;	/* PCLOCK */
7495c7671fSmiod 	uint32_t cpuclock;	/* CPU clock */
7595c7671fSmiod 	int flags;
7654a9edacSmiod 
7754a9edacSmiod 	struct timecounter tc;
7895c7671fSmiod } sh_clock = {
7995c7671fSmiod #ifdef PCLOCK
8095c7671fSmiod 	.pclock = PCLOCK,
8195c7671fSmiod #endif
8295c7671fSmiod 	.rtc = {
8395c7671fSmiod 		/* SH RTC module to default RTC */
8495c7671fSmiod 		.init	= sh_rtc_init,
8595c7671fSmiod 		.get	= sh_rtc_get,
8695c7671fSmiod 		.set	= sh_rtc_set
8795c7671fSmiod 	}
8895c7671fSmiod };
8995c7671fSmiod 
9095c7671fSmiod uint32_t maxwdog;
9195c7671fSmiod 
9295c7671fSmiod /* TMU */
9395c7671fSmiod /* interrupt handler is timing critical. prepared for each. */
9495c7671fSmiod int sh3_clock_intr(void *);
9595c7671fSmiod int sh4_clock_intr(void *);
9654a9edacSmiod u_int sh_timecounter_get(struct timecounter *);
9795c7671fSmiod 
9895c7671fSmiod /*
9995c7671fSmiod  * Estimate CPU and Peripheral clock.
10095c7671fSmiod  */
10195c7671fSmiod #define	TMU_START(x)							\
10295c7671fSmiod do {									\
10395c7671fSmiod 	_reg_bclr_1(SH_(TSTR), TSTR_STR##x);				\
10495c7671fSmiod 	_reg_write_4(SH_(TCNT ## x), 0xffffffff);			\
10595c7671fSmiod 	_reg_bset_1(SH_(TSTR), TSTR_STR##x);				\
10695c7671fSmiod } while (/*CONSTCOND*/0)
10754a9edacSmiod 
10895c7671fSmiod #define	TMU_ELAPSED(x)							\
10995c7671fSmiod 	(0xffffffff - _reg_read_4(SH_(TCNT ## x)))
1108f81a840Smiod 
11195c7671fSmiod void
sh_clock_init(int flags,struct rtc_ops * rtc)11295c7671fSmiod sh_clock_init(int flags, struct rtc_ops *rtc)
11395c7671fSmiod {
11454a9edacSmiod 	uint32_t s, t0, cnt_1s;
11595c7671fSmiod 
11695c7671fSmiod 	sh_clock.flags = flags;
11795c7671fSmiod 	if (rtc != NULL)
11895c7671fSmiod 		sh_clock.rtc = *rtc;	/* structure copy */
11995c7671fSmiod 
12095c7671fSmiod 	/* Initialize TMU */
12195c7671fSmiod 	_reg_write_2(SH_(TCR0), 0);
12295c7671fSmiod 	_reg_write_2(SH_(TCR1), 0);
12395c7671fSmiod 	_reg_write_2(SH_(TCR2), 0);
12495c7671fSmiod 
12595c7671fSmiod 	/* Reset RTC alarm and interrupt */
12695c7671fSmiod 	_reg_write_1(SH_(RCR1), 0);
12795c7671fSmiod 
12895c7671fSmiod 	/* Stop all counter */
12995c7671fSmiod 	_reg_write_1(SH_(TSTR), 0);
13095c7671fSmiod 
13195c7671fSmiod 	/*
13295c7671fSmiod 	 * Estimate CPU clock.
13395c7671fSmiod 	 */
13495c7671fSmiod 	if (sh_clock.flags & SH_CLOCK_NORTC) {
13595c7671fSmiod 		/* Set TMU channel 0 source to PCLOCK / 16 */
13695c7671fSmiod 		_reg_write_2(SH_(TCR0), TCR_TPSC_P16);
13795c7671fSmiod 		sh_clock.tmuclk = sh_clock.pclock / 16;
13895c7671fSmiod 	} else {
13995c7671fSmiod 		/* Set TMU channel 0 source to RTC counter clock (16.384kHz) */
14095c7671fSmiod 		_reg_write_2(SH_(TCR0),
14195c7671fSmiod 		    CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC);
14295c7671fSmiod 		sh_clock.tmuclk = SH_RTC_CLOCK;
14354a9edacSmiod 
14454a9edacSmiod 		/* Make sure RTC oscillator is enabled */
14554a9edacSmiod 		_reg_bset_1(SH_(RCR2), SH_RCR2_ENABLE);
14695c7671fSmiod 	}
14795c7671fSmiod 
14895c7671fSmiod 	s = _cpu_exception_suspend();
14995c7671fSmiod 	_cpu_spin(1);	/* load function on cache. */
15095c7671fSmiod 	TMU_START(0);
15195c7671fSmiod 	_cpu_spin(10000000);
15295c7671fSmiod 	t0 = TMU_ELAPSED(0);
15395c7671fSmiod 	_cpu_exception_resume(s);
15495c7671fSmiod 
15595c7671fSmiod 	sh_clock.cpucycle_1us = (sh_clock.tmuclk * 10) / t0;
15695c7671fSmiod 
15754a9edacSmiod 	cnt_1s = ((uint64_t)sh_clock.tmuclk * 10000000 * 10 + t0 / 2) / t0;
15895c7671fSmiod 	if (CPU_IS_SH4)
15954a9edacSmiod 		sh_clock.cpuclock = cnt_1s / 2;	/* two-issue */
16054a9edacSmiod 	else
16154a9edacSmiod 		sh_clock.cpuclock = cnt_1s;
16295c7671fSmiod 
16395c7671fSmiod 	/*
16495c7671fSmiod 	 * Estimate PCLOCK
16595c7671fSmiod 	 */
16695c7671fSmiod 	if (sh_clock.pclock == 0) {
16754a9edacSmiod 		uint32_t t1;
16854a9edacSmiod 
16995c7671fSmiod 		/* set TMU channel 1 source to PCLOCK / 4 */
17095c7671fSmiod 		_reg_write_2(SH_(TCR1), TCR_TPSC_P4);
17195c7671fSmiod 		s = _cpu_exception_suspend();
17295c7671fSmiod 		_cpu_spin(1);	/* load function on cache. */
17395c7671fSmiod 		TMU_START(0);
17495c7671fSmiod 		TMU_START(1);
17554a9edacSmiod 		_cpu_spin(cnt_1s); /* 1 sec. */
17695c7671fSmiod 		t0 = TMU_ELAPSED(0);
17795c7671fSmiod 		t1 = TMU_ELAPSED(1);
17895c7671fSmiod 		_cpu_exception_resume(s);
17995c7671fSmiod 
18054a9edacSmiod 		sh_clock.pclock =
18154a9edacSmiod 		    ((uint64_t)t1 * 4 * SH_RTC_CLOCK + t0 / 2) / t0;
18295c7671fSmiod 	}
18395c7671fSmiod 
18454a9edacSmiod 	/* Stop all counters */
18595c7671fSmiod 	_reg_write_1(SH_(TSTR), 0);
18695c7671fSmiod 
18795c7671fSmiod #undef TMU_START
18895c7671fSmiod #undef TMU_ELAPSED
18995c7671fSmiod }
19095c7671fSmiod 
19195c7671fSmiod int
sh_clock_get_cpuclock(void)1920f1d1626Stobiasu sh_clock_get_cpuclock(void)
19395c7671fSmiod {
19495c7671fSmiod 	return (sh_clock.cpuclock);
19595c7671fSmiod }
19695c7671fSmiod 
19795c7671fSmiod int
sh_clock_get_pclock(void)1980f1d1626Stobiasu sh_clock_get_pclock(void)
19995c7671fSmiod {
20095c7671fSmiod 	return (sh_clock.pclock);
20195c7671fSmiod }
20295c7671fSmiod 
20395c7671fSmiod void
setstatclockrate(int newhz)20495c7671fSmiod setstatclockrate(int newhz)
20595c7671fSmiod {
20695c7671fSmiod }
20795c7671fSmiod 
20854a9edacSmiod u_int
sh_timecounter_get(struct timecounter * tc)20954a9edacSmiod sh_timecounter_get(struct timecounter *tc)
21095c7671fSmiod {
21154a9edacSmiod 	return 0xffffffff - _reg_read_4(SH_(TCNT2));
21295c7671fSmiod }
21395c7671fSmiod 
21495c7671fSmiod /*
21595c7671fSmiod  *  Wait at least `n' usec.
21695c7671fSmiod  */
21795c7671fSmiod void
delay(int n)21895c7671fSmiod delay(int n)
21995c7671fSmiod {
22095c7671fSmiod 	_cpu_spin(sh_clock.cpucycle_1us * n);
22195c7671fSmiod }
22295c7671fSmiod 
223449137a4Skettenis extern todr_chip_handle_t todr_handle;
224449137a4Skettenis struct todr_chip_handle rtc_todr;
225449137a4Skettenis 
226449137a4Skettenis int
rtc_gettime(struct todr_chip_handle * handle,struct timeval * tv)227449137a4Skettenis rtc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
228449137a4Skettenis {
229449137a4Skettenis 	struct clock_ymdhms dt;
230449137a4Skettenis 
231449137a4Skettenis 	sh_clock.rtc.get(sh_clock.rtc._cookie, tv->tv_sec, &dt);
232449137a4Skettenis 	tv->tv_sec = clock_ymdhms_to_secs(&dt);
233449137a4Skettenis 	tv->tv_usec = 0;
234449137a4Skettenis 	return 0;
235449137a4Skettenis }
236449137a4Skettenis 
237449137a4Skettenis int
rtc_settime(struct todr_chip_handle * handle,struct timeval * tv)238449137a4Skettenis rtc_settime(struct todr_chip_handle *handle, struct timeval *tv)
239449137a4Skettenis {
240449137a4Skettenis 	struct clock_ymdhms dt;
241449137a4Skettenis 
242449137a4Skettenis 	clock_secs_to_ymdhms(tv->tv_sec, &dt);
243449137a4Skettenis 	sh_clock.rtc.set(sh_clock.rtc._cookie, &dt);
244449137a4Skettenis 	return 0;
245449137a4Skettenis }
246449137a4Skettenis 
24795c7671fSmiod /*
24895c7671fSmiod  * Start the clock interrupt.
24995c7671fSmiod  */
25095c7671fSmiod void
cpu_initclocks(void)2510f1d1626Stobiasu cpu_initclocks(void)
25295c7671fSmiod {
25395c7671fSmiod 	if (sh_clock.pclock == 0)
25495c7671fSmiod 		panic("No PCLOCK information.");
25595c7671fSmiod 
25695c7671fSmiod 	/* Set global variables. */
25795c7671fSmiod 	tick = 1000000 / hz;
258ee48eda3Scheloha 	tick_nsec = 1000000000 / hz;
25995c7671fSmiod 
260a2953de3Scheloha 	stathz = hz;
261a2953de3Scheloha 	profhz = stathz;
26211d1f9b2Scheloha }
263a2953de3Scheloha 
26411d1f9b2Scheloha void
cpu_startclock(void)26511d1f9b2Scheloha cpu_startclock(void)
26611d1f9b2Scheloha {
267a2953de3Scheloha 	clockintr_cpu_init(NULL);
268a2953de3Scheloha 
26995c7671fSmiod 	/*
27095c7671fSmiod 	 * Use TMU channel 0 as hard clock
27195c7671fSmiod 	 */
27295c7671fSmiod 	_reg_bclr_1(SH_(TSTR), TSTR_STR0);
27395c7671fSmiod 
27495c7671fSmiod 	if (sh_clock.flags & SH_CLOCK_NORTC) {
27595c7671fSmiod 		/* use PCLOCK/16 as TMU0 source */
27695c7671fSmiod 		_reg_write_2(SH_(TCR0), TCR_UNIE | TCR_TPSC_P16);
27795c7671fSmiod 	} else {
27895c7671fSmiod 		/* use RTC clock as TMU0 source */
27995c7671fSmiod 		_reg_write_2(SH_(TCR0), TCR_UNIE |
28095c7671fSmiod 		    (CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC));
28195c7671fSmiod 	}
28295c7671fSmiod 	sh_clock.hz_cnt = sh_clock.tmuclk / hz - 1;
28395c7671fSmiod 
28495c7671fSmiod 	_reg_write_4(SH_(TCOR0), sh_clock.hz_cnt);
28595c7671fSmiod 	_reg_write_4(SH_(TCNT0), sh_clock.hz_cnt);
28695c7671fSmiod 
28795c7671fSmiod 	intc_intr_establish(SH_INTEVT_TMU0_TUNI0, IST_LEVEL, IPL_CLOCK,
28895c7671fSmiod 	    CPU_IS_SH3 ? sh3_clock_intr : sh4_clock_intr, NULL, "clock");
28995c7671fSmiod 	/* start hardclock */
29095c7671fSmiod 	_reg_bset_1(SH_(TSTR), TSTR_STR0);
29195c7671fSmiod 
29295c7671fSmiod 	/*
29354a9edacSmiod 	 * TMU channel 1 is one shot timer for soft interrupts.
29495c7671fSmiod 	 */
29595c7671fSmiod 	_reg_write_2(SH_(TCR1), TCR_UNIE | TCR_TPSC_P4);
29695c7671fSmiod 	_reg_write_4(SH_(TCOR1), 0xffffffff);
29754a9edacSmiod 
29854a9edacSmiod 	/*
29954a9edacSmiod 	 * TMU channel 2 is freerunning counter for timecounter.
30054a9edacSmiod 	 */
30154a9edacSmiod 	_reg_write_2(SH_(TCR2), TCR_TPSC_P4);
30295c7671fSmiod 	_reg_write_4(SH_(TCOR2), 0xffffffff);
30395c7671fSmiod 
30454a9edacSmiod 	/*
30554a9edacSmiod 	 * Start and initialize timecounter.
30654a9edacSmiod 	 */
30754a9edacSmiod 	_reg_bset_1(SH_(TSTR), TSTR_STR2);
30854a9edacSmiod 
30954a9edacSmiod 	sh_clock.tc.tc_get_timecount = sh_timecounter_get;
31054a9edacSmiod 	sh_clock.tc.tc_frequency = sh_clock.pclock / 4;
31154a9edacSmiod 	sh_clock.tc.tc_name = "tmu_pclock_4";
31254a9edacSmiod 	sh_clock.tc.tc_quality = 100;
31354a9edacSmiod 	sh_clock.tc.tc_counter_mask = 0xffffffff;
31454a9edacSmiod 	tc_init(&sh_clock.tc);
31554a9edacSmiod 
31695c7671fSmiod 	/* Make sure to start RTC */
3178f81a840Smiod 	if (sh_clock.rtc.init != NULL)
31895c7671fSmiod 		sh_clock.rtc.init(sh_clock.rtc._cookie);
31995c7671fSmiod 
320449137a4Skettenis 	rtc_todr.todr_gettime = rtc_gettime;
321449137a4Skettenis 	rtc_todr.todr_settime = rtc_settime;
322449137a4Skettenis 	todr_handle = &rtc_todr;
32395c7671fSmiod }
32495c7671fSmiod 
32595c7671fSmiod #ifdef SH3
32695c7671fSmiod int
sh3_clock_intr(void * arg)32795c7671fSmiod sh3_clock_intr(void *arg) /* trap frame */
32895c7671fSmiod {
32995c7671fSmiod #if (NWDOG > 0)
33095c7671fSmiod 	uint32_t i;
33195c7671fSmiod 
33295c7671fSmiod 	i = (uint32_t)SHREG_WTCNT_R;
33395c7671fSmiod 	if (i > maxwdog)
33495c7671fSmiod 		maxwdog = i;
33595c7671fSmiod 	wdog_wr_cnt(0);			/* reset to zero */
33695c7671fSmiod #endif
33795c7671fSmiod 	/* clear underflow status */
33895c7671fSmiod 	_reg_bclr_2(SH3_TCR0, TCR_UNF);
33995c7671fSmiod 
340a2953de3Scheloha 	clockintr_dispatch(arg);
34195c7671fSmiod 
34295c7671fSmiod 	return (1);
34395c7671fSmiod }
34495c7671fSmiod #endif /* SH3 */
34595c7671fSmiod 
34695c7671fSmiod #ifdef SH4
34795c7671fSmiod int
sh4_clock_intr(void * arg)34895c7671fSmiod sh4_clock_intr(void *arg) /* trap frame */
34995c7671fSmiod {
35095c7671fSmiod #if (NWDOG > 0)
35195c7671fSmiod 	uint32_t i;
35295c7671fSmiod 
35395c7671fSmiod 	i = (uint32_t)SHREG_WTCNT_R;
35495c7671fSmiod 	if (i > maxwdog)
35595c7671fSmiod 		maxwdog = i;
35695c7671fSmiod 	wdog_wr_cnt(0);			/* reset to zero */
35795c7671fSmiod #endif
35895c7671fSmiod 	/* clear underflow status */
35995c7671fSmiod 	_reg_bclr_2(SH4_TCR0, TCR_UNF);
36095c7671fSmiod 
361a2953de3Scheloha 	clockintr_dispatch(arg);
36295c7671fSmiod 
36395c7671fSmiod 	return (1);
36495c7671fSmiod }
36595c7671fSmiod #endif /* SH4 */
36695c7671fSmiod 
36795c7671fSmiod /*
36895c7671fSmiod  * SH3 RTC module ops.
36995c7671fSmiod  */
37095c7671fSmiod 
37195c7671fSmiod void
sh_rtc_init(void * cookie)37295c7671fSmiod sh_rtc_init(void *cookie)
37395c7671fSmiod {
37495c7671fSmiod 	/* Make sure to start RTC */
37595c7671fSmiod 	_reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
37695c7671fSmiod }
37795c7671fSmiod 
37895c7671fSmiod void
sh_rtc_get(void * cookie,time_t base,struct clock_ymdhms * dt)37995c7671fSmiod sh_rtc_get(void *cookie, time_t base, struct clock_ymdhms *dt)
38095c7671fSmiod {
38195c7671fSmiod 	int retry = 8;
38295c7671fSmiod 
38395c7671fSmiod 	/* disable carry interrupt */
38495c7671fSmiod 	_reg_bclr_1(SH_(RCR1), SH_RCR1_CIE);
38595c7671fSmiod 
38695c7671fSmiod 	do {
38795c7671fSmiod 		uint8_t r = _reg_read_1(SH_(RCR1));
38895c7671fSmiod 		r &= ~SH_RCR1_CF;
38995c7671fSmiod 		r |= SH_RCR1_AF; /* don't clear alarm flag */
39095c7671fSmiod 		_reg_write_1(SH_(RCR1), r);
39195c7671fSmiod 
39295c7671fSmiod 		if (CPU_IS_SH3)
39395c7671fSmiod 			dt->dt_year = FROMBCD(_reg_read_1(SH3_RYRCNT));
39495c7671fSmiod 		else
39595c7671fSmiod 			dt->dt_year = FROMBCD(_reg_read_2(SH4_RYRCNT) & 0x00ff);
39695c7671fSmiod 
39795c7671fSmiod 		/* read counter */
39895c7671fSmiod #define	RTCGET(x, y)	dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT)))
39995c7671fSmiod 		RTCGET(mon, MON);
40095c7671fSmiod 		RTCGET(wday, WK);
40195c7671fSmiod 		RTCGET(day, DAY);
40295c7671fSmiod 		RTCGET(hour, HR);
40395c7671fSmiod 		RTCGET(min, MIN);
40495c7671fSmiod 		RTCGET(sec, SEC);
40595c7671fSmiod #undef RTCGET
40695c7671fSmiod 	} while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
40795c7671fSmiod 
40895c7671fSmiod 	if (retry == 0) {
40995c7671fSmiod 		printf("rtc_gettime: couldn't read RTC register.\n");
41095c7671fSmiod 		memset(dt, 0, sizeof(*dt));
41195c7671fSmiod 		return;
41295c7671fSmiod 	}
41395c7671fSmiod 
41495c7671fSmiod 	dt->dt_year = (dt->dt_year % 100) + 1900;
41595c7671fSmiod 	if (dt->dt_year < 1970)
41695c7671fSmiod 		dt->dt_year += 100;
41795c7671fSmiod }
41895c7671fSmiod 
41995c7671fSmiod void
sh_rtc_set(void * cookie,struct clock_ymdhms * dt)42095c7671fSmiod sh_rtc_set(void *cookie, struct clock_ymdhms *dt)
42195c7671fSmiod {
42295c7671fSmiod 	uint8_t r;
42395c7671fSmiod 
42495c7671fSmiod 	/* stop clock */
42595c7671fSmiod 	r = _reg_read_1(SH_(RCR2));
42695c7671fSmiod 	r |= SH_RCR2_RESET;
42795c7671fSmiod 	r &= ~SH_RCR2_START;
42895c7671fSmiod 	_reg_write_1(SH_(RCR2), r);
42995c7671fSmiod 
43095c7671fSmiod 	/* set time */
43195c7671fSmiod 	if (CPU_IS_SH3)
43295c7671fSmiod 		_reg_write_1(SH3_RYRCNT, TOBCD(dt->dt_year % 100));
43395c7671fSmiod 	else
43495c7671fSmiod 		_reg_write_2(SH4_RYRCNT, TOBCD(dt->dt_year % 100));
43595c7671fSmiod #define	RTCSET(x, y)	_reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y))
43695c7671fSmiod 	RTCSET(MON, mon);
43795c7671fSmiod 	RTCSET(WK, wday);
43895c7671fSmiod 	RTCSET(DAY, day);
43995c7671fSmiod 	RTCSET(HR, hour);
44095c7671fSmiod 	RTCSET(MIN, min);
44195c7671fSmiod 	RTCSET(SEC, sec);
44295c7671fSmiod #undef RTCSET
44395c7671fSmiod 	/* start clock */
44495c7671fSmiod 	_reg_write_1(SH_(RCR2), r | SH_RCR2_START);
44595c7671fSmiod }
446