clock.c revision 212453
1135549Sdes/*-
2135549Sdes * Copyright (C) 1995, 1996 Wolfgang Solfrank.
3135549Sdes * Copyright (C) 1995, 1996 TooLs GmbH.
4218384Sdougb * All rights reserved.
5135549Sdes *
6135549Sdes * Redistribution and use in source and binary forms, with or without
7135549Sdes * modification, are permitted provided that the following conditions
8135549Sdes * are met:
9135549Sdes * 1. Redistributions of source code must retain the above copyright
10135549Sdes *    notice, this list of conditions and the following disclaimer.
11135549Sdes * 2. Redistributions in binary form must reproduce the above copyright
12135549Sdes *    notice, this list of conditions and the following disclaimer in the
13135549Sdes *    documentation and/or other materials provided with the distribution.
14135549Sdes * 3. All advertising materials mentioning features or use of this software
15135549Sdes *    must display the following acknowledgement:
16135549Sdes *	This product includes software developed by TooLs GmbH.
17135549Sdes * 4. The name of TooLs GmbH may not be used to endorse or promote products
18135549Sdes *    derived from this software without specific prior written permission.
19135549Sdes *
20135549Sdes * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21135549Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22135549Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23135549Sdes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24135549Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25135549Sdes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26135549Sdes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27170224Sdougb * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28170224Sdougb * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29135549Sdes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30135549Sdes *
31135549Sdes *	$NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $
32135549Sdes */
33135549Sdes/*
34135549Sdes * Copyright (C) 2001 Benno Rice.
35135549Sdes * All rights reserved.
36135549Sdes *
37135549Sdes * Redistribution and use in source and binary forms, with or without
38170224Sdougb * modification, are permitted provided that the following conditions
39135549Sdes * are met:
40135549Sdes * 1. Redistributions of source code must retain the above copyright
41135549Sdes *    notice, this list of conditions and the following disclaimer.
42135549Sdes * 2. Redistributions in binary form must reproduce the above copyright
43135549Sdes *    notice, this list of conditions and the following disclaimer in the
44135549Sdes *    documentation and/or other materials provided with the distribution.
45135549Sdes *
46135549Sdes * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
47135549Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48135549Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49135549Sdes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50135549Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51135549Sdes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52135549Sdes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53135549Sdes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54135549Sdes * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55135549Sdes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56135549Sdes */
57135549Sdes
58135549Sdes#include <sys/cdefs.h>
59135549Sdes__FBSDID("$FreeBSD: head/sys/powerpc/aim/clock.c 212453 2010-09-11 04:45:51Z mav $");
60135549Sdes
61135549Sdes#include <sys/param.h>
62135549Sdes#include <sys/systm.h>
63135549Sdes#include <sys/kernel.h>
64135549Sdes#include <sys/bus.h>
65135549Sdes#include <sys/interrupt.h>
66135549Sdes#include <sys/pcpu.h>
67135549Sdes#include <sys/sysctl.h>
68135549Sdes#include <sys/timeet.h>
69135549Sdes#include <sys/timetc.h>
70135549Sdes
71135549Sdes#include <dev/ofw/openfirm.h>
72135549Sdes
73135549Sdes#include <machine/clock.h>
74135549Sdes#include <machine/cpu.h>
75135549Sdes#include <machine/intr_machdep.h>
76135549Sdes#include <machine/md_var.h>
77135549Sdes#include <machine/smp.h>
78135549Sdes
79170224Sdougb/*
80135549Sdes * Initially we assume a processor with a bus frequency of 12.5 MHz.
81135549Sdes */
82135549Sdesstatic int		initialized = 0;
83193149Sdougbstatic u_long		ns_per_tick = 80;
84193149Sdougbstatic u_long		ticks_per_sec = 12500000;
85193149Sdougbstatic u_long		*decr_counts[MAXCPU];
86224093Sdougb
87170224Sdougbstatic int		decr_et_start(struct eventtimer *et,
88135549Sdes    struct bintime *first, struct bintime *period);
89135549Sdesstatic int		decr_et_stop(struct eventtimer *et);
90135549Sdesstatic timecounter_get_t	decr_get_timecount;
91165077Sdougb
92224093Sdougbstruct decr_state {
93135549Sdes	int	mode;	/* 0 - off, 1 - periodic, 2 - one-shot. */
94135549Sdes	int32_t	div;	/* Periodic divisor. */
95135549Sdes};
96135549Sdesstatic DPCPU_DEFINE(struct decr_state, decr_state);
97135549Sdes
98135549Sdesstatic struct eventtimer	decr_et;
99135549Sdesstatic struct timecounter	decr_tc = {
100170224Sdougb	decr_get_timecount,	/* get_timecount */
101135549Sdes	0,			/* no poll_pps */
102135549Sdes	~0u,			/* counter_mask */
103135549Sdes	0,			/* frequency */
104135549Sdes	"timebase"		/* name */
105135549Sdes};
106135549Sdes
107135549Sdes/*
108135549Sdes * Decrementor interrupt handler.
109135549Sdes */
110135549Sdesvoid
111135549Sdesdecr_intr(struct trapframe *frame)
112135549Sdes{
113135549Sdes	struct decr_state *s = DPCPU_PTR(decr_state);
114135549Sdes	int		nticks = 0;
115135549Sdes	int32_t		val;
116135549Sdes
117135549Sdes	if (!initialized)
118135549Sdes		return;
119135549Sdes
120135549Sdes	(*decr_counts[curcpu])++;
121135549Sdes
122135549Sdes	if (s->mode == 1) {
123135549Sdes		/*
124135549Sdes		 * Based on the actual time delay since the last decrementer
125135549Sdes		 * reload, we arrange for earlier interrupt next time.
126135549Sdes		 */
127135549Sdes		__asm ("mfdec %0" : "=r"(val));
128135549Sdes		while (val < 0) {
129135549Sdes			val += s->div;
130135549Sdes			nticks++;
131135549Sdes		}
132135549Sdes		mtdec(val);
133135549Sdes	} else if (s->mode == 2) {
134135549Sdes		nticks = 1;
135135549Sdes		decr_et_stop(NULL);
136135549Sdes	}
137135549Sdes
138135549Sdes	while (nticks-- > 0) {
139135549Sdes		if (decr_et.et_active)
140135549Sdes			decr_et.et_event_cb(&decr_et, decr_et.et_arg);
141135549Sdes	}
142135549Sdes}
143135549Sdes
144135549Sdes/*
145135549Sdes * BSP early initialization.
146135549Sdes */
147135549Sdesvoid
148135549Sdesdecr_init(void)
149135549Sdes{
150135549Sdes	struct cpuref cpu;
151135549Sdes	char buf[32];
152135549Sdes
153135549Sdes	/*
154135549Sdes	 * Check the BSP's timebase frequency. Sometimes we can't find the BSP, so fall
155135549Sdes	 * back to the first CPU in this case.
156135549Sdes	 */
157135549Sdes	if (platform_smp_get_bsp(&cpu) != 0)
158135549Sdes		platform_smp_first_cpu(&cpu);
159135549Sdes	ticks_per_sec = platform_timebase_freq(&cpu);
160135549Sdes	ns_per_tick = 1000000000 / ticks_per_sec;
161135549Sdes
162135549Sdes	set_cputicker(mftb, ticks_per_sec, 0);
163135549Sdes	snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
164135549Sdes	intrcnt_add(buf, &decr_counts[curcpu]);
165135549Sdes	decr_et_stop(NULL);
166135549Sdes	initialized = 1;
167135549Sdes}
168135549Sdes
169135549Sdes#ifdef SMP
170135549Sdes/*
171135549Sdes * AP early initialization.
172135549Sdes */
173135549Sdesvoid
174135549Sdesdecr_ap_init(void)
175135549Sdes{
176135549Sdes	char buf[32];
177135549Sdes
178135549Sdes	snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
179135549Sdes	intrcnt_add(buf, &decr_counts[curcpu]);
180135549Sdes	decr_et_stop(NULL);
181135549Sdes}
182135549Sdes#endif
183135549Sdes
184170224Sdougb/*
185135549Sdes * Final initialization.
186135549Sdes */
187135549Sdesvoid
188193149Sdougbdecr_tc_init(void)
189193149Sdougb{
190193149Sdougb
191193149Sdougb	decr_tc.tc_frequency = ticks_per_sec;
192193149Sdougb	tc_init(&decr_tc);
193193149Sdougb	decr_et.et_name = "decrementer";
194193149Sdougb	decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
195224093Sdougb	    ET_FLAGS_PERCPU;
196170224Sdougb	decr_et.et_quality = 1000;
197135549Sdes	decr_et.et_frequency = ticks_per_sec;
198135549Sdes	decr_et.et_min_period.sec = 0;
199135549Sdes	decr_et.et_min_period.frac =
200135549Sdes	    ((0x00000002LLU << 32) / ticks_per_sec) << 32;
201135549Sdes	decr_et.et_max_period.sec = 0x7fffffffLLU / ticks_per_sec;
202135549Sdes	decr_et.et_max_period.frac =
203135549Sdes	    ((0x7fffffffLLU << 32) / ticks_per_sec) << 32;
204165077Sdougb	decr_et.et_start = decr_et_start;
205224093Sdougb	decr_et.et_stop = decr_et_stop;
206135549Sdes	decr_et.et_priv = NULL;
207135549Sdes	et_register(&decr_et);
208135549Sdes}
209135549Sdes
210135549Sdes/*
211135549Sdes * Event timer start method.
212135549Sdes */
213170224Sdougbstatic int
214135549Sdesdecr_et_start(struct eventtimer *et,
215135549Sdes    struct bintime *first, struct bintime *period)
216135549Sdes{
217135549Sdes	struct decr_state *s = DPCPU_PTR(decr_state);
218135549Sdes	uint32_t fdiv;
219135549Sdes
220135549Sdes	if (period != NULL) {
221135549Sdes		s->mode = 1;
222135549Sdes		s->div = (decr_et.et_frequency * (period->frac >> 32)) >> 32;
223135549Sdes		if (period->sec != 0)
224135549Sdes			s->div += decr_et.et_frequency * period->sec;
225135549Sdes	} else {
226135549Sdes		s->mode = 2;
227135549Sdes		s->div = 0x7fffffff;
228135549Sdes	}
229135549Sdes	if (first != NULL) {
230135549Sdes		fdiv = (decr_et.et_frequency * (first->frac >> 32)) >> 32;
231135549Sdes		if (first->sec != 0)
232135549Sdes			fdiv += decr_et.et_frequency * first->sec;
233135549Sdes	} else
234135549Sdes		fdiv = s->div;
235135549Sdes
236135549Sdes	mtdec(fdiv);
237135549Sdes	return (0);
238135549Sdes}
239135549Sdes
240135549Sdes/*
241135549Sdes * Event timer stop method.
242135549Sdes */
243135549Sdesstatic int
244135549Sdesdecr_et_stop(struct eventtimer *et)
245135549Sdes{
246135549Sdes	struct decr_state *s = DPCPU_PTR(decr_state);
247135549Sdes
248135549Sdes	s->mode = 0;
249135549Sdes	s->div = 0x7fffffff;
250135549Sdes	mtdec(s->div);
251135549Sdes	return (0);
252135549Sdes}
253135549Sdes
254135549Sdes/*
255135549Sdes * Timecounter get method.
256135549Sdes */
257135549Sdesstatic unsigned
258135549Sdesdecr_get_timecount(struct timecounter *tc)
259135549Sdes{
260135549Sdes	register_t tb;
261135549Sdes
262135549Sdes	__asm __volatile("mftb %0" : "=r"(tb));
263135549Sdes	return (tb);
264135549Sdes}
265135549Sdes
266135549Sdes/*
267135549Sdes * Wait for about n microseconds (at least!).
268135549Sdes */
269135549Sdesvoid
270135549SdesDELAY(int n)
271135549Sdes{
272135549Sdes	u_quad_t	tb, ttb;
273135549Sdes
274135549Sdes	tb = mftb();
275135549Sdes	ttb = tb + (n * 1000 + ns_per_tick - 1) / ns_per_tick;
276135549Sdes	while (tb < ttb)
277135549Sdes		tb = mftb();
278135549Sdes}
279135549Sdes
280135549Sdes