1193323Sed/*	$NetBSD: i80321_timer.c,v 1.7 2003/07/27 04:52:28 thorpej Exp $	*/
2193323Sed
3193323Sed/*-
4193323Sed * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
5193323Sed * All rights reserved.
6193323Sed *
7193323Sed * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8193323Sed *
9193323Sed * Redistribution and use in source and binary forms, with or without
10193323Sed * modification, are permitted provided that the following conditions
11193323Sed * are met:
12193323Sed * 1. Redistributions of source code must retain the above copyright
13193323Sed *    notice, this list of conditions and the following disclaimer.
14193323Sed * 2. Redistributions in binary form must reproduce the above copyright
15193323Sed *    notice, this list of conditions and the following disclaimer in the
16193323Sed *    documentation and/or other materials provided with the distribution.
17193323Sed * 3. All advertising materials mentioning features or use of this software
18193323Sed *    must display the following acknowledgement:
19193323Sed *	This product includes software developed for the NetBSD Project by
20193323Sed *	Wasabi Systems, Inc.
21193323Sed * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22193323Sed *    or promote products derived from this software without specific prior
23198090Srdivacky *    written permission.
24202375Srdivacky *
25193323Sed * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27193323Sed * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28193323Sed * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29193323Sed * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30198090Srdivacky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31198090Srdivacky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32207618Srdivacky * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33198090Srdivacky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34207618Srdivacky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35198090Srdivacky * POSSIBILITY OF SUCH DAMAGE.
36198090Srdivacky */
37198090Srdivacky
38198090Srdivacky/*
39198090Srdivacky * Timer/clock support for the Intel i80321 I/O processor.
40193323Sed */
41193323Sed
42193323Sed#include <sys/cdefs.h>
43193323Sed__FBSDID("$FreeBSD$");
44193323Sed
45193323Sed#include <sys/param.h>
46193323Sed#include <sys/systm.h>
47193323Sed#include <sys/kernel.h>
48198090Srdivacky#include <sys/module.h>
49198090Srdivacky#include <sys/time.h>
50198090Srdivacky#include <sys/bus.h>
51198090Srdivacky#include <sys/resource.h>
52198090Srdivacky#include <sys/rman.h>
53198090Srdivacky#include <sys/timetc.h>
54198090Srdivacky
55198090Srdivacky#include <machine/bus.h>
56198090Srdivacky#include <machine/cpu.h>
57198090Srdivacky#include <machine/cpufunc.h>
58198090Srdivacky#include <machine/frame.h>
59198090Srdivacky#include <machine/resource.h>
60201360Srdivacky#include <machine/intr.h>
61198090Srdivacky#include <arm/xscale/i80321/i80321reg.h>
62198090Srdivacky#include <arm/xscale/i80321/i80321var.h>
63198090Srdivacky
64198090Srdivacky#ifdef CPU_XSCALE_81342
65198090Srdivacky#define ICU_INT_TIMER0	(8) /* XXX: Can't include i81342reg.h because
66198090Srdivacky			       definitions overrides the ones from i80321reg.h
67198090Srdivacky			       */
68198090Srdivacky#endif
69198090Srdivacky#include "opt_timer.h"
70198090Srdivacky
71198090Srdivackyvoid (*i80321_hardclock_hook)(void) = NULL;
72198090Srdivackystruct i80321_timer_softc {
73198090Srdivacky	device_t	dev;
74198090Srdivacky} timer_softc;
75198090Srdivacky
76198090Srdivacky
77198090Srdivackystatic unsigned i80321_timer_get_timecount(struct timecounter *tc);
78198090Srdivacky
79198090Srdivacky
80198090Srdivackystatic uint32_t counts_per_hz;
81198090Srdivacky
82198090Srdivacky#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342)
83198090Srdivackystatic uint32_t offset;
84198090Srdivackystatic uint32_t last = -1;
85198090Srdivacky#endif
86198090Srdivacky
87198090Srdivackystatic int ticked = 0;
88198090Srdivacky
89198090Srdivacky#ifndef COUNTS_PER_SEC
90198090Srdivacky#define	COUNTS_PER_SEC		200000000	/* 200MHz */
91198090Srdivacky#endif
92198090Srdivacky
93198090Srdivacky#define	COUNTS_PER_USEC		(COUNTS_PER_SEC / 1000000)
94198090Srdivacky
95198090Srdivackystatic struct timecounter i80321_timer_timecounter = {
96198090Srdivacky	i80321_timer_get_timecount, /* get_timecount */
97198090Srdivacky	NULL,			    /* no poll_pps */
98198090Srdivacky	~0u,			    /* counter_mask */
99198090Srdivacky#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342)
100198090Srdivacky	COUNTS_PER_SEC,
101198090Srdivacky#else
102198090Srdivacky	COUNTS_PER_SEC * 3,	 	   /* frequency */
103198090Srdivacky#endif
104198090Srdivacky	"i80321 timer",		    /* name */
105198090Srdivacky	1000			    /* quality */
106198090Srdivacky};
107198090Srdivacky
108198090Srdivackystatic int
109198090Srdivackyi80321_timer_probe(device_t dev)
110198090Srdivacky{
111198090Srdivacky
112198090Srdivacky	device_set_desc(dev, "i80321 timer");
113198090Srdivacky	return (0);
114198090Srdivacky}
115198090Srdivacky
116198090Srdivackystatic int
117198090Srdivackyi80321_timer_attach(device_t dev)
118198090Srdivacky{
119198090Srdivacky	timer_softc.dev = dev;
120198090Srdivacky
121198090Srdivacky	return (0);
122198090Srdivacky}
123198090Srdivacky
124198090Srdivackystatic device_method_t i80321_timer_methods[] = {
125198090Srdivacky	DEVMETHOD(device_probe, i80321_timer_probe),
126198090Srdivacky	DEVMETHOD(device_attach, i80321_timer_attach),
127198090Srdivacky	{0, 0},
128198090Srdivacky};
129198090Srdivacky
130198090Srdivackystatic driver_t i80321_timer_driver = {
131198090Srdivacky	"itimer",
132198090Srdivacky	i80321_timer_methods,
133198090Srdivacky	sizeof(struct i80321_timer_softc),
134198090Srdivacky};
135198090Srdivackystatic devclass_t i80321_timer_devclass;
136198090Srdivacky
137198090SrdivackyDRIVER_MODULE(itimer, iq, i80321_timer_driver, i80321_timer_devclass, 0, 0);
138198090Srdivacky
139198090Srdivackyint	clockhandler(void *);
140198090Srdivacky
141198090Srdivacky
142198090Srdivackystatic __inline uint32_t
143198090Srdivackytmr1_read(void)
144198090Srdivacky{
145198090Srdivacky	uint32_t rv;
146198090Srdivacky
147198090Srdivacky#ifdef CPU_XSCALE_81342
148198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c1, c9, 0"
149198090Srdivacky#else
150198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c1, c1, 0"
151198090Srdivacky#endif
152198090Srdivacky		: "=r" (rv));
153198090Srdivacky	return (rv);
154198090Srdivacky}
155198090Srdivacky
156198090Srdivackystatic __inline void
157198090Srdivackytmr1_write(uint32_t val)
158198090Srdivacky{
159198090Srdivacky
160198090Srdivacky
161198090Srdivacky#ifdef CPU_XSCALE_81342
162198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c1, c9, 0"
163198090Srdivacky#else
164198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c1, c1, 0"
165198090Srdivacky#endif
166198090Srdivacky		:
167198090Srdivacky		: "r" (val));
168198090Srdivacky}
169198090Srdivacky
170198090Srdivackystatic __inline uint32_t
171198090Srdivackytcr1_read(void)
172198090Srdivacky{
173198090Srdivacky	uint32_t rv;
174198090Srdivacky
175198090Srdivacky#ifdef CPU_XSCALE_81342
176198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c3, c9, 0"
177198090Srdivacky#else
178198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c3, c1, 0"
179198090Srdivacky#endif
180198090Srdivacky		: "=r" (rv));
181198090Srdivacky	return (rv);
182198090Srdivacky}
183198090Srdivackystatic __inline void
184198090Srdivackytcr1_write(uint32_t val)
185198090Srdivacky{
186198090Srdivacky
187198090Srdivacky#ifdef CPU_XSCALE_81342
188198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c3, c9, 0"
189198090Srdivacky#else
190198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c3, c1, 0"
191198090Srdivacky#endif
192198090Srdivacky		:
193198090Srdivacky		: "r" (val));
194198090Srdivacky}
195198090Srdivacky
196198090Srdivackystatic __inline void
197198090Srdivackytrr1_write(uint32_t val)
198198090Srdivacky{
199198090Srdivacky
200198090Srdivacky#ifdef CPU_XSCALE_81342
201198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c5, c9, 0"
202198090Srdivacky#else
203198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c5, c1, 0"
204198090Srdivacky#endif
205198090Srdivacky		:
206198090Srdivacky		: "r" (val));
207198090Srdivacky}
208198090Srdivacky
209198090Srdivackystatic __inline uint32_t
210198090Srdivackytmr0_read(void)
211198090Srdivacky{
212198090Srdivacky	uint32_t rv;
213198090Srdivacky
214198090Srdivacky#ifdef CPU_XSCALE_81342
215198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c0, c9, 0"
216198090Srdivacky#else
217198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c0, c1, 0"
218198090Srdivacky#endif
219198090Srdivacky		: "=r" (rv));
220198090Srdivacky	return (rv);
221198090Srdivacky}
222198090Srdivacky
223198090Srdivackystatic __inline void
224198090Srdivackytmr0_write(uint32_t val)
225198090Srdivacky{
226198090Srdivacky
227198090Srdivacky#ifdef CPU_XSCALE_81342
228198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c0, c9, 0"
229198090Srdivacky#else
230198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c0, c1, 0"
231198090Srdivacky#endif
232198090Srdivacky		:
233198090Srdivacky		: "r" (val));
234198090Srdivacky}
235198090Srdivacky
236198090Srdivackystatic __inline uint32_t
237198090Srdivackytcr0_read(void)
238198090Srdivacky{
239198090Srdivacky	uint32_t rv;
240198090Srdivacky
241198090Srdivacky#ifdef CPU_XSCALE_81342
242198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c2, c9, 0"
243198090Srdivacky#else
244198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c2, c1, 0"
245198090Srdivacky#endif
246198090Srdivacky		: "=r" (rv));
247199989Srdivacky	return (rv);
248199989Srdivacky}
249199989Srdivackystatic __inline void
250199989Srdivackytcr0_write(uint32_t val)
251199989Srdivacky{
252198090Srdivacky
253198090Srdivacky#ifdef CPU_XSCALE_81342
254198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c2, c9, 0"
255198090Srdivacky#else
256198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c2, c1, 0"
257198090Srdivacky#endif
258198090Srdivacky		:
259198090Srdivacky		: "r" (val));
260198090Srdivacky}
261198090Srdivacky
262198090Srdivackystatic __inline void
263198090Srdivackytrr0_write(uint32_t val)
264198090Srdivacky{
265198090Srdivacky
266205218Srdivacky#ifdef CPU_XSCALE_81342
267198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c4, c9, 0"
268198090Srdivacky#else
269210299Sed	__asm __volatile("mcr p6, 0, %0, c4, c1, 0"
270198090Srdivacky#endif
271198090Srdivacky		:
272199481Srdivacky		: "r" (val));
273199481Srdivacky}
274198090Srdivacky
275198090Srdivackystatic __inline void
276210299Sedtisr_write(uint32_t val)
277210299Sed{
278210299Sed
279198090Srdivacky#ifdef CPU_XSCALE_81342
280198090Srdivacky	__asm __volatile("mcr p6, 0, %0, c6, c9, 0"
281204961Srdivacky#else
282204961Srdivacky	__asm __volatile("mcr p6, 0, %0, c6, c1, 0"
283204961Srdivacky#endif
284204961Srdivacky		:
285204961Srdivacky		: "r" (val));
286204961Srdivacky}
287205218Srdivacky
288198090Srdivackystatic __inline uint32_t
289198090Srdivackytisr_read(void)
290198090Srdivacky{
291198090Srdivacky	int ret;
292198090Srdivacky
293198090Srdivacky#ifdef CPU_XSCALE_81342
294198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c6, c9, 0" : "=r" (ret));
295198090Srdivacky#else
296198090Srdivacky	__asm __volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret));
297198090Srdivacky#endif
298198090Srdivacky	return (ret);
299199481Srdivacky}
300199481Srdivacky
301199481Srdivackystatic unsigned
302199481Srdivackyi80321_timer_get_timecount(struct timecounter *tc)
303199481Srdivacky{
304199481Srdivacky#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342)
305199481Srdivacky	uint32_t cur = tcr0_read();
306199481Srdivacky
307198396Srdivacky	if (cur > last && last != -1) {
308198396Srdivacky		offset += counts_per_hz;
309198396Srdivacky		if (ticked > 0)
310198090Srdivacky			ticked--;
311198090Srdivacky	}
312198090Srdivacky	if (ticked) {
313198090Srdivacky		offset += ticked * counts_per_hz;
314198090Srdivacky		ticked = 0;
315198090Srdivacky	}
316198090Srdivacky	return (counts_per_hz - cur + offset);
317198396Srdivacky#else
318198090Srdivacky	uint32_t ret;
319198090Srdivacky
320198090Srdivacky	__asm __volatile("mrc p14, 0, %0, c1, c0, 0\n"
321198090Srdivacky	    : "=r" (ret));
322198090Srdivacky	return (ret);
323198090Srdivacky#endif
324198090Srdivacky}
325200581Srdivacky
326198090Srdivacky/*
327198090Srdivacky * i80321_calibrate_delay:
328198090Srdivacky *
329200581Srdivacky *	Calibrate the delay loop.
330200581Srdivacky */
331198090Srdivackyvoid
332198090Srdivackyi80321_calibrate_delay(void)
333198090Srdivacky{
334198090Srdivacky
335198090Srdivacky	/*
336198090Srdivacky	 * Just use hz=100 for now -- we'll adjust it, if necessary,
337198090Srdivacky	 * in cpu_initclocks().
338198090Srdivacky	 */
339198090Srdivacky	counts_per_hz = COUNTS_PER_SEC / 100;
340198090Srdivacky
341198090Srdivacky	tmr0_write(0);			/* stop timer */
342198090Srdivacky	tisr_write(TISR_TMR0);		/* clear interrupt */
343198090Srdivacky	trr0_write(counts_per_hz);	/* reload value */
344198090Srdivacky	tcr0_write(counts_per_hz);	/* current value */
345198090Srdivacky
346198090Srdivacky	tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
347198090Srdivacky}
348198090Srdivacky
349198090Srdivacky/*
350198090Srdivacky * cpu_initclocks:
351198090Srdivacky *
352198090Srdivacky *	Initialize the clock and get them going.
353198090Srdivacky */
354198090Srdivackyvoid
355198090Srdivackycpu_initclocks(void)
356198090Srdivacky{
357198090Srdivacky	u_int oldirqstate;
358198090Srdivacky	struct resource *irq;
359198090Srdivacky	int rid = 0;
360198090Srdivacky	void *ihl;
361198090Srdivacky	device_t dev = timer_softc.dev;
362198090Srdivacky
363198090Srdivacky	if (hz < 50 || COUNTS_PER_SEC % hz) {
364198090Srdivacky		printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
365198090Srdivacky		hz = 100;
366198090Srdivacky	}
367198090Srdivacky	tick = 1000000 / hz;	/* number of microseconds between interrupts */
368198090Srdivacky
369198090Srdivacky	/*
370198090Srdivacky	 * We only have one timer available; stathz and profhz are
371198090Srdivacky	 * always left as 0 (the upper-layer clock code deals with
372198090Srdivacky	 * this situation).
373198090Srdivacky	 */
374198090Srdivacky	if (stathz != 0)
375198090Srdivacky		printf("Cannot get %d Hz statclock\n", stathz);
376198090Srdivacky	stathz = 0;
377198090Srdivacky
378198090Srdivacky	if (profhz != 0)
379198090Srdivacky		printf("Cannot get %d Hz profclock\n", profhz);
380198090Srdivacky	profhz = 0;
381198090Srdivacky
382198090Srdivacky	/* Report the clock frequency. */
383198090Srdivacky
384198090Srdivacky	oldirqstate = disable_interrupts(I32_bit);
385198090Srdivacky
386198090Srdivacky	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
387198090Srdivacky#ifdef CPU_XSCALE_81342
388198090Srdivacky	    ICU_INT_TIMER0, ICU_INT_TIMER0,
389198090Srdivacky#else
390198090Srdivacky	    ICU_INT_TMR0, ICU_INT_TMR0,
391198090Srdivacky#endif
392198090Srdivacky	    1, RF_ACTIVE);
393198090Srdivacky	if (!irq)
394202375Srdivacky		panic("Unable to setup the clock irq handler.\n");
395202375Srdivacky	else
396202375Srdivacky		bus_setup_intr(dev, irq, INTR_TYPE_CLK, clockhandler, NULL,
397202375Srdivacky		    NULL, &ihl);
398193323Sed	tmr0_write(0);			/* stop timer */
399193323Sed	tisr_write(TISR_TMR0);		/* clear interrupt */
400193323Sed
401193323Sed	counts_per_hz = COUNTS_PER_SEC / hz;
402193323Sed
403195340Sed	trr0_write(counts_per_hz);	/* reload value */
404193323Sed	tcr0_write(counts_per_hz);	/* current value */
405193323Sed	tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
406193323Sed
407198090Srdivacky	tc_init(&i80321_timer_timecounter);
408198090Srdivacky	restore_interrupts(oldirqstate);
409198090Srdivacky	rid = 0;
410198090Srdivacky#if !defined(XSCALE_DISABLE_CCNT) && !defined(CPU_XSCALE_81342)
411198090Srdivacky	/* Enable the clock count register. */
412198090Srdivacky	__asm __volatile("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (rid));
413198090Srdivacky	rid &= ~(1 <<  3);
414198090Srdivacky	rid |= (1 << 2) | 1;
415198090Srdivacky	__asm __volatile("mcr p14, 0, %0, c0, c0, 0\n"
416198090Srdivacky	    : : "r" (rid));
417198090Srdivacky#endif
418198090Srdivacky}
419198090Srdivacky
420198090Srdivacky
421198090Srdivacky/*
422198090Srdivacky * DELAY:
423198090Srdivacky *
424193323Sed *	Delay for at least N microseconds.
425193323Sed */
426193323Sedvoid
427193323SedDELAY(int n)
428198090Srdivacky{
429198090Srdivacky	uint32_t cur, last, delta, usecs;
430198090Srdivacky
431198090Srdivacky	/*
432198090Srdivacky	 * This works by polling the timer and counting the
433	 * number of microseconds that go by.
434	 */
435	last = tcr0_read();
436	delta = usecs = 0;
437
438	while (n > usecs) {
439		cur = tcr0_read();
440
441		/* Check to see if the timer has wrapped around. */
442		if (last < cur)
443			delta += (last + (counts_per_hz - cur));
444		else
445			delta += (last - cur);
446
447		last = cur;
448
449		if (delta >= COUNTS_PER_USEC) {
450			usecs += delta / COUNTS_PER_USEC;
451			delta %= COUNTS_PER_USEC;
452		}
453	}
454}
455
456/*
457 * clockhandler:
458 *
459 *	Handle the hardclock interrupt.
460 */
461int
462clockhandler(void *arg)
463{
464	struct trapframe *frame = arg;
465
466	ticked++;
467	tisr_write(TISR_TMR0);
468	hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
469
470	if (i80321_hardclock_hook != NULL)
471		(*i80321_hardclock_hook)();
472	return (FILTER_HANDLED);
473}
474
475void
476cpu_startprofclock(void)
477{
478}
479
480void
481cpu_stopprofclock(void)
482{
483
484}
485