clock.c revision 247463
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: head/sys/powerpc/aim/clock.c 247463 2013-02-28 13:46:03Z mav $");
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
122212453Smav	if (s->mode == 1) {
123212453Smav		/*
124212453Smav		 * Based on the actual time delay since the last decrementer
125212453Smav		 * reload, we arrange for earlier interrupt next time.
126212453Smav		 */
127212453Smav		__asm ("mfdec %0" : "=r"(val));
128212453Smav		while (val < 0) {
129212453Smav			val += s->div;
130212453Smav			nticks++;
131212453Smav		}
132212453Smav		mtdec(val);
133212453Smav	} else if (s->mode == 2) {
134212453Smav		nticks = 1;
135212453Smav		decr_et_stop(NULL);
136212453Smav	}
137212453Smav
138198427Snwhitehorn	while (nticks-- > 0) {
139212453Smav		if (decr_et.et_active)
140212453Smav			decr_et.et_event_cb(&decr_et, decr_et.et_arg);
14177957Sbenno	}
14277957Sbenno}
14377957Sbenno
144212453Smav/*
145212453Smav * BSP early initialization.
146212453Smav */
14777957Sbennovoid
148110380Sbennodecr_init(void)
149110380Sbenno{
150192067Snwhitehorn	struct cpuref cpu;
151212453Smav	char buf[32];
152125691Sgrehan
15378880Sbenno	/*
154192067Snwhitehorn	 * Check the BSP's timebase frequency. Sometimes we can't find the BSP, so fall
155192067Snwhitehorn	 * back to the first CPU in this case.
15678880Sbenno	 */
157192067Snwhitehorn	if (platform_smp_get_bsp(&cpu) != 0)
158192067Snwhitehorn		platform_smp_first_cpu(&cpu);
159192067Snwhitehorn	ticks_per_sec = platform_timebase_freq(&cpu);
160192067Snwhitehorn	ns_per_tick = 1000000000 / ticks_per_sec;
161192067Snwhitehorn
162198427Snwhitehorn	set_cputicker(mftb, ticks_per_sec, 0);
163212453Smav	snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
164212453Smav	intrcnt_add(buf, &decr_counts[curcpu]);
165212453Smav	decr_et_stop(NULL);
166212453Smav	initialized = 1;
16777957Sbenno}
16877957Sbenno
169192109Sraj#ifdef SMP
170212453Smav/*
171212453Smav * AP early initialization.
172212453Smav */
173173584Sgrehanvoid
174192109Srajdecr_ap_init(void)
175192109Sraj{
176212453Smav	char buf[32];
177192109Sraj
178212453Smav	snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
179212453Smav	intrcnt_add(buf, &decr_counts[curcpu]);
180212453Smav	decr_et_stop(NULL);
181192109Sraj}
182192109Sraj#endif
183192109Sraj
184212453Smav/*
185212453Smav * Final initialization.
186212453Smav */
187192109Srajvoid
188173584Sgrehandecr_tc_init(void)
189173584Sgrehan{
190212453Smav
191212453Smav	decr_tc.tc_frequency = ticks_per_sec;
192212453Smav	tc_init(&decr_tc);
193212453Smav	decr_et.et_name = "decrementer";
194212453Smav	decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
195212453Smav	    ET_FLAGS_PERCPU;
196212453Smav	decr_et.et_quality = 1000;
197212453Smav	decr_et.et_frequency = ticks_per_sec;
198247463Smav	decr_et.et_min_period = (0x00000002LLU << 32) / ticks_per_sec;
199247463Smav	decr_et.et_max_period = (0x7fffffffLLU << 32) / ticks_per_sec;
200212453Smav	decr_et.et_start = decr_et_start;
201212453Smav	decr_et.et_stop = decr_et_stop;
202212453Smav	decr_et.et_priv = NULL;
203212453Smav	et_register(&decr_et);
204173584Sgrehan}
205173584Sgrehan
206212453Smav/*
207212453Smav * Event timer start method.
208212453Smav */
209212453Smavstatic int
210212453Smavdecr_et_start(struct eventtimer *et,
211247463Smav    sbintime_t first, sbintime_t period)
212212453Smav{
213212453Smav	struct decr_state *s = DPCPU_PTR(decr_state);
214212453Smav	uint32_t fdiv;
215212453Smav
216247463Smav	if (period != 0) {
217212453Smav		s->mode = 1;
218247463Smav		s->div = (decr_et.et_frequency * period) >> 32;
219212453Smav	} else {
220212453Smav		s->mode = 2;
221247463Smav		s->div = 0;
222212453Smav	}
223247463Smav	if (first != 0) {
224247463Smav		fdiv = (decr_et.et_frequency * first) >> 32;
225212453Smav	} else
226212453Smav		fdiv = s->div;
227212453Smav
228212453Smav	mtdec(fdiv);
229212453Smav	return (0);
230212453Smav}
231212453Smav
232212453Smav/*
233212453Smav * Event timer stop method.
234212453Smav */
235212453Smavstatic int
236212453Smavdecr_et_stop(struct eventtimer *et)
237212453Smav{
238212453Smav	struct decr_state *s = DPCPU_PTR(decr_state);
239212453Smav
240212453Smav	s->mode = 0;
241212453Smav	s->div = 0x7fffffff;
242212453Smav	mtdec(s->div);
243212453Smav	return (0);
244212453Smav}
245212453Smav
246212453Smav/*
247212453Smav * Timecounter get method.
248212453Smav */
24978880Sbennostatic unsigned
250110380Sbennodecr_get_timecount(struct timecounter *tc)
25178880Sbenno{
252183089Smarcel	register_t tb;
253183089Smarcel
254183089Smarcel	__asm __volatile("mftb %0" : "=r"(tb));
255183089Smarcel	return (tb);
25678880Sbenno}
25778880Sbenno
25877957Sbenno/*
25977957Sbenno * Wait for about n microseconds (at least!).
26077957Sbenno */
26177957Sbennovoid
262120460SgrehanDELAY(int n)
26377957Sbenno{
264110381Sbenno	u_quad_t	tb, ttb;
265125691Sgrehan
26677957Sbenno	tb = mftb();
267110381Sbenno	ttb = tb + (n * 1000 + ns_per_tick - 1) / ns_per_tick;
268110381Sbenno	while (tb < ttb)
269110381Sbenno		tb = mftb();
27077957Sbenno}
27177957Sbenno
272