1 /*-
2 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
3 * Copyright (C) 1995, 1996 TooLs GmbH.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by TooLs GmbH.
17 * 4. The name of TooLs GmbH may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $
32 */
33 /*
34 * Copyright (C) 2001 Benno Rice.
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 *
46 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57
58 #include <sys/cdefs.h>
59 __FBSDID("$FreeBSD: releng/11.1/sys/powerpc/powerpc/clock.c 298642 2016-04-26 14:44:49Z pfg $");
60
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/kernel.h>
64 #include <sys/bus.h>
65 #include <sys/interrupt.h>
66 #include <sys/pcpu.h>
67 #include <sys/sysctl.h>
68 #include <sys/timeet.h>
69 #include <sys/timetc.h>
70
71 #include <dev/ofw/openfirm.h>
72
73 #include <machine/clock.h>
74 #include <machine/cpu.h>
75 #include <machine/intr_machdep.h>
76 #include <machine/md_var.h>
77 #include <machine/smp.h>
78
79 /*
80 * Initially we assume a processor with a bus frequency of 12.5 MHz.
81 */
82 static int initialized = 0;
83 static u_long ns_per_tick = 80;
84 static u_long ticks_per_sec = 12500000;
85 static u_long *decr_counts[MAXCPU];
86
87 static int decr_et_start(struct eventtimer *et,
88 sbintime_t first, sbintime_t period);
89 static int decr_et_stop(struct eventtimer *et);
90 static timecounter_get_t decr_get_timecount;
91
92 struct decr_state {
93 int mode; /* 0 - off, 1 - periodic, 2 - one-shot. */
94 int32_t div; /* Periodic divisor. */
95 };
96 static DPCPU_DEFINE(struct decr_state, decr_state);
97
98 static struct eventtimer decr_et;
99 static struct timecounter decr_tc = {
100 decr_get_timecount, /* get_timecount */
101 0, /* no poll_pps */
102 ~0u, /* counter_mask */
103 0, /* frequency */
104 "timebase" /* name */
105 };
106
107 /*
108 * Decrementer interrupt handler.
109 */
110 void
111 decr_intr(struct trapframe *frame)
112 {
113 struct decr_state *s = DPCPU_PTR(decr_state);
114 int nticks = 0;
115 int32_t val;
116
117 if (!initialized)
118 return;
119
120 (*decr_counts[curcpu])++;
121
122 #ifdef BOOKE
123 /*
124 * Interrupt handler must reset DIS to avoid getting another
125 * interrupt once EE is enabled.
126 */
127 mtspr(SPR_TSR, TSR_DIS);
128 #endif
129
130 if (s->mode == 1) {
131 /*
132 * Based on the actual time delay since the last decrementer
133 * reload, we arrange for earlier interrupt next time.
134 */
135 __asm ("mfdec %0" : "=r"(val));
136 while (val < 0) {
137 val += s->div;
138 nticks++;
139 }
140 mtdec(val);
141 } else if (s->mode == 2) {
142 nticks = 1;
143 decr_et_stop(NULL);
144 }
145
146 while (nticks-- > 0) {
147 if (decr_et.et_active)
148 decr_et.et_event_cb(&decr_et, decr_et.et_arg);
149 }
150 }
151
152 void
153 cpu_initclocks(void)
154 {
155
156 decr_tc_init();
157 cpu_initclocks_bsp();
158 }
159
160 /*
161 * BSP early initialization.
162 */
163 void
164 decr_init(void)
165 {
166 struct cpuref cpu;
167 char buf[32];
168
169 /*
170 * Check the BSP's timebase frequency. Sometimes we can't find the BSP,
171 * so fall back to the first CPU in this case.
172 */
173 if (platform_smp_get_bsp(&cpu) != 0)
174 platform_smp_first_cpu(&cpu);
175 ticks_per_sec = platform_timebase_freq(&cpu);
176 ns_per_tick = 1000000000 / ticks_per_sec;
177
178 set_cputicker(mftb, ticks_per_sec, 0);
179 snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
180 intrcnt_add(buf, &decr_counts[curcpu]);
181 decr_et_stop(NULL);
182 initialized = 1;
183 }
184
185 #ifdef SMP
186 /*
187 * AP early initialization.
188 */
189 void
190 decr_ap_init(void)
191 {
192 char buf[32];
193
194 snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
195 intrcnt_add(buf, &decr_counts[curcpu]);
196 decr_et_stop(NULL);
197 }
198 #endif
199
200 /*
201 * Final initialization.
202 */
203 void
204 decr_tc_init(void)
205 {
206
207 decr_tc.tc_frequency = ticks_per_sec;
208 tc_init(&decr_tc);
209 decr_et.et_name = "decrementer";
210 decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
211 ET_FLAGS_PERCPU;
212 decr_et.et_quality = 1000;
213 decr_et.et_frequency = ticks_per_sec;
214 decr_et.et_min_period = (0x00000002LLU << 32) / ticks_per_sec;
215 decr_et.et_max_period = (0x7fffffffLLU << 32) / ticks_per_sec;
216 decr_et.et_start = decr_et_start;
217 decr_et.et_stop = decr_et_stop;
218 decr_et.et_priv = NULL;
219 et_register(&decr_et);
220 }
221
222 /*
223 * Event timer start method.
224 */
225 static int
226 decr_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
227 {
228 struct decr_state *s = DPCPU_PTR(decr_state);
229 uint32_t fdiv;
230 #ifdef BOOKE
231 uint32_t tcr;
232 #endif
233
234 if (period != 0) {
235 s->mode = 1;
236 s->div = (decr_et.et_frequency * period) >> 32;
237 } else {
238 s->mode = 2;
239 s->div = 0;
240 }
241 if (first != 0)
242 fdiv = (decr_et.et_frequency * first) >> 32;
243 else
244 fdiv = s->div;
245
246 #ifdef BOOKE
247 tcr = mfspr(SPR_TCR);
248 tcr |= TCR_DIE;
249 if (s->mode == 1) {
250 mtspr(SPR_DECAR, s->div);
251 tcr |= TCR_ARE;
252 } else
253 tcr &= ~TCR_ARE;
254 mtdec(fdiv);
255 mtspr(SPR_TCR, tcr);
256 #else
257 mtdec(fdiv);
258 #endif
259
260 return (0);
261 }
262
263 /*
264 * Event timer stop method.
265 */
266 static int
267 decr_et_stop(struct eventtimer *et)
268 {
269 struct decr_state *s = DPCPU_PTR(decr_state);
270 #ifdef BOOKE
271 uint32_t tcr;
272 #endif
273
274 s->mode = 0;
275 s->div = 0x7fffffff;
276 #ifdef BOOKE
277 tcr = mfspr(SPR_TCR);
278 tcr &= ~(TCR_DIE | TCR_ARE);
279 mtspr(SPR_TCR, tcr);
280 #else
281 mtdec(s->div);
282 #endif
283 return (0);
284 }
285
286 /*
287 * Timecounter get method.
288 */
289 static unsigned
290 decr_get_timecount(struct timecounter *tc)
291 {
292 return (mftb());
293 }
294
295 /*
296 * Wait for about n microseconds (at least!).
297 */
298 void
299 DELAY(int n)
300 {
301 u_quad_t tb, ttb;
302
303 tb = mftb();
304 ttb = tb + howmany(n * 1000, ns_per_tick);
305 while (tb < ttb)
306 tb = mftb();
307 }
308
Cache object: 709374a938ef4dbe5afde02d139d0a62
|