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 $ */
5 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6 * Copyright (C) 1995, 1996 TooLs GmbH.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
;
54 uint32_t ticks_per_intr
= 0;
56 static struct timecounter powerpc_timecounter
= {
57 get_powerpc_timecount
, /* get_timecount */
59 0x7fffffff, /* counter_mask */
68 * Start the real-time and statistics clocks. Leave stathz 0 since there
69 * are no other timers available.
74 struct cpu_info
* const ci
= curcpu();
77 ticks_per_intr
= ticks_per_sec
/ hz
;
78 cpu_timebase
= ticks_per_sec
;
80 if ((mfpvr() >> 16) == MPC601
)
82 ("mfspr %0,%1" : "=r"(ci
->ci_lasttb
) : "n"(SPR_RTCL_R
));
85 __asm
volatile ("mftb %0" : "=r"(ci
->ci_lasttb
));
86 __asm
volatile ("mtdec %0" :: "r"(ticks_per_intr
));
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.
102 setstatclockrate(int arg
)
105 /* Nothing we can do */
109 decr_intr(struct clockframe
*frame
)
111 struct cpu_info
* const ci
= curcpu();
118 /* Check whether we are initialized */
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
));
132 ci
->ci_ev_clock
.ev_count
++;
135 if (pri
& (1 << SPL_CLOCK
)) {
136 ci
->ci_tickspending
+= nticks
;
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.
146 if ((mfpvr() >> 16) == MPC601
)
148 ("mfspr %0,%1" : "=r"(tb
) : "n"(SPR_RTCL_R
));
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
);
175 * Wait for about n microseconds (at least!).
178 delay(unsigned int n
)
181 u_long tbh
, tbl
, scratch
;
184 if ((mfpvr() >> 16) == MPC601
) {
188 while (n
>= 1000000) {
192 rtc
[1] += (n
* 1000);
193 if (rtc
[1] >= 1000000000) {
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:"
200 : "r"(rtc
[0]), "r"(rtc
[1]), "n"(SPR_RTCU_R
), "n"(SPR_RTCL_R
)
206 tb
+= (n
* 1000 + ns_per_tick
- 1) / ns_per_tick
;
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
)
217 get_powerpc_timecount(struct timecounter
*tc
)
222 __asm
volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1"
223 : "=r"(msr
), "=r"(scratch
) : "K"((u_short
)~PSL_EE
));
225 if ((mfpvr() >> 16) == MPC601
)
226 __asm
volatile ("mfspr %0,%1" : "=r"(tb
) : "n"(SPR_RTCL_R
));
229 __asm
volatile ("mftb %0" : "=r"(tb
));
236 init_powerpc_tc(void)
238 /* from machdep initialization */
239 powerpc_timecounter
.tc_frequency
= ticks_per_sec
;
240 tc_init(&powerpc_timecounter
);