]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/powerpc/booke/clock.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / powerpc / booke / clock.c
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$");
60
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/kernel.h>
64 #include <sys/sysctl.h>
65 #include <sys/bus.h>
66 #include <sys/interrupt.h>
67 #include <sys/ktr.h>
68 #include <sys/pcpu.h>
69 #include <sys/timeet.h>
70 #include <sys/timetc.h>
71
72 #include <machine/clock.h>
73 #include <machine/intr_machdep.h>
74 #include <machine/platform.h>
75 #include <machine/psl.h>
76 #include <machine/spr.h>
77 #include <machine/cpu.h>
78 #include <machine/md_var.h>
79
80 /*
81  * Initially we assume a processor with a bus frequency of 12.5 MHz.
82  */
83 static int              initialized = 0;
84 static u_long           ns_per_tick = 80;
85 static u_long           ticks_per_sec = 12500000;
86 static u_long           *decr_counts[MAXCPU];
87
88 #define DIFF19041970    2082844800
89
90 static int              decr_et_start(struct eventtimer *et,
91     struct bintime *first, struct bintime *period);
92 static int              decr_et_stop(struct eventtimer *et);
93 static timecounter_get_t decr_get_timecount;
94
95 struct decr_state {
96         int     mode;   /* 0 - off, 1 - periodic, 2 - one-shot. */
97         int32_t div;    /* Periodic divisor. */
98 };
99 static DPCPU_DEFINE(struct decr_state, decr_state);
100
101 static struct eventtimer        decr_et;
102 static struct timecounter       decr_timecounter = {
103         decr_get_timecount,     /* get_timecount */
104         0,                      /* no poll_pps */
105         ~0u,                    /* counter_mask */
106         0,                      /* frequency */
107         "timebase"              /* name */
108 };
109
110 /*
111  * Decrementer interrupt handler.
112  */
113 void
114 decr_intr(struct trapframe *frame)
115 {
116         struct decr_state *s = DPCPU_PTR(decr_state);
117
118         if (!initialized)
119                 return;
120
121         (*decr_counts[curcpu])++;
122
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
129         CTR1(KTR_INTR, "%s: DEC interrupt", __func__);
130
131         if (s->mode == 2)
132                 decr_et_stop(NULL);
133
134         if (decr_et.et_active)
135                 decr_et.et_event_cb(&decr_et, decr_et.et_arg);
136 }
137
138 void
139 cpu_initclocks(void)
140 {
141
142         decr_tc_init();
143         cpu_initclocks_bsp();
144 }
145
146 /*
147  * BSP early initialization.
148  */
149 void
150 decr_init(void)
151 {
152         struct cpuref cpu;
153         char buf[32];
154
155         if (platform_smp_get_bsp(&cpu) != 0)
156                 platform_smp_first_cpu(&cpu);
157         ticks_per_sec = platform_timebase_freq(&cpu);
158         ns_per_tick = 1000000000 / ticks_per_sec;
159
160         set_cputicker(mftb, ticks_per_sec, 0);
161         snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
162         intrcnt_add(buf, &decr_counts[curcpu]);
163         decr_et_stop(NULL);
164         initialized = 1;
165 }
166
167 #ifdef SMP
168 /*
169  * AP early initialization.
170  */
171 void
172 decr_ap_init(void)
173 {
174         char buf[32];
175
176         snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
177         intrcnt_add(buf, &decr_counts[curcpu]);
178         decr_et_stop(NULL);
179 }
180 #endif
181
182 /*
183  * Final initialization.
184  */
185 void
186 decr_tc_init(void)
187 {
188
189         decr_timecounter.tc_frequency = ticks_per_sec;
190         tc_init(&decr_timecounter);
191         decr_et.et_name = "decrementer";
192         decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
193             ET_FLAGS_PERCPU;
194         decr_et.et_quality = 1000;
195         decr_et.et_frequency = ticks_per_sec;
196         decr_et.et_min_period.sec = 0;
197         decr_et.et_min_period.frac =
198             ((0x00000002LLU << 32) / ticks_per_sec) << 32;
199         decr_et.et_max_period.sec = 0xfffffffeLLU / ticks_per_sec;
200         decr_et.et_max_period.frac =
201             ((0xfffffffeLLU << 32) / ticks_per_sec) << 32;
202         decr_et.et_start = decr_et_start;
203         decr_et.et_stop = decr_et_stop;
204         decr_et.et_priv = NULL;
205         et_register(&decr_et);
206 }
207
208 /*
209  * Event timer start method.
210  */
211 static int
212 decr_et_start(struct eventtimer *et,
213     struct bintime *first, struct bintime *period)
214 {
215         struct decr_state *s = DPCPU_PTR(decr_state);
216         uint32_t fdiv, tcr;
217
218         if (period != NULL) {
219                 s->mode = 1;
220                 s->div = (decr_et.et_frequency * (period->frac >> 32)) >> 32;
221                 if (period->sec != 0)
222                         s->div += decr_et.et_frequency * period->sec;
223         } else {
224                 s->mode = 2;
225                 s->div = 0xffffffff;
226         }
227         if (first != NULL) {
228                 fdiv = (decr_et.et_frequency * (first->frac >> 32)) >> 32;
229                 if (first->sec != 0)
230                         fdiv += decr_et.et_frequency * first->sec;
231         } else
232                 fdiv = s->div;
233
234         tcr = mfspr(SPR_TCR);
235         tcr |= TCR_DIE;
236         if (s->mode == 1) {
237                 mtspr(SPR_DECAR, s->div);
238                 tcr |= TCR_ARE;
239         } else
240                 tcr &= ~TCR_ARE;
241         mtdec(fdiv);
242         mtspr(SPR_TCR, tcr);
243         return (0);
244 }
245
246 /*
247  * Event timer stop method.
248  */
249 static int
250 decr_et_stop(struct eventtimer *et)
251 {
252         struct decr_state *s = DPCPU_PTR(decr_state);
253         uint32_t tcr;
254
255         s->mode = 0;
256         s->div = 0xffffffff;
257         tcr = mfspr(SPR_TCR);
258         tcr &= ~(TCR_DIE | TCR_ARE);
259         mtspr(SPR_TCR, tcr);
260         return (0);
261 }
262
263 /*
264  * Timecounter get method.
265  */
266 static unsigned
267 decr_get_timecount(struct timecounter *tc)
268 {
269         quad_t tb;
270
271         tb = mftb();
272         return (tb);
273 }
274
275 /*
276  * Wait for about n microseconds (at least!).
277  */
278 void
279 DELAY(int n)
280 {
281         u_quad_t start, end, now;
282
283         start = mftb();
284         end = start + (u_quad_t)ticks_per_sec / (1000000ULL / n);
285         do {
286                 now = mftb();
287         } while (now < end || (now > start && end < start));
288 }
289