]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/powerpc/booke/clock.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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     sbintime_t first, sbintime_t 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 = (0x00000002LLU << 32) / ticks_per_sec;
197         decr_et.et_max_period = (0xfffffffeLLU << 32) / ticks_per_sec;
198         decr_et.et_start = decr_et_start;
199         decr_et.et_stop = decr_et_stop;
200         decr_et.et_priv = NULL;
201         et_register(&decr_et);
202 }
203
204 /*
205  * Event timer start method.
206  */
207 static int
208 decr_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
209 {
210         struct decr_state *s = DPCPU_PTR(decr_state);
211         uint32_t fdiv, tcr;
212
213         if (period != 0) {
214                 s->mode = 1;
215                 s->div = (decr_et.et_frequency * period) >> 32;
216         } else {
217                 s->mode = 2;
218                 s->div = 0;
219         }
220         if (first != 0)
221                 fdiv = (decr_et.et_frequency * first) >> 32;
222         else
223                 fdiv = s->div;
224
225         tcr = mfspr(SPR_TCR);
226         tcr |= TCR_DIE;
227         if (s->mode == 1) {
228                 mtspr(SPR_DECAR, s->div);
229                 tcr |= TCR_ARE;
230         } else
231                 tcr &= ~TCR_ARE;
232         mtdec(fdiv);
233         mtspr(SPR_TCR, tcr);
234         return (0);
235 }
236
237 /*
238  * Event timer stop method.
239  */
240 static int
241 decr_et_stop(struct eventtimer *et)
242 {
243         struct decr_state *s = DPCPU_PTR(decr_state);
244         uint32_t tcr;
245
246         s->mode = 0;
247         s->div = 0xffffffff;
248         tcr = mfspr(SPR_TCR);
249         tcr &= ~(TCR_DIE | TCR_ARE);
250         mtspr(SPR_TCR, tcr);
251         return (0);
252 }
253
254 /*
255  * Timecounter get method.
256  */
257 static unsigned
258 decr_get_timecount(struct timecounter *tc)
259 {
260         quad_t tb;
261
262         tb = mftb();
263         return (tb);
264 }
265
266 /*
267  * Wait for about n microseconds (at least!).
268  */
269 void
270 DELAY(int n)
271 {
272         u_quad_t start, end, now;
273
274         start = mftb();
275         end = start + (u_quad_t)ticks_per_sec / (1000000ULL / n);
276         do {
277                 now = mftb();
278         } while (now < end || (now > start && end < start));
279 }
280