xref: /openbsd/sys/arch/macppc/macppc/clock.c (revision 0ed1bf01)
1 /*	$OpenBSD: clock.c,v 1.58 2023/09/17 14:50:51 cheloha Exp $	*/
2 /*	$NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6  * Copyright (C) 1995, 1996 TooLs GmbH.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by TooLs GmbH.
20  * 4. The name of TooLs GmbH may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/clockintr.h>
39 #include <sys/evcount.h>
40 #include <sys/stdint.h>
41 #include <sys/timetc.h>
42 
43 #include <machine/autoconf.h>
44 #include <machine/pio.h>
45 #include <machine/intr.h>
46 #include <machine/vmparam.h>
47 
48 #include <dev/clock_subr.h>
49 #include <dev/ofw/openfirm.h>
50 
51 void dec_rearm(void *, uint64_t);
52 void dec_trigger(void *);
53 void decr_intr(struct clockframe *frame);
54 u_int tb_get_timecount(struct timecounter *);
55 
56 /*
57  * Initially we assume a processor with a bus frequency of 12.5 MHz.
58  */
59 u_int32_t ticks_per_sec = 3125000;
60 u_int32_t ns_per_tick = 320;
61 uint64_t dec_nsec_cycle_ratio;
62 uint64_t dec_nsec_max;
63 int clock_initialized;
64 
65 const struct intrclock dec_intrclock = {
66 	.ic_rearm = dec_rearm,
67 	.ic_trigger = dec_trigger
68 };
69 
70 static struct timecounter tb_timecounter = {
71 	.tc_get_timecount = tb_get_timecount,
72 	.tc_counter_mask = 0xffffffff,
73 	.tc_frequency = 0,
74 	.tc_name = "tb",
75 	.tc_quality = 0,
76 	.tc_priv = NULL,
77 	.tc_user = TC_TB,
78 };
79 
80 /* calibrate the timecounter frequency for the listed models */
81 static const char *calibrate_tc_models[] = {
82 	"PowerMac10,1"
83 };
84 
85 time_read_t  *time_read;
86 time_write_t *time_write;
87 
88 static struct evcount clk_count;
89 static int clk_irq = PPC_CLK_IRQ;
90 
91 extern todr_chip_handle_t todr_handle;
92 struct todr_chip_handle rtc_todr;
93 
94 int
rtc_gettime(struct todr_chip_handle * handle,struct timeval * tv)95 rtc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
96 {
97 	time_t sec;
98 
99 	if (time_read == NULL)
100 		return ENXIO;
101 
102 	(*time_read)(&sec);
103 	tv->tv_sec = sec - utc_offset;
104 	tv->tv_usec = 0;
105 	return 0;
106 }
107 
108 int
rtc_settime(struct todr_chip_handle * handle,struct timeval * tv)109 rtc_settime(struct todr_chip_handle *handle, struct timeval *tv)
110 {
111 	if (time_write == NULL)
112 		return ENXIO;
113 
114 	(*time_write)(tv->tv_sec + utc_offset);
115 	return 0;
116 }
117 
118 void
decr_intr(struct clockframe * frame)119 decr_intr(struct clockframe *frame)
120 {
121 	struct cpu_info *ci = curcpu();
122 	int s;
123 
124 	if (!clock_initialized)
125 		return;
126 
127 	clk_count.ec_count++;		/* XXX not atomic */
128 
129 	ppc_mtdec(UINT32_MAX >> 1);	/* clear DEC exception */
130 
131 	/*
132 	 * We can't actually mask DEC interrupts at or above IPL_CLOCK
133 	 * without masking other essential interrupts.  To simulate
134 	 * masking, we retrigger the DEC by hand from splx(9) the next
135 	 * time our IPL drops below IPL_CLOCK.
136 	 */
137 	if (ci->ci_cpl >= IPL_CLOCK) {
138 		ci->ci_dec_deferred = 1;
139 		return;
140 	}
141 	ci->ci_dec_deferred = 0;
142 
143 	s = splclock();
144 	ppc_intr_enable(1);
145 	clockintr_dispatch(frame);
146 	splx(s);
147 	(void) ppc_intr_disable();
148 }
149 
150 void
cpu_initclocks(void)151 cpu_initclocks(void)
152 {
153 	int intrstate;
154 	u_int32_t first_tb, second_tb;
155 	time_t first_sec, sec;
156 	int calibrate = 0, n;
157 
158 	/* check if we should calibrate the timecounter frequency */
159 	for (n = 0; n < sizeof(calibrate_tc_models) /
160 	    sizeof(calibrate_tc_models[0]); n++) {
161 		if (!strcmp(calibrate_tc_models[n], hw_prod)) {
162 			calibrate = 1;
163 			break;
164 		}
165 	}
166 
167 	/* if a RTC is available, calibrate the timecounter frequency */
168 	if (calibrate && time_read != NULL) {
169 		time_read(&first_sec);
170 		do {
171 			first_tb = ppc_mftbl();
172 			time_read(&sec);
173 		} while (sec == first_sec);
174 		first_sec = sec;
175 		do {
176 			second_tb = ppc_mftbl();
177 			time_read(&sec);
178 		} while (sec == first_sec);
179 		ticks_per_sec = second_tb - first_tb;
180 #ifdef DEBUG
181 		printf("tb: using measured timecounter frequency of %ld Hz\n",
182 		    ticks_per_sec);
183 #endif
184 	}
185 	ns_per_tick = 1000000000 / ticks_per_sec;
186 
187 	tb_timecounter.tc_frequency = ticks_per_sec;
188 	tc_init(&tb_timecounter);
189 
190 	rtc_todr.todr_gettime = rtc_gettime;
191 	rtc_todr.todr_settime = rtc_settime;
192 	todr_handle = &rtc_todr;
193 
194 	intrstate = ppc_intr_disable();
195 
196 	stathz = hz;
197 	profhz = stathz * 10;
198 	statclock_is_randomized = 1;
199 
200 	dec_nsec_cycle_ratio = ticks_per_sec * (1ULL << 32) / 1000000000;
201 	dec_nsec_max = UINT64_MAX / dec_nsec_cycle_ratio;
202 
203 	evcount_attach(&clk_count, "clock", &clk_irq);
204 
205 	ppc_intr_enable(intrstate);
206 }
207 
208 void
cpu_startclock(void)209 cpu_startclock(void)
210 {
211 	clock_initialized = 1;
212 	clockintr_cpu_init(&dec_intrclock);
213 	clockintr_trigger();
214 }
215 
216 /*
217  * Wait for about n microseconds (us) (at least!).
218  */
219 void
delay(unsigned n)220 delay(unsigned n)
221 {
222 	u_int64_t tb;
223 
224 	tb = ppc_mftb();
225 	tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
226 	while (tb > ppc_mftb())
227 		;
228 }
229 
230 void
setstatclockrate(int newhz)231 setstatclockrate(int newhz)
232 {
233 }
234 
235 u_int
tb_get_timecount(struct timecounter * tc)236 tb_get_timecount(struct timecounter *tc)
237 {
238 	return ppc_mftbl();
239 }
240 
241 void
dec_rearm(void * unused,uint64_t nsecs)242 dec_rearm(void *unused, uint64_t nsecs)
243 {
244 	uint32_t cycles;
245 
246 	if (nsecs > dec_nsec_max)
247 		nsecs = dec_nsec_max;
248 	cycles = (nsecs * dec_nsec_cycle_ratio) >> 32;
249 	if (cycles > UINT32_MAX >> 1)
250 		cycles = UINT32_MAX >> 1;
251 	ppc_mtdec(cycles);
252 }
253 
254 void
dec_trigger(void * unused)255 dec_trigger(void *unused)
256 {
257 	int s;
258 
259 	s = ppc_intr_disable();
260 	ppc_mtdec(0);
261 	ppc_mtdec(UINT32_MAX);
262 	ppc_intr_enable(s);
263 }
264