1178172Simp/*-
2178172Simp * Copyright (c) 2006-2007 Bruce M. Simpson.
3178172Simp * Copyright (c) 2003-2004 Juli Mallett.
4178172Simp * All rights reserved.
5178172Simp *
6178172Simp * Redistribution and use in source and binary forms, with or without
7178172Simp * modification, are permitted provided that the following conditions
8178172Simp * are met:
9178172Simp * 1. Redistributions of source code must retain the above copyright
10178172Simp *	notice, this list of conditions and the following disclaimer.
11178172Simp * 2. Redistributions in binary form must reproduce the above copyright
12178172Simp *	notice, this list of conditions and the following disclaimer in the
13178172Simp *	documentation and/or other materials provided with the distribution.
14178172Simp *
15178172Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18178172Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19178172Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25178172Simp * SUCH DAMAGE.
26178172Simp */
27178172Simp
28178172Simp/*
29178172Simp * Simple driver for the 32-bit interval counter built in to all
30178172Simp * MIPS32 CPUs.
31178172Simp */
32178172Simp
33178172Simp#include <sys/cdefs.h>
34178172Simp__FBSDID("$FreeBSD$");
35178172Simp
36178172Simp#include <sys/param.h>
37178172Simp#include <sys/systm.h>
38178172Simp#include <sys/sysctl.h>
39178172Simp#include <sys/bus.h>
40178172Simp#include <sys/kernel.h>
41178172Simp#include <sys/module.h>
42178172Simp#include <sys/rman.h>
43178172Simp#include <sys/power.h>
44178172Simp#include <sys/smp.h>
45178172Simp#include <sys/time.h>
46210403Smav#include <sys/timeet.h>
47178172Simp#include <sys/timetc.h>
48178172Simp
49203746Sneel#include <machine/hwfunc.h>
50178172Simp#include <machine/clock.h>
51178172Simp#include <machine/locore.h>
52178172Simp#include <machine/md_var.h>
53178172Simp
54178172Simpuint64_t counter_freq;
55178172Simp
56205364Sneelstruct timecounter *platform_timecounter;
57205364Sneel
58215701Sdimstatic DPCPU_DEFINE(uint32_t, cycles_per_tick);
59210403Smavstatic uint32_t cycles_per_usec;
60178172Simp
61215701Sdimstatic DPCPU_DEFINE(volatile uint32_t, counter_upper);
62215701Sdimstatic DPCPU_DEFINE(volatile uint32_t, counter_lower_last);
63215701Sdimstatic DPCPU_DEFINE(uint32_t, compare_ticks);
64215701Sdimstatic DPCPU_DEFINE(uint32_t, lost_ticks);
65178172Simp
66210403Smavstruct clock_softc {
67210403Smav	int intr_rid;
68210403Smav	struct resource *intr_res;
69210403Smav	void *intr_handler;
70210403Smav	struct timecounter tc;
71210403Smav	struct eventtimer et;
72210403Smav};
73210403Smavstatic struct clock_softc *softc;
74210403Smav
75178172Simp/*
76178172Simp * Device methods
77178172Simp */
78178172Simpstatic int clock_probe(device_t);
79178172Simpstatic void clock_identify(driver_t *, device_t);
80178172Simpstatic int clock_attach(device_t);
81178172Simpstatic unsigned counter_get_timecount(struct timecounter *tc);
82178172Simp
83178172Simpvoid
84178172Simpmips_timer_early_init(uint64_t clock_hz)
85178172Simp{
86178172Simp	/* Initialize clock early so that we can use DELAY sooner */
87178172Simp	counter_freq = clock_hz;
88178172Simp	cycles_per_usec = (clock_hz / (1000 * 1000));
89178172Simp}
90178172Simp
91178172Simpvoid
92202046Simpplatform_initclocks(void)
93178172Simp{
94203746Sneel
95205364Sneel	if (platform_timecounter != NULL)
96205364Sneel		tc_init(platform_timecounter);
97178172Simp}
98178172Simp
99178172Simpstatic uint64_t
100178172Simptick_ticker(void)
101178172Simp{
102178172Simp	uint64_t ret;
103178172Simp	uint32_t ticktock;
104210854Sneel	uint32_t t_lower_last, t_upper;
105178172Simp
106178172Simp	/*
107210854Sneel	 * Disable preemption because we are working with cpu specific data.
108178172Simp	 */
109210854Sneel	critical_enter();
110210854Sneel
111210854Sneel	/*
112210854Sneel	 * Note that even though preemption is disabled, interrupts are
113210854Sneel	 * still enabled. In particular there is a race with clock_intr()
114210854Sneel	 * reading the values of 'counter_upper' and 'counter_lower_last'.
115210854Sneel	 *
116210854Sneel	 * XXX this depends on clock_intr() being executed periodically
117210854Sneel	 * so that 'counter_upper' and 'counter_lower_last' are not stale.
118210854Sneel	 */
119210854Sneel	do {
120210854Sneel		t_upper = DPCPU_GET(counter_upper);
121210854Sneel		t_lower_last = DPCPU_GET(counter_lower_last);
122210854Sneel	} while (t_upper != DPCPU_GET(counter_upper));
123210854Sneel
124178172Simp	ticktock = mips_rd_count();
125210854Sneel
126178172Simp	critical_exit();
127178172Simp
128210854Sneel	/* COUNT register wrapped around */
129210854Sneel	if (ticktock < t_lower_last)
130210854Sneel		t_upper++;
131210854Sneel
132210854Sneel	ret = ((uint64_t)t_upper << 32) | ticktock;
133178172Simp	return (ret);
134178172Simp}
135178172Simp
136178172Simpvoid
137178172Simpmips_timer_init_params(uint64_t platform_counter_freq, int double_count)
138178172Simp{
139178172Simp
140178172Simp	/*
141178172Simp	 * XXX: Do not use printf here: uart code 8250 may use DELAY so this
142178172Simp	 * function should  be called before cninit.
143178172Simp	 */
144178172Simp	counter_freq = platform_counter_freq;
145202046Simp	/*
146202046Simp	 * XXX: Some MIPS32 cores update the Count register only every two
147202046Simp	 * pipeline cycles.
148202797Simp	 * We know this because of status registers in CP0, make it automatic.
149202046Simp	 */
150202046Simp	if (double_count != 0)
151202046Simp		counter_freq /= 2;
152202046Simp
153178172Simp	cycles_per_usec = counter_freq / (1 * 1000 * 1000);
154178172Simp	set_cputicker(tick_ticker, counter_freq, 1);
155178172Simp}
156178172Simp
157178172Simpstatic int
158178172Simpsysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS)
159178172Simp{
160178172Simp	int error;
161178172Simp	uint64_t freq;
162178172Simp
163210403Smav	if (softc == NULL)
164178172Simp		return (EOPNOTSUPP);
165178172Simp	freq = counter_freq;
166217616Smdf	error = sysctl_handle_64(oidp, &freq, sizeof(freq), req);
167178172Simp	if (error == 0 && req->newptr != NULL) {
168178172Simp		counter_freq = freq;
169210403Smav		softc->et.et_frequency = counter_freq;
170210403Smav		softc->tc.tc_frequency = counter_freq;
171178172Simp	}
172178172Simp	return (error);
173178172Simp}
174178172Simp
175217616SmdfSYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_U64 | CTLFLAG_RW,
176217616Smdf    NULL, 0, sysctl_machdep_counter_freq, "QU",
177181236Strhodes    "Timecounter frequency in Hz");
178178172Simp
179178172Simpstatic unsigned
180178172Simpcounter_get_timecount(struct timecounter *tc)
181178172Simp{
182178172Simp
183178172Simp	return (mips_rd_count());
184178172Simp}
185178172Simp
186178172Simp/*
187178172Simp * Wait for about n microseconds (at least!).
188178172Simp */
189178172Simpvoid
190178172SimpDELAY(int n)
191178172Simp{
192178172Simp	uint32_t cur, last, delta, usecs;
193178172Simp
194178172Simp	/*
195178172Simp	 * This works by polling the timer and counting the number of
196178172Simp	 * microseconds that go by.
197178172Simp	 */
198178172Simp	last = mips_rd_count();
199178172Simp	delta = usecs = 0;
200178172Simp
201178172Simp	while (n > usecs) {
202178172Simp		cur = mips_rd_count();
203178172Simp
204178172Simp		/* Check to see if the timer has wrapped around. */
205178172Simp		if (cur < last)
206202046Simp			delta += cur + (0xffffffff - last) + 1;
207178172Simp		else
208202046Simp			delta += cur - last;
209178172Simp
210178172Simp		last = cur;
211178172Simp
212178172Simp		if (delta >= cycles_per_usec) {
213178172Simp			usecs += delta / cycles_per_usec;
214178172Simp			delta %= cycles_per_usec;
215178172Simp		}
216178172Simp	}
217178172Simp}
218178172Simp
219210403Smavstatic int
220247463Smavclock_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
221210403Smav{
222210403Smav	uint32_t fdiv, div, next;
223210403Smav
224247463Smav	if (period != 0) {
225247463Smav		div = (et->et_frequency * period) >> 32;
226210403Smav	} else
227210403Smav		div = 0;
228247463Smav	if (first != 0)
229247463Smav		fdiv = (et->et_frequency * first) >> 32;
230247463Smav	else
231210403Smav		fdiv = div;
232210403Smav	DPCPU_SET(cycles_per_tick, div);
233210403Smav	next = mips_rd_count() + fdiv;
234210403Smav	DPCPU_SET(compare_ticks, next);
235210403Smav	mips_wr_compare(next);
236210403Smav	return (0);
237210403Smav}
238210403Smav
239210403Smavstatic int
240210403Smavclock_stop(struct eventtimer *et)
241210403Smav{
242210403Smav
243210403Smav	DPCPU_SET(cycles_per_tick, 0);
244210403Smav	mips_wr_compare(0xffffffff);
245210403Smav	return (0);
246210403Smav}
247210403Smav
248178172Simp/*
249178172Simp * Device section of file below
250178172Simp */
251178172Simpstatic int
252178172Simpclock_intr(void *arg)
253178172Simp{
254210403Smav	struct clock_softc *sc = (struct clock_softc *)arg;
255210403Smav	uint32_t cycles_per_tick;
256208585Sneel	uint32_t count, compare_last, compare_next, lost_ticks;
257205576Sneel
258210403Smav	cycles_per_tick = DPCPU_GET(cycles_per_tick);
259178172Simp	/*
260178172Simp	 * Set next clock edge.
261178172Simp	 */
262205576Sneel	count = mips_rd_count();
263208585Sneel	compare_last = DPCPU_GET(compare_ticks);
264210403Smav	if (cycles_per_tick > 0) {
265210403Smav		compare_next = count + cycles_per_tick;
266210403Smav		DPCPU_SET(compare_ticks, compare_next);
267210403Smav		mips_wr_compare(compare_next);
268210404Smav	} else	/* In one-shot mode timer should be stopped after the event. */
269210403Smav		mips_wr_compare(0xffffffff);
270208585Sneel
271210854Sneel	/* COUNT register wrapped around */
272210854Sneel	if (count < DPCPU_GET(counter_lower_last)) {
273210854Sneel		DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1);
274178172Simp	}
275210854Sneel	DPCPU_SET(counter_lower_last, count);
276208585Sneel
277210403Smav	if (cycles_per_tick > 0) {
278178172Simp
279210403Smav		/*
280210403Smav		 * Account for the "lost time" between when the timer interrupt
281210403Smav		 * fired and when 'clock_intr' actually started executing.
282210403Smav		 */
283210403Smav		lost_ticks = DPCPU_GET(lost_ticks);
284210403Smav		lost_ticks += count - compare_last;
285210403Smav
286210403Smav		/*
287210403Smav		 * If the COUNT and COMPARE registers are no longer in sync
288210403Smav		 * then make up some reasonable value for the 'lost_ticks'.
289210403Smav		 *
290210403Smav		 * This could happen, for e.g., after we resume normal
291210403Smav		 * operations after exiting the debugger.
292210403Smav		 */
293210403Smav		if (lost_ticks > 2 * cycles_per_tick)
294210403Smav			lost_ticks = cycles_per_tick;
295205576Sneel
296210403Smav		while (lost_ticks >= cycles_per_tick) {
297210403Smav			if (sc->et.et_active)
298210403Smav				sc->et.et_event_cb(&sc->et, sc->et.et_arg);
299210403Smav			lost_ticks -= cycles_per_tick;
300210403Smav		}
301210403Smav		DPCPU_SET(lost_ticks, lost_ticks);
302208585Sneel	}
303210403Smav	if (sc->et.et_active)
304210403Smav		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
305178172Simp	return (FILTER_HANDLED);
306178172Simp}
307178172Simp
308178172Simpstatic int
309178172Simpclock_probe(device_t dev)
310178172Simp{
311178172Simp
312178172Simp	if (device_get_unit(dev) != 0)
313178172Simp		panic("can't attach more clocks");
314178172Simp
315178172Simp	device_set_desc(dev, "Generic MIPS32 ticker");
316265999Sian	return (BUS_PROBE_NOWILDCARD);
317178172Simp}
318178172Simp
319178172Simpstatic void
320178172Simpclock_identify(driver_t * drv, device_t parent)
321178172Simp{
322178172Simp
323178172Simp	BUS_ADD_CHILD(parent, 0, "clock", 0);
324178172Simp}
325178172Simp
326178172Simpstatic int
327178172Simpclock_attach(device_t dev)
328178172Simp{
329210403Smav	struct clock_softc *sc;
330178172Simp	int error;
331178172Simp
332210403Smav	softc = sc = device_get_softc(dev);
333210403Smav	sc->intr_rid = 0;
334210403Smav	sc->intr_res = bus_alloc_resource(dev,
335210403Smav	    SYS_RES_IRQ, &sc->intr_rid, 5, 5, 1, RF_ACTIVE);
336210403Smav	if (sc->intr_res == NULL) {
337178172Simp		device_printf(dev, "failed to allocate irq\n");
338178172Simp		return (ENXIO);
339178172Simp	}
340210403Smav	error = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
341210403Smav	    clock_intr, NULL, sc, &sc->intr_handler);
342178172Simp	if (error != 0) {
343178172Simp		device_printf(dev, "bus_setup_intr returned %d\n", error);
344178172Simp		return (error);
345178172Simp	}
346202046Simp
347210403Smav	sc->tc.tc_get_timecount = counter_get_timecount;
348210403Smav	sc->tc.tc_counter_mask = 0xffffffff;
349210403Smav	sc->tc.tc_frequency = counter_freq;
350210403Smav	sc->tc.tc_name = "MIPS32";
351210403Smav	sc->tc.tc_quality = 800;
352210403Smav	sc->tc.tc_priv = sc;
353210403Smav	tc_init(&sc->tc);
354210403Smav	sc->et.et_name = "MIPS32";
355210403Smav	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
356210403Smav	    ET_FLAGS_PERCPU;
357210403Smav	sc->et.et_quality = 800;
358210403Smav	sc->et.et_frequency = counter_freq;
359247463Smav	sc->et.et_min_period = 0x00004000LLU; /* To be safe. */
360247463Smav	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
361210403Smav	sc->et.et_start = clock_start;
362210403Smav	sc->et.et_stop = clock_stop;
363210403Smav	sc->et.et_priv = sc;
364210403Smav	et_register(&sc->et);
365178172Simp	return (0);
366178172Simp}
367178172Simp
368178172Simpstatic device_method_t clock_methods[] = {
369178172Simp	/* Device interface */
370178172Simp	DEVMETHOD(device_probe, clock_probe),
371178172Simp	DEVMETHOD(device_identify, clock_identify),
372178172Simp	DEVMETHOD(device_attach, clock_attach),
373178172Simp	DEVMETHOD(device_detach, bus_generic_detach),
374178172Simp	DEVMETHOD(device_shutdown, bus_generic_shutdown),
375178172Simp
376178172Simp	{0, 0}
377178172Simp};
378178172Simp
379178172Simpstatic driver_t clock_driver = {
380210403Smav	"clock",
381210403Smav	clock_methods,
382210403Smav	sizeof(struct clock_softc),
383178172Simp};
384178172Simp
385178172Simpstatic devclass_t clock_devclass;
386178172Simp
387178172SimpDRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0);
388