No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / powerpc / powerpc / clock.c
blob612965d94fb68699bdf5e2852b3d765c613830aa
1 /* $NetBSD: clock.c,v 1.5 2008/01/08 12:05:49 joerg Exp $ */
2 /* $OpenBSD: clock.c,v 1.3 1997/10/13 13:42:53 pefo Exp $ */
4 /*
5 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6 * Copyright (C) 1995, 1996 TooLs GmbH.
7 * All rights reserved.
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.
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.
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.5 2008/01/08 12:05:49 joerg Exp $");
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/timetc.h>
44 #include <uvm/uvm_extern.h>
46 #include <powerpc/spr.h>
48 void decr_intr(struct clockframe *);
49 void init_powerpc_tc(void);
50 static u_int get_powerpc_timecount(struct timecounter *);
52 uint32_t ticks_per_sec;
53 uint32_t ns_per_tick;
54 uint32_t ticks_per_intr = 0;
56 static struct timecounter powerpc_timecounter = {
57 get_powerpc_timecount, /* get_timecount */
58 0, /* no poll_pps */
59 0x7fffffff, /* counter_mask */
60 0, /* frequency */
61 "mftb", /* name */
62 100, /* quality */
63 NULL, /* tc_priv */
64 NULL /* tc_next */
68 * Start the real-time and statistics clocks. Leave stathz 0 since there
69 * are no other timers available.
71 void
72 cpu_initclocks(void)
74 struct cpu_info * const ci = curcpu();
75 uint32_t msr;
77 ticks_per_intr = ticks_per_sec / hz;
78 cpu_timebase = ticks_per_sec;
79 #ifdef PPC_OEA601
80 if ((mfpvr() >> 16) == MPC601)
81 __asm volatile
82 ("mfspr %0,%1" : "=r"(ci->ci_lasttb) : "n"(SPR_RTCL_R));
83 else
84 #endif
85 __asm volatile ("mftb %0" : "=r"(ci->ci_lasttb));
86 __asm volatile ("mtdec %0" :: "r"(ticks_per_intr));
87 init_powerpc_tc();
90 * Now allow all hardware interrupts including hardclock(9).
92 __asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
93 : "=r"(msr) : "K"(PSL_EE|PSL_RI));
97 * We assume newhz is either stathz or profhz, and that neither will
98 * change after being set up above. Could recalculate intervals here
99 * but that would be a drag.
101 void
102 setstatclockrate(int arg)
105 /* Nothing we can do */
108 void
109 decr_intr(struct clockframe *frame)
111 struct cpu_info * const ci = curcpu();
112 int msr;
113 int pri;
114 u_long tb;
115 long ticks;
116 int nticks;
118 /* Check whether we are initialized */
119 if (!ticks_per_intr)
120 return;
123 * Based on the actual time delay since the last decrementer reload,
124 * we arrange for earlier interrupt next time.
126 __asm ("mfdec %0" : "=r"(ticks));
127 for (nticks = 0; ticks < 0; nticks++)
128 ticks += ticks_per_intr;
129 __asm volatile ("mtdec %0" :: "r"(ticks));
131 uvmexp.intrs++;
132 ci->ci_ev_clock.ev_count++;
134 pri = splclock();
135 if (pri & (1 << SPL_CLOCK)) {
136 ci->ci_tickspending += nticks;
137 } else {
138 nticks += ci->ci_tickspending;
139 ci->ci_tickspending = 0;
142 * lasttb is used during microtime. Set it to the virtual
143 * start of this tick interval.
145 #ifdef PPC_OEA601
146 if ((mfpvr() >> 16) == MPC601)
147 __asm volatile
148 ("mfspr %0,%1" : "=r"(tb) : "n"(SPR_RTCL_R));
149 else
150 #endif
151 __asm volatile ("mftb %0" : "=r"(tb));
153 ci->ci_lasttb = tb + ticks - ticks_per_intr;
156 * Reenable interrupts
158 __asm volatile ("mfmsr %0; ori %0, %0, %1; mtmsr %0"
159 : "=r"(msr) : "K"(PSL_EE));
162 * Do standard timer interrupt stuff.
163 * Do softclock stuff only on the last iteration.
165 frame->pri = pri | (1 << SIR_CLOCK);
166 while (--nticks > 0)
167 hardclock(frame);
168 frame->pri = pri;
169 hardclock(frame);
171 splx(pri);
175 * Wait for about n microseconds (at least!).
177 void
178 delay(unsigned int n)
180 u_quad_t tb;
181 u_long tbh, tbl, scratch;
183 #ifdef PPC_OEA601
184 if ((mfpvr() >> 16) == MPC601) {
185 u_int32_t rtc[2];
187 mfrtc(rtc);
188 while (n >= 1000000) {
189 rtc[0]++;
190 n -= 1000000;
192 rtc[1] += (n * 1000);
193 if (rtc[1] >= 1000000000) {
194 rtc[0]++;
195 rtc[1] -= 1000000000;
197 __asm volatile ("1: mfspr %0,%3; cmplw %0,%1; blt 1b; bgt 2f;"
198 "mfspr %0,%4; cmplw %0,%2; blt 1b; 2:"
199 : "=&r"(scratch)
200 : "r"(rtc[0]), "r"(rtc[1]), "n"(SPR_RTCU_R), "n"(SPR_RTCL_R)
201 : "cr0");
202 } else
203 #endif
205 tb = mftb();
206 tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
207 tbh = tb >> 32;
208 tbl = tb;
209 __asm volatile ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;"
210 "mftb %0; cmplw %0,%2; blt 1b; 2:"
211 : "=&r"(scratch) : "r"(tbh), "r"(tbl)
212 : "cr0");
216 static u_int
217 get_powerpc_timecount(struct timecounter *tc)
219 u_long tb;
220 int msr, scratch;
222 __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1"
223 : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE));
224 #ifdef PPC_OEA601
225 if ((mfpvr() >> 16) == MPC601)
226 __asm volatile ("mfspr %0,%1" : "=r"(tb) : "n"(SPR_RTCL_R));
227 else
228 #endif
229 __asm volatile ("mftb %0" : "=r"(tb));
230 mtmsr(msr);
232 return tb;
235 void
236 init_powerpc_tc(void)
238 /* from machdep initialization */
239 powerpc_timecounter.tc_frequency = ticks_per_sec;
240 tc_init(&powerpc_timecounter);