1/*	$NetBSD: omap2_mputmr.c,v 1.3 2010/06/19 19:44:58 matt Exp $	*/
2
3/*
4 * OMAP 2430 GP timers
5 */
6
7/*
8 * Based on i80321_timer.c and arch/arm/sa11x0/sa11x0_ost.c
9 *
10 * Copyright (c) 1997 Mark Brinicombe.
11 * Copyright (c) 1997 Causality Limited.
12 * All rights reserved.
13 *
14 * This code is derived from software contributed to The NetBSD Foundation
15 * by IWAMOTO Toshihiro and Ichiro FUKUHARA.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 * 3. All advertising materials mentioning features or use of this software
26 *    must display the following acknowledgement:
27 *	This product includes software developed by the NetBSD
28 *	Foundation, Inc. and its contributors.
29 * 4. Neither the name of The NetBSD Foundation nor the names of its
30 *    contributors may be used to endorse or promote products derived
31 *    from this software without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
34 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
35 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
36 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
37 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 * POSSIBILITY OF SUCH DAMAGE.
44 *
45 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
46 * All rights reserved.
47 *
48 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
49 *
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 * 1. Redistributions of source code must retain the above copyright
54 *    notice, this list of conditions and the following disclaimer.
55 * 2. Redistributions in binary form must reproduce the above copyright
56 *    notice, this list of conditions and the following disclaimer in the
57 *    documentation and/or other materials provided with the distribution.
58 * 3. All advertising materials mentioning features or use of this software
59 *    must display the following acknowledgement:
60 *	This product includes software developed for the NetBSD Project by
61 *	Wasabi Systems, Inc.
62 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
63 *    or promote products derived from this software without specific prior
64 *    written permission.
65 *
66 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
67 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
68 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
69 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
70 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
71 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
72 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
73 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
74 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
75 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
76 * POSSIBILITY OF SUCH DAMAGE.
77 */
78
79#include <sys/cdefs.h>
80__KERNEL_RCSID(0, "$NetBSD: omap2_mputmr.c,v 1.3 2010/06/19 19:44:58 matt Exp $");
81
82#include "opt_omap.h"
83#include "opt_cpuoptions.h"
84
85#include <sys/types.h>
86#include <sys/param.h>
87#include <sys/systm.h>
88#include <sys/kernel.h>
89#include <sys/time.h>
90#include <sys/timetc.h>
91#include <sys/device.h>
92
93#include <dev/clock_subr.h>
94
95#include <sys/bus.h>
96#include <machine/intr.h>
97
98#include <arm/omap/omap_gptmrreg.h>
99#include <arm/omap/omap2_mputmrvar.h>
100
101#ifndef ARM11_PMC
102uint32_t counts_per_usec, counts_per_hz;
103#endif
104struct mputmr_softc *clock_sc;
105struct mputmr_softc *stat_sc;
106struct mputmr_softc *ref_sc;
107static uint32_t mpu_get_timecount(struct timecounter *);
108
109static struct timecounter mpu_timecounter = {
110	.tc_get_timecount = mpu_get_timecount,
111	.tc_counter_mask = 0xffffffff,
112	.tc_frequency = OMAP_MPU_TIMER_CLOCK_FREQ,
113	.tc_name = "gpt",
114	.tc_quality = 100,
115	.tc_priv = NULL
116};
117
118static inline void
119_timer_intr_dis(struct mputmr_softc *sc)
120{
121	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIER, 0);
122}
123
124static inline void
125_timer_intr_enb(struct mputmr_softc *sc)
126{
127	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIER, TIER_OVF_IT_ENA);
128}
129
130static inline uint32_t
131_timer_intr_sts(struct mputmr_softc *sc)
132{
133	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, TISR);
134}
135
136static inline void
137_timer_intr_ack(struct mputmr_softc *sc)
138{
139	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TISR, TIER_OVF_IT_ENA);
140}
141
142static inline uint32_t
143_timer_read(struct mputmr_softc *sc)
144{
145	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, TCRR);
146}
147
148static inline void
149_timer_stop(struct mputmr_softc *sc)
150{
151	uint32_t r;
152
153	r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TCLR);
154	r &= ~TCLR_ST;
155	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCLR, r);
156}
157
158static inline void
159_timer_reload(struct mputmr_softc *sc, uint32_t val)
160{
161	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TLDR, val);
162	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCRR, val);
163}
164
165static inline void
166_timer_start(struct mputmr_softc *sc, timer_factors *tfp)
167{
168	uint32_t r=0;
169
170	if (tfp->ptv != 0) {
171		r |= TCLR_PRE(1);
172		r |= (TCLR_PTV(tfp->ptv - 1) & TCLR_PTV_MASK);
173	}
174	r |= (TCLR_CE | TCLR_AR | TCLR_ST);
175
176	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCLR, r);
177}
178
179static uint32_t
180mpu_get_timecount(struct timecounter *tc)
181{
182	return _timer_read(ref_sc);
183}
184
185int
186clockintr(void *frame)
187{
188	_timer_intr_ack(clock_sc);
189	hardclock(frame);
190	return 1;
191}
192
193int
194statintr(void *frame)
195{
196	_timer_intr_ack(stat_sc);
197	statclock(frame);
198	return 1;
199}
200
201static void
202setclockrate(struct mputmr_softc *sc, int schz)
203{
204	timer_factors tf;
205
206	_timer_stop(sc);
207	calc_timer_factors(schz, &tf);
208	_timer_reload(sc, tf.reload);
209	_timer_start(sc, &tf);
210}
211
212void
213setstatclockrate(int schz)
214{
215	setclockrate(stat_sc, schz);
216}
217
218void
219cpu_initclocks(void)
220{
221	if (clock_sc == NULL)
222		panic("Clock timer was not configured.");
223	if (stat_sc == NULL)
224		panic("Statistics timer was not configured.");
225	if (ref_sc == NULL)
226		panic("Microtime reference timer was not configured.");
227
228	/*
229	 * We already have the timers running, but not generating interrupts.
230	 * In addition, we've set stathz and profhz.
231	 */
232	printf("clock: hz=%d stathz=%d\n", hz, stathz);
233
234	_timer_intr_dis(clock_sc);
235	_timer_intr_dis(stat_sc);
236	_timer_intr_dis(ref_sc);
237
238	setclockrate(clock_sc, hz);
239	setclockrate(stat_sc, stathz);
240	setclockrate(ref_sc, 0);
241
242
243	/*
244	 * The "cookie" parameter must be zero to pass the interrupt frame
245	 * through to hardclock() and statclock().
246	 */
247
248	intr_establish(clock_sc->sc_intr, IPL_CLOCK, IST_LEVEL, clockintr, 0);
249	intr_establish(stat_sc->sc_intr, IPL_HIGH, IST_LEVEL, statintr, 0);
250
251	_timer_intr_enb(clock_sc);
252	_timer_intr_enb(stat_sc);
253
254	tc_init(&mpu_timecounter);
255}
256
257#if !(defined(ARM11_PMC) || defined(CORTEX_PMC))
258void
259delay(u_int n)
260{
261	uint32_t cur, last, delta, usecs;
262
263	if (clock_sc == NULL)
264		panic("The timer must be initialized sooner.");
265
266	/*
267	 * This works by polling the timer and counting the
268	 * number of microseconds that go by.
269	 */
270	last = _timer_read(clock_sc);
271
272	delta = usecs = 0;
273
274	while (n > usecs) {
275		cur = _timer_read(clock_sc);
276
277		/* Check to see if the timer has wrapped around. */
278		if (last < cur)
279			delta += (last + (counts_per_hz - cur));
280		else
281			delta += (last - cur);
282
283		last = cur;
284
285		if (delta >= counts_per_usec) {
286			usecs += delta / counts_per_usec;
287			delta %= counts_per_usec;
288		}
289	}
290}
291#endif /* ARM11_PMC || CORTEX_PMC */
292
293/*
294 * OVF_Rate =
295 *	(0xFFFFFFFF - GPTn.TLDR + 1) * (timer functional clock period)  * PS
296 */
297void
298calc_timer_factors(int ints_per_sec, timer_factors *tf)
299{
300	uint32_t ptv_power;	/* PS */
301	uint32_t count_freq;
302	const uint32_t us_per_sec = 1000000;
303
304	if (ints_per_sec == 0) {
305		/*
306		 * When ints_per_sec equal to zero there is mean full range
307		 * timer usage. Nevertheless autoreload mode is still enabled.
308		 */
309		tf->ptv = 0;
310		tf->reload = 0;
311		tf->counts_per_usec = OMAP_MPU_TIMER_CLOCK_FREQ / us_per_sec;
312		return;
313	}
314
315
316	tf->ptv = 8;
317	for (;;) {
318		ptv_power = 1 << tf->ptv;
319		count_freq = OMAP_MPU_TIMER_CLOCK_FREQ;
320		count_freq /= hz;
321		count_freq /= ptv_power;
322		tf->reload = -count_freq;
323		tf->counts_per_usec = count_freq / us_per_sec;
324		if ((tf->reload * ptv_power * ints_per_sec
325		     == OMAP_MPU_TIMER_CLOCK_FREQ)
326		    && (tf->counts_per_usec * ptv_power * us_per_sec
327			== OMAP_MPU_TIMER_CLOCK_FREQ))
328		{	/* Exact match.  Life is good. */
329			/* Currently reload is MPU_LOAD_TIMER+1.  Fix it. */
330			tf->reload--;
331			return;
332		}
333		if (tf->ptv == 0) {
334			tf->counts_per_usec++;
335			return;
336		}
337		tf->ptv--;
338	}
339}
340