xref: /netbsd-src/sys/arch/powerpc/ibm4xx/clock.c (revision f10e8fc157b578b98320eb1c228c17449576e984)
1*f10e8fc1Srin /*	$NetBSD: clock.c,v 1.33 2022/10/05 08:18:00 rin Exp $	*/
2d26d3b35Seeh /*      $OpenBSD: clock.c,v 1.3 1997/10/13 13:42:53 pefo Exp $  */
3d26d3b35Seeh 
4d26d3b35Seeh /*
5d26d3b35Seeh  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6d26d3b35Seeh  * Copyright (C) 1995, 1996 TooLs GmbH.
7d26d3b35Seeh  * All rights reserved.
8d26d3b35Seeh  *
9d26d3b35Seeh  * Redistribution and use in source and binary forms, with or without
10d26d3b35Seeh  * modification, are permitted provided that the following conditions
11d26d3b35Seeh  * are met:
12d26d3b35Seeh  * 1. Redistributions of source code must retain the above copyright
13d26d3b35Seeh  *    notice, this list of conditions and the following disclaimer.
14d26d3b35Seeh  * 2. Redistributions in binary form must reproduce the above copyright
15d26d3b35Seeh  *    notice, this list of conditions and the following disclaimer in the
16d26d3b35Seeh  *    documentation and/or other materials provided with the distribution.
17d26d3b35Seeh  * 3. All advertising materials mentioning features or use of this software
18d26d3b35Seeh  *    must display the following acknowledgement:
19d26d3b35Seeh  *	This product includes software developed by TooLs GmbH.
20d26d3b35Seeh  * 4. The name of TooLs GmbH may not be used to endorse or promote products
21d26d3b35Seeh  *    derived from this software without specific prior written permission.
22d26d3b35Seeh  *
23d26d3b35Seeh  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24d26d3b35Seeh  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25d26d3b35Seeh  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26d26d3b35Seeh  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27d26d3b35Seeh  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28d26d3b35Seeh  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29d26d3b35Seeh  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30d26d3b35Seeh  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31d26d3b35Seeh  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32d26d3b35Seeh  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33d26d3b35Seeh  */
34d26d3b35Seeh 
35ed517291Slukem #include <sys/cdefs.h>
36*f10e8fc1Srin __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.33 2022/10/05 08:18:00 rin Exp $");
3736c20c46Srin 
3836c20c46Srin #ifdef _KERNEL_OPT
3936c20c46Srin #include "opt_ppcarch.h"
4012c9d0e1Srin #include "opt_ppcparam.h"
4136c20c46Srin #endif
42ed517291Slukem 
43d26d3b35Seeh #include <sys/param.h>
44d26d3b35Seeh #include <sys/kernel.h>
45d26d3b35Seeh #include <sys/systm.h>
4618a5a8d1Sjoerg #include <sys/timetc.h>
471fd2c684Smatt #include <sys/cpu.h>
48fb44a857Sthorpej 
49a191b55bSsimonb #include <uvm/uvm_extern.h>
50a191b55bSsimonb 
51fb44a857Sthorpej #include <prop/proplib.h>
52d26d3b35Seeh 
53d26d3b35Seeh #include <powerpc/spr.h>
545a4cb80dSmatt #include <powerpc/ibm4xx/spr.h>
551fd2c684Smatt #include <powerpc/ibm4xx/cpu.h>
56d26d3b35Seeh 
57d26d3b35Seeh /*
58d26d3b35Seeh  * Initially we assume a processor with a bus frequency of 12.5 MHz.
59d26d3b35Seeh  */
60d26d3b35Seeh static u_long ticks_per_sec;
61d26d3b35Seeh static u_long ns_per_tick;
62d26d3b35Seeh static long ticks_per_intr;
63292989c8Snonaka static volatile u_long lasttb, lasttb2;
64d26d3b35Seeh static u_long ticksmissed;
65d26d3b35Seeh static volatile int tickspending;
66d26d3b35Seeh 
6718a5a8d1Sjoerg static void init_ppc4xx_tc(void);
6818a5a8d1Sjoerg static u_int get_ppc4xx_timecount(struct timecounter *);
6918a5a8d1Sjoerg 
7018a5a8d1Sjoerg static struct timecounter ppc4xx_timecounter = {
71482eef70Srin 	.tc_get_timecount = get_ppc4xx_timecount,
72482eef70Srin 	.tc_counter_mask = ~0u,
73482eef70Srin 	.tc_name = "ppc_timebase",
74482eef70Srin 	.tc_quality = 100,
7518a5a8d1Sjoerg };
7618a5a8d1Sjoerg 
77d26d3b35Seeh void decr_intr(struct clockframe *);	/* called from trap_subr.S */
78d26d3b35Seeh void stat_intr(struct clockframe *);	/* called from trap_subr.S */
79d26d3b35Seeh 
80d26d3b35Seeh #ifdef FAST_STAT_CLOCK
81a1f606d3Slukem /* Stat clock runs at ~ 1.5 kHz */
82d26d3b35Seeh #define PERIOD_POWER	17
83d26d3b35Seeh #define TCR_PERIOD	TCR_FP_2_17
84d26d3b35Seeh #else
85d26d3b35Seeh /* Stat clock runs at ~ 95Hz */
86d26d3b35Seeh #define PERIOD_POWER	21
87d26d3b35Seeh #define TCR_PERIOD	TCR_FP_2_21
88d26d3b35Seeh #endif
89d26d3b35Seeh 
90d26d3b35Seeh 
91d26d3b35Seeh void
stat_intr(struct clockframe * frame)92d26d3b35Seeh stat_intr(struct clockframe *frame)
93d26d3b35Seeh {
946a66466fSmatt 	struct cpu_info * const ci = curcpu();
95a191b55bSsimonb 
96d26d3b35Seeh 	mtspr(SPR_TSR, TSR_FIS);	/* Clear TSR[FIS] */
976a66466fSmatt 	ci->ci_data.cpu_nintr++;
986a66466fSmatt 	ci->ci_ev_statclock.ev_count++;
9919461b0aSfreza 
10019461b0aSfreza 	/* Nobody can interrupt us, but see if we're allowed to run. */
101dba36e03Smatt 	int s = splclock();
10282862d91Skiyohara 
10382862d91Skiyohara 	/*
10482862d91Skiyohara 	 * Reenable interrupts
10582862d91Skiyohara 	 */
10682862d91Skiyohara 	__asm volatile ("wrteei 1");
10782862d91Skiyohara 
1080a1f6f49Srin 	if (IPL_CLOCK > s) {
1090a1f6f49Srin 		ci->ci_idepth++;
110d26d3b35Seeh   		statclock(frame);
1110a1f6f49Srin 		ci->ci_idepth--;
1120a1f6f49Srin 	}
113dba36e03Smatt 	splx(s);
114d26d3b35Seeh }
115d26d3b35Seeh 
116d26d3b35Seeh void
decr_intr(struct clockframe * frame)117d26d3b35Seeh decr_intr(struct clockframe *frame)
118d26d3b35Seeh {
1196a66466fSmatt 	struct cpu_info * const ci = curcpu();
120dba36e03Smatt 	int pcpl;
121e8dd39d8Sscw 	long tbtick, xticks;
122d26d3b35Seeh 	int nticks;
12378037d3fSfreza 
124d26d3b35Seeh 	/*
125d26d3b35Seeh 	 * Check whether we are initialized.
126d26d3b35Seeh 	 */
127d26d3b35Seeh 	if (!ticks_per_intr)
128d26d3b35Seeh 		return;
129d26d3b35Seeh 
130e8dd39d8Sscw 	tbtick = mftbl();
131d26d3b35Seeh 	mtspr(SPR_TSR, TSR_PIS);	/* Clear TSR[PIS] */
132292989c8Snonaka 
133292989c8Snonaka 	xticks = tbtick - lasttb2;	/* Number of TLB cycles since last exception */
134d26d3b35Seeh 	for (nticks = 0; xticks > ticks_per_intr; nticks++)
135d26d3b35Seeh 		xticks -= ticks_per_intr;
136292989c8Snonaka 	lasttb2 = tbtick - xticks;
137d26d3b35Seeh 
1386a66466fSmatt 	ci->ci_data.cpu_nintr++;
1396a66466fSmatt 	ci->ci_ev_clock.ev_count++;
140dba36e03Smatt 	pcpl = splclock();
14182862d91Skiyohara 
14282862d91Skiyohara 	/*
14382862d91Skiyohara 	 * Reenable interrupts
14482862d91Skiyohara 	 */
14582862d91Skiyohara 	__asm volatile ("wrteei 1");
14682862d91Skiyohara 
147dba36e03Smatt 	if (pcpl >= IPL_CLOCK) {
148d26d3b35Seeh 		tickspending += nticks;
149d26d3b35Seeh 		ticksmissed += nticks;
150d26d3b35Seeh 	} else {
151d26d3b35Seeh 		nticks += tickspending;
152d26d3b35Seeh 		tickspending = 0;
153d26d3b35Seeh 
154d26d3b35Seeh 		/*
155292989c8Snonaka 		 * lasttb is used during microtime. Set it to the virtual
156292989c8Snonaka 		 * start of this tick interval.
157292989c8Snonaka 		 */
158292989c8Snonaka 		lasttb = lasttb2;
159292989c8Snonaka 
160292989c8Snonaka 		/*
161d26d3b35Seeh 		 * Do standard timer interrupt stuff.
162d26d3b35Seeh 		 */
1630a1f6f49Srin 		ci->ci_idepth++;
1649a704364Srin 		while (nticks-- > 0)
165d26d3b35Seeh 			hardclock(frame);
1660a1f6f49Srin 		ci->ci_idepth--;
167d26d3b35Seeh 	}
168dba36e03Smatt 	splx(pcpl);
169d26d3b35Seeh }
170d26d3b35Seeh 
171d26d3b35Seeh void
cpu_initclocks(void)172d26d3b35Seeh cpu_initclocks(void)
173d26d3b35Seeh {
1746a66466fSmatt 	struct cpu_info * const ci = curcpu();
1756a66466fSmatt 
17678037d3fSfreza 	/* Initialized in powerpc/ibm4xx/cpu.c */
1776a66466fSmatt 	evcnt_attach_static(&ci->ci_ev_clock);
1786a66466fSmatt 	evcnt_attach_static(&ci->ci_ev_statclock);
1797cfa7d3cSsimonb 
180d26d3b35Seeh 	ticks_per_intr = ticks_per_sec / hz;
181d26d3b35Seeh 	stathz = profhz = ticks_per_sec / (1 << PERIOD_POWER);
18278037d3fSfreza 
18378037d3fSfreza 	printf("Setting PIT to %ld/%d = %ld\n", ticks_per_sec, hz,
18478037d3fSfreza 	    ticks_per_intr);
18578037d3fSfreza 
186292989c8Snonaka 	lasttb2 = lasttb = mftbl();
187d26d3b35Seeh 	mtspr(SPR_PIT, ticks_per_intr);
18878037d3fSfreza 
189d26d3b35Seeh 	/* Enable PIT & FIT(2^17c = 0.655ms) interrupts and auto-reload */
190d26d3b35Seeh 	mtspr(SPR_TCR, TCR_PIE | TCR_ARE | TCR_FIE | TCR_PERIOD);
19118a5a8d1Sjoerg 
19218a5a8d1Sjoerg 	init_ppc4xx_tc();
193d26d3b35Seeh }
194d26d3b35Seeh 
195d26d3b35Seeh void
calc_delayconst(void)196d26d3b35Seeh calc_delayconst(void)
197d26d3b35Seeh {
198fb44a857Sthorpej 	prop_number_t freq;
199d26d3b35Seeh 
200fb44a857Sthorpej 	freq = prop_dictionary_get(board_properties, "processor-frequency");
2010754ce03Seeh 
20212c9d0e1Srin #ifndef PPC_CPU_FREQ
20312c9d0e1Srin 	KASSERT(freq != NULL);
20412c9d0e1Srin #else
20512c9d0e1Srin 	/* XXX hack for pckbc_cnattach() for Explora */
20612c9d0e1Srin 	if (freq == NULL)
20712c9d0e1Srin 		ticks_per_sec = (u_long) PPC_CPU_FREQ;
20812c9d0e1Srin 	else
20912c9d0e1Srin #endif
210fb44a857Sthorpej 		ticks_per_sec = (u_long) prop_number_integer_value(freq);
21112c9d0e1Srin 
212d26d3b35Seeh 	ns_per_tick = 1000000000 / ticks_per_sec;
213d26d3b35Seeh }
214d26d3b35Seeh 
21518a5a8d1Sjoerg static u_int
get_ppc4xx_timecount(struct timecounter * tc)21618a5a8d1Sjoerg get_ppc4xx_timecount(struct timecounter *tc)
217d26d3b35Seeh {
218d26d3b35Seeh 	u_long tb;
219d26d3b35Seeh 	int msr;
220d26d3b35Seeh 
221*f10e8fc1Srin 	__asm volatile ("mfmsr %0; wrteei 0" : "=r" (msr));
22244b1e07eShannken 	tb = mftbl();
2232d65de24Sperry 	__asm volatile ("mtmsr %0" :: "r" (msr));
22418a5a8d1Sjoerg 
22518a5a8d1Sjoerg 	return tb;
226d26d3b35Seeh }
227d26d3b35Seeh 
228d26d3b35Seeh /*
229d26d3b35Seeh  * Wait for about n microseconds (at least!).
230d26d3b35Seeh  */
231d26d3b35Seeh void
delay(unsigned int n)232d26d3b35Seeh delay(unsigned int n)
233d26d3b35Seeh {
234d26d3b35Seeh 	u_quad_t tb;
235d26d3b35Seeh 	u_long tbh, tbl, scratch;
236d26d3b35Seeh 
237d26d3b35Seeh 	tb = mftb();
238d26d3b35Seeh 	/* use 1000ULL to force 64 bit math to avoid 32 bit overflows */
239d26d3b35Seeh 	tb += (n * 1000ULL + ns_per_tick - 1) / ns_per_tick;
240d26d3b35Seeh 	tbh = tb >> 32;
241d26d3b35Seeh 	tbl = tb;
2422d65de24Sperry 	__asm volatile (
243*f10e8fc1Srin 	"1:"
24444b1e07eShannken #ifdef PPC_IBM403
245*f10e8fc1Srin 		"mftbhi	%0;"
24644b1e07eShannken #else
247*f10e8fc1Srin 		"mftbu	%0;"
24844b1e07eShannken #endif
249*f10e8fc1Srin 		"cmplw	%0,%1;"
250*f10e8fc1Srin 		"blt	1b;"
251*f10e8fc1Srin 		"bgt	2f;"
25244b1e07eShannken #ifdef PPC_IBM403
253*f10e8fc1Srin 		"mftblo	%0;"
25444b1e07eShannken #else
255*f10e8fc1Srin 		"mftb	%0;"
25644b1e07eShannken #endif
257*f10e8fc1Srin 		"cmplw	%0,%2;"
258*f10e8fc1Srin 		"blt	1b;"
259*f10e8fc1Srin 	"2:"
260*f10e8fc1Srin 	    : "=&r" (scratch)
261*f10e8fc1Srin 	    : "r" (tbh), "r" (tbl)
262*f10e8fc1Srin 	    : "cr0");
263d26d3b35Seeh }
264d26d3b35Seeh 
265d26d3b35Seeh /*
266d26d3b35Seeh  * Nothing to do.
267d26d3b35Seeh  */
268d26d3b35Seeh void
setstatclockrate(int arg)269d26d3b35Seeh setstatclockrate(int arg)
270d26d3b35Seeh {
271d26d3b35Seeh 
272d26d3b35Seeh 	/* Do nothing */
273d26d3b35Seeh }
27418a5a8d1Sjoerg 
27518a5a8d1Sjoerg static void
init_ppc4xx_tc(void)27618a5a8d1Sjoerg init_ppc4xx_tc(void)
27718a5a8d1Sjoerg {
27818a5a8d1Sjoerg 	/* from machdep initialization */
27918a5a8d1Sjoerg 	ppc4xx_timecounter.tc_frequency = ticks_per_sec;
28018a5a8d1Sjoerg 	tc_init(&ppc4xx_timecounter);
28118a5a8d1Sjoerg }
282