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