1139825Simp/*-
277957Sbenno * Copyright (C) 1995, 1996 Wolfgang Solfrank.
377957Sbenno * Copyright (C) 1995, 1996 TooLs GmbH.
477957Sbenno * All rights reserved.
577957Sbenno *
677957Sbenno * Redistribution and use in source and binary forms, with or without
777957Sbenno * modification, are permitted provided that the following conditions
877957Sbenno * are met:
977957Sbenno * 1. Redistributions of source code must retain the above copyright
1077957Sbenno *    notice, this list of conditions and the following disclaimer.
1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1277957Sbenno *    notice, this list of conditions and the following disclaimer in the
1377957Sbenno *    documentation and/or other materials provided with the distribution.
1477957Sbenno * 3. All advertising materials mentioning features or use of this software
1577957Sbenno *    must display the following acknowledgement:
1677957Sbenno *	This product includes software developed by TooLs GmbH.
1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products
1877957Sbenno *    derived from this software without specific prior written permission.
1977957Sbenno *
2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3077957Sbenno *
3178880Sbenno *	$NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $
3277957Sbenno */
3378880Sbenno/*
3478880Sbenno * Copyright (C) 2001 Benno Rice.
3578880Sbenno * All rights reserved.
3678880Sbenno *
3778880Sbenno * Redistribution and use in source and binary forms, with or without
3878880Sbenno * modification, are permitted provided that the following conditions
3978880Sbenno * are met:
4078880Sbenno * 1. Redistributions of source code must retain the above copyright
4178880Sbenno *    notice, this list of conditions and the following disclaimer.
4278880Sbenno * 2. Redistributions in binary form must reproduce the above copyright
4378880Sbenno *    notice, this list of conditions and the following disclaimer in the
4478880Sbenno *    documentation and/or other materials provided with the distribution.
4578880Sbenno *
4678880Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
4778880Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4878880Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4978880Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5078880Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
5178880Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
5278880Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5378880Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
5478880Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
5578880Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5678880Sbenno */
5777957Sbenno
58113038Sobrien#include <sys/cdefs.h>
59113038Sobrien__FBSDID("$FreeBSD$");
6077957Sbenno
6177957Sbenno#include <sys/param.h>
6277957Sbenno#include <sys/systm.h>
6378880Sbenno#include <sys/kernel.h>
64178628Smarcel#include <sys/bus.h>
65178628Smarcel#include <sys/interrupt.h>
66178628Smarcel#include <sys/pcpu.h>
6778880Sbenno#include <sys/sysctl.h>
68212453Smav#include <sys/timeet.h>
6977957Sbenno#include <sys/timetc.h>
7077957Sbenno
7177957Sbenno#include <dev/ofw/openfirm.h>
7277957Sbenno
73160713Smarcel#include <machine/clock.h>
7477957Sbenno#include <machine/cpu.h>
75212453Smav#include <machine/intr_machdep.h>
76125691Sgrehan#include <machine/md_var.h>
77183089Smarcel#include <machine/smp.h>
7877957Sbenno
7977957Sbenno/*
8077957Sbenno * Initially we assume a processor with a bus frequency of 12.5 MHz.
8177957Sbenno */
82212453Smavstatic int		initialized = 0;
83212453Smavstatic u_long		ns_per_tick = 80;
8499032Sbennostatic u_long		ticks_per_sec = 12500000;
85212453Smavstatic u_long		*decr_counts[MAXCPU];
8677957Sbenno
87212453Smavstatic int		decr_et_start(struct eventtimer *et,
88247463Smav    sbintime_t first, sbintime_t period);
89212453Smavstatic int		decr_et_stop(struct eventtimer *et);
90110380Sbennostatic timecounter_get_t	decr_get_timecount;
9178880Sbenno
92212453Smavstruct decr_state {
93212453Smav	int	mode;	/* 0 - off, 1 - periodic, 2 - one-shot. */
94212453Smav	int32_t	div;	/* Periodic divisor. */
95212453Smav};
96215701Sdimstatic DPCPU_DEFINE(struct decr_state, decr_state);
97212453Smav
98212453Smavstatic struct eventtimer	decr_et;
99212453Smavstatic struct timecounter	decr_tc = {
100110380Sbenno	decr_get_timecount,	/* get_timecount */
10178880Sbenno	0,			/* no poll_pps */
10278880Sbenno	~0u,			/* counter_mask */
10378880Sbenno	0,			/* frequency */
104212453Smav	"timebase"		/* name */
10578880Sbenno};
10678880Sbenno
107212453Smav/*
108215121Sraj * Decrementer interrupt handler.
109212453Smav */
11077957Sbennovoid
111153666Sjhbdecr_intr(struct trapframe *frame)
11277957Sbenno{
113212453Smav	struct decr_state *s = DPCPU_PTR(decr_state);
114212453Smav	int		nticks = 0;
115212453Smav	int32_t		val;
11677957Sbenno
117212453Smav	if (!initialized)
11877957Sbenno		return;
11977957Sbenno
120212453Smav	(*decr_counts[curcpu])++;
12177957Sbenno
122256793Snwhitehorn#ifdef BOOKE
123256793Snwhitehorn	/*
124256793Snwhitehorn	 * Interrupt handler must reset DIS to avoid getting another
125256793Snwhitehorn	 * interrupt once EE is enabled.
126256793Snwhitehorn	 */
127256793Snwhitehorn	mtspr(SPR_TSR, TSR_DIS);
128256793Snwhitehorn#endif
129256793Snwhitehorn
130212453Smav	if (s->mode == 1) {
131212453Smav		/*
132212453Smav		 * Based on the actual time delay since the last decrementer
133212453Smav		 * reload, we arrange for earlier interrupt next time.
134212453Smav		 */
135212453Smav		__asm ("mfdec %0" : "=r"(val));
136212453Smav		while (val < 0) {
137212453Smav			val += s->div;
138212453Smav			nticks++;
139212453Smav		}
140212453Smav		mtdec(val);
141212453Smav	} else if (s->mode == 2) {
142212453Smav		nticks = 1;
143212453Smav		decr_et_stop(NULL);
144212453Smav	}
145212453Smav
146198427Snwhitehorn	while (nticks-- > 0) {
147212453Smav		if (decr_et.et_active)
148212453Smav			decr_et.et_event_cb(&decr_et, decr_et.et_arg);
14977957Sbenno	}
15077957Sbenno}
15177957Sbenno
152256793Snwhitehornvoid
153256793Snwhitehorncpu_initclocks(void)
154256793Snwhitehorn{
155256793Snwhitehorn
156256793Snwhitehorn	decr_tc_init();
157256793Snwhitehorn	cpu_initclocks_bsp();
158256793Snwhitehorn}
159256793Snwhitehorn
160212453Smav/*
161212453Smav * BSP early initialization.
162212453Smav */
16377957Sbennovoid
164110380Sbennodecr_init(void)
165110380Sbenno{
166192067Snwhitehorn	struct cpuref cpu;
167212453Smav	char buf[32];
168125691Sgrehan
16978880Sbenno	/*
170256818Snwhitehorn	 * Check the BSP's timebase frequency. Sometimes we can't find the BSP,
171256818Snwhitehorn	 * so fall back to the first CPU in this case.
17278880Sbenno	 */
173192067Snwhitehorn	if (platform_smp_get_bsp(&cpu) != 0)
174192067Snwhitehorn		platform_smp_first_cpu(&cpu);
175192067Snwhitehorn	ticks_per_sec = platform_timebase_freq(&cpu);
176192067Snwhitehorn	ns_per_tick = 1000000000 / ticks_per_sec;
177192067Snwhitehorn
178198427Snwhitehorn	set_cputicker(mftb, ticks_per_sec, 0);
179212453Smav	snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
180212453Smav	intrcnt_add(buf, &decr_counts[curcpu]);
181212453Smav	decr_et_stop(NULL);
182212453Smav	initialized = 1;
18377957Sbenno}
18477957Sbenno
185192109Sraj#ifdef SMP
186212453Smav/*
187212453Smav * AP early initialization.
188212453Smav */
189173584Sgrehanvoid
190192109Srajdecr_ap_init(void)
191192109Sraj{
192212453Smav	char buf[32];
193192109Sraj
194212453Smav	snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
195212453Smav	intrcnt_add(buf, &decr_counts[curcpu]);
196212453Smav	decr_et_stop(NULL);
197192109Sraj}
198192109Sraj#endif
199192109Sraj
200212453Smav/*
201212453Smav * Final initialization.
202212453Smav */
203192109Srajvoid
204173584Sgrehandecr_tc_init(void)
205173584Sgrehan{
206212453Smav
207212453Smav	decr_tc.tc_frequency = ticks_per_sec;
208212453Smav	tc_init(&decr_tc);
209212453Smav	decr_et.et_name = "decrementer";
210212453Smav	decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
211212453Smav	    ET_FLAGS_PERCPU;
212212453Smav	decr_et.et_quality = 1000;
213212453Smav	decr_et.et_frequency = ticks_per_sec;
214247463Smav	decr_et.et_min_period = (0x00000002LLU << 32) / ticks_per_sec;
215247463Smav	decr_et.et_max_period = (0x7fffffffLLU << 32) / ticks_per_sec;
216212453Smav	decr_et.et_start = decr_et_start;
217212453Smav	decr_et.et_stop = decr_et_stop;
218212453Smav	decr_et.et_priv = NULL;
219212453Smav	et_register(&decr_et);
220173584Sgrehan}
221173584Sgrehan
222212453Smav/*
223212453Smav * Event timer start method.
224212453Smav */
225212453Smavstatic int
226256793Snwhitehorndecr_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
227212453Smav{
228212453Smav	struct decr_state *s = DPCPU_PTR(decr_state);
229212453Smav	uint32_t fdiv;
230256793Snwhitehorn#ifdef BOOKE
231256793Snwhitehorn	uint32_t tcr;
232256793Snwhitehorn#endif
233212453Smav
234247463Smav	if (period != 0) {
235212453Smav		s->mode = 1;
236247463Smav		s->div = (decr_et.et_frequency * period) >> 32;
237212453Smav	} else {
238212453Smav		s->mode = 2;
239247463Smav		s->div = 0;
240212453Smav	}
241256793Snwhitehorn	if (first != 0)
242247463Smav		fdiv = (decr_et.et_frequency * first) >> 32;
243256793Snwhitehorn	else
244212453Smav		fdiv = s->div;
245212453Smav
246256793Snwhitehorn#ifdef BOOKE
247256793Snwhitehorn	tcr = mfspr(SPR_TCR);
248256793Snwhitehorn	tcr |= TCR_DIE;
249256793Snwhitehorn	if (s->mode == 1) {
250256793Snwhitehorn		mtspr(SPR_DECAR, s->div);
251256793Snwhitehorn		tcr |= TCR_ARE;
252256793Snwhitehorn	} else
253256793Snwhitehorn		tcr &= ~TCR_ARE;
254212453Smav	mtdec(fdiv);
255256793Snwhitehorn	mtspr(SPR_TCR, tcr);
256256793Snwhitehorn#else
257256793Snwhitehorn	mtdec(fdiv);
258256793Snwhitehorn#endif
259256793Snwhitehorn
260212453Smav	return (0);
261212453Smav}
262212453Smav
263212453Smav/*
264212453Smav * Event timer stop method.
265212453Smav */
266212453Smavstatic int
267212453Smavdecr_et_stop(struct eventtimer *et)
268212453Smav{
269212453Smav	struct decr_state *s = DPCPU_PTR(decr_state);
270256793Snwhitehorn#ifdef BOOKE
271256793Snwhitehorn	uint32_t tcr;
272256793Snwhitehorn#endif
273212453Smav
274212453Smav	s->mode = 0;
275212453Smav	s->div = 0x7fffffff;
276256793Snwhitehorn#ifdef BOOKE
277256793Snwhitehorn	tcr = mfspr(SPR_TCR);
278256793Snwhitehorn	tcr &= ~(TCR_DIE | TCR_ARE);
279256793Snwhitehorn	mtspr(SPR_TCR, tcr);
280256793Snwhitehorn#else
281212453Smav	mtdec(s->div);
282256793Snwhitehorn#endif
283212453Smav	return (0);
284212453Smav}
285212453Smav
286212453Smav/*
287212453Smav * Timecounter get method.
288212453Smav */
28978880Sbennostatic unsigned
290110380Sbennodecr_get_timecount(struct timecounter *tc)
29178880Sbenno{
292256793Snwhitehorn	return (mftb());
29378880Sbenno}
29478880Sbenno
29577957Sbenno/*
29677957Sbenno * Wait for about n microseconds (at least!).
29777957Sbenno */
29877957Sbennovoid
299120460SgrehanDELAY(int n)
30077957Sbenno{
301110381Sbenno	u_quad_t	tb, ttb;
302125691Sgrehan
30377957Sbenno	tb = mftb();
304298642Spfg	ttb = tb + howmany(n * 1000, ns_per_tick);
305110381Sbenno	while (tb < ttb)
306110381Sbenno		tb = mftb();
30777957Sbenno}
30877957Sbenno
309