i80321_timer.c revision 278613
1/*	$NetBSD: i80321_timer.c,v 1.7 2003/07/27 04:52:28 thorpej Exp $	*/
2
3/*-
4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed for the NetBSD Project by
20 *	Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 *    or promote products derived from this software without specific prior
23 *    written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * Timer/clock support for the Intel i80321 I/O processor.
40 */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: stable/10/sys/arm/xscale/i80321/i80321_timer.c 278613 2015-02-12 03:50:33Z ian $");
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/module.h>
49#include <sys/time.h>
50#include <sys/bus.h>
51#include <sys/resource.h>
52#include <sys/rman.h>
53#include <sys/timetc.h>
54
55#include <machine/armreg.h>
56#include <machine/bus.h>
57#include <machine/cpu.h>
58#include <machine/cpufunc.h>
59#include <machine/frame.h>
60#include <machine/resource.h>
61#include <machine/intr.h>
62#include <arm/xscale/i80321/i80321reg.h>
63#include <arm/xscale/i80321/i80321var.h>
64
65#ifdef CPU_XSCALE_81342
66#define ICU_INT_TIMER0	(8) /* XXX: Can't include i81342reg.h because
67			       definitions overrides the ones from i80321reg.h
68			       */
69#endif
70#include "opt_timer.h"
71
72void (*i80321_hardclock_hook)(void) = NULL;
73struct i80321_timer_softc {
74	device_t	dev;
75} timer_softc;
76
77
78static unsigned i80321_timer_get_timecount(struct timecounter *tc);
79
80
81static uint32_t counts_per_hz;
82
83#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342)
84static uint32_t offset;
85static uint32_t last = -1;
86#endif
87
88static int ticked = 0;
89
90#ifndef COUNTS_PER_SEC
91#define	COUNTS_PER_SEC		200000000	/* 200MHz */
92#endif
93
94#define	COUNTS_PER_USEC		(COUNTS_PER_SEC / 1000000)
95
96static struct timecounter i80321_timer_timecounter = {
97	i80321_timer_get_timecount, /* get_timecount */
98	NULL,			    /* no poll_pps */
99	~0u,			    /* counter_mask */
100#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342)
101	COUNTS_PER_SEC,
102#else
103	COUNTS_PER_SEC * 3,	 	   /* frequency */
104#endif
105	"i80321 timer",		    /* name */
106	1000			    /* quality */
107};
108
109static int
110i80321_timer_probe(device_t dev)
111{
112
113	device_set_desc(dev, "i80321 timer");
114	return (0);
115}
116
117static int
118i80321_timer_attach(device_t dev)
119{
120	timer_softc.dev = dev;
121
122	return (0);
123}
124
125static device_method_t i80321_timer_methods[] = {
126	DEVMETHOD(device_probe, i80321_timer_probe),
127	DEVMETHOD(device_attach, i80321_timer_attach),
128	{0, 0},
129};
130
131static driver_t i80321_timer_driver = {
132	"itimer",
133	i80321_timer_methods,
134	sizeof(struct i80321_timer_softc),
135};
136static devclass_t i80321_timer_devclass;
137
138DRIVER_MODULE(itimer, iq, i80321_timer_driver, i80321_timer_devclass, 0, 0);
139
140int	clockhandler(void *);
141
142
143static __inline uint32_t
144tmr1_read(void)
145{
146	uint32_t rv;
147
148#ifdef CPU_XSCALE_81342
149	__asm __volatile("mrc p6, 0, %0, c1, c9, 0"
150#else
151	__asm __volatile("mrc p6, 0, %0, c1, c1, 0"
152#endif
153		: "=r" (rv));
154	return (rv);
155}
156
157static __inline void
158tmr1_write(uint32_t val)
159{
160
161
162#ifdef CPU_XSCALE_81342
163	__asm __volatile("mcr p6, 0, %0, c1, c9, 0"
164#else
165	__asm __volatile("mcr p6, 0, %0, c1, c1, 0"
166#endif
167		:
168		: "r" (val));
169}
170
171static __inline uint32_t
172tcr1_read(void)
173{
174	uint32_t rv;
175
176#ifdef CPU_XSCALE_81342
177	__asm __volatile("mrc p6, 0, %0, c3, c9, 0"
178#else
179	__asm __volatile("mrc p6, 0, %0, c3, c1, 0"
180#endif
181		: "=r" (rv));
182	return (rv);
183}
184static __inline void
185tcr1_write(uint32_t val)
186{
187
188#ifdef CPU_XSCALE_81342
189	__asm __volatile("mcr p6, 0, %0, c3, c9, 0"
190#else
191	__asm __volatile("mcr p6, 0, %0, c3, c1, 0"
192#endif
193		:
194		: "r" (val));
195}
196
197static __inline void
198trr1_write(uint32_t val)
199{
200
201#ifdef CPU_XSCALE_81342
202	__asm __volatile("mcr p6, 0, %0, c5, c9, 0"
203#else
204	__asm __volatile("mcr p6, 0, %0, c5, c1, 0"
205#endif
206		:
207		: "r" (val));
208}
209
210static __inline uint32_t
211tmr0_read(void)
212{
213	uint32_t rv;
214
215#ifdef CPU_XSCALE_81342
216	__asm __volatile("mrc p6, 0, %0, c0, c9, 0"
217#else
218	__asm __volatile("mrc p6, 0, %0, c0, c1, 0"
219#endif
220		: "=r" (rv));
221	return (rv);
222}
223
224static __inline void
225tmr0_write(uint32_t val)
226{
227
228#ifdef CPU_XSCALE_81342
229	__asm __volatile("mcr p6, 0, %0, c0, c9, 0"
230#else
231	__asm __volatile("mcr p6, 0, %0, c0, c1, 0"
232#endif
233		:
234		: "r" (val));
235}
236
237static __inline uint32_t
238tcr0_read(void)
239{
240	uint32_t rv;
241
242#ifdef CPU_XSCALE_81342
243	__asm __volatile("mrc p6, 0, %0, c2, c9, 0"
244#else
245	__asm __volatile("mrc p6, 0, %0, c2, c1, 0"
246#endif
247		: "=r" (rv));
248	return (rv);
249}
250static __inline void
251tcr0_write(uint32_t val)
252{
253
254#ifdef CPU_XSCALE_81342
255	__asm __volatile("mcr p6, 0, %0, c2, c9, 0"
256#else
257	__asm __volatile("mcr p6, 0, %0, c2, c1, 0"
258#endif
259		:
260		: "r" (val));
261}
262
263static __inline void
264trr0_write(uint32_t val)
265{
266
267#ifdef CPU_XSCALE_81342
268	__asm __volatile("mcr p6, 0, %0, c4, c9, 0"
269#else
270	__asm __volatile("mcr p6, 0, %0, c4, c1, 0"
271#endif
272		:
273		: "r" (val));
274}
275
276static __inline void
277tisr_write(uint32_t val)
278{
279
280#ifdef CPU_XSCALE_81342
281	__asm __volatile("mcr p6, 0, %0, c6, c9, 0"
282#else
283	__asm __volatile("mcr p6, 0, %0, c6, c1, 0"
284#endif
285		:
286		: "r" (val));
287}
288
289static __inline uint32_t
290tisr_read(void)
291{
292	int ret;
293
294#ifdef CPU_XSCALE_81342
295	__asm __volatile("mrc p6, 0, %0, c6, c9, 0" : "=r" (ret));
296#else
297	__asm __volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret));
298#endif
299	return (ret);
300}
301
302static unsigned
303i80321_timer_get_timecount(struct timecounter *tc)
304{
305#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342)
306	uint32_t cur = tcr0_read();
307
308	if (cur > last && last != -1) {
309		offset += counts_per_hz;
310		if (ticked > 0)
311			ticked--;
312	}
313	if (ticked) {
314		offset += ticked * counts_per_hz;
315		ticked = 0;
316	}
317	return (counts_per_hz - cur + offset);
318#else
319	uint32_t ret;
320
321	__asm __volatile("mrc p14, 0, %0, c1, c0, 0\n"
322	    : "=r" (ret));
323	return (ret);
324#endif
325}
326
327/*
328 * i80321_calibrate_delay:
329 *
330 *	Calibrate the delay loop.
331 */
332void
333i80321_calibrate_delay(void)
334{
335
336	/*
337	 * Just use hz=100 for now -- we'll adjust it, if necessary,
338	 * in cpu_initclocks().
339	 */
340	counts_per_hz = COUNTS_PER_SEC / 100;
341
342	tmr0_write(0);			/* stop timer */
343	tisr_write(TISR_TMR0);		/* clear interrupt */
344	trr0_write(counts_per_hz);	/* reload value */
345	tcr0_write(counts_per_hz);	/* current value */
346
347	tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
348}
349
350/*
351 * cpu_initclocks:
352 *
353 *	Initialize the clock and get them going.
354 */
355void
356cpu_initclocks(void)
357{
358	u_int oldirqstate;
359	struct resource *irq;
360	int rid = 0;
361	void *ihl;
362	device_t dev = timer_softc.dev;
363
364	if (hz < 50 || COUNTS_PER_SEC % hz) {
365		printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
366		hz = 100;
367	}
368	tick = 1000000 / hz;	/* number of microseconds between interrupts */
369
370	/*
371	 * We only have one timer available; stathz and profhz are
372	 * always left as 0 (the upper-layer clock code deals with
373	 * this situation).
374	 */
375	if (stathz != 0)
376		printf("Cannot get %d Hz statclock\n", stathz);
377	stathz = 0;
378
379	if (profhz != 0)
380		printf("Cannot get %d Hz profclock\n", profhz);
381	profhz = 0;
382
383	/* Report the clock frequency. */
384
385	oldirqstate = disable_interrupts(PSR_I);
386
387	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
388#ifdef CPU_XSCALE_81342
389	    ICU_INT_TIMER0, ICU_INT_TIMER0,
390#else
391	    ICU_INT_TMR0, ICU_INT_TMR0,
392#endif
393	    1, RF_ACTIVE);
394	if (!irq)
395		panic("Unable to setup the clock irq handler.\n");
396	else
397		bus_setup_intr(dev, irq, INTR_TYPE_CLK, clockhandler, NULL,
398		    NULL, &ihl);
399	tmr0_write(0);			/* stop timer */
400	tisr_write(TISR_TMR0);		/* clear interrupt */
401
402	counts_per_hz = COUNTS_PER_SEC / hz;
403
404	trr0_write(counts_per_hz);	/* reload value */
405	tcr0_write(counts_per_hz);	/* current value */
406	tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
407
408	tc_init(&i80321_timer_timecounter);
409	restore_interrupts(oldirqstate);
410	rid = 0;
411#if !defined(XSCALE_DISABLE_CCNT) && !defined(CPU_XSCALE_81342)
412	/* Enable the clock count register. */
413	__asm __volatile("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (rid));
414	rid &= ~(1 <<  3);
415	rid |= (1 << 2) | 1;
416	__asm __volatile("mcr p14, 0, %0, c0, c0, 0\n"
417	    : : "r" (rid));
418#endif
419}
420
421
422/*
423 * DELAY:
424 *
425 *	Delay for at least N microseconds.
426 */
427void
428DELAY(int n)
429{
430	uint32_t cur, last, delta, usecs;
431
432	/*
433	 * This works by polling the timer and counting the
434	 * number of microseconds that go by.
435	 */
436	last = tcr0_read();
437	delta = usecs = 0;
438
439	while (n > usecs) {
440		cur = tcr0_read();
441
442		/* Check to see if the timer has wrapped around. */
443		if (last < cur)
444			delta += (last + (counts_per_hz - cur));
445		else
446			delta += (last - cur);
447
448		last = cur;
449
450		if (delta >= COUNTS_PER_USEC) {
451			usecs += delta / COUNTS_PER_USEC;
452			delta %= COUNTS_PER_USEC;
453		}
454	}
455}
456
457/*
458 * clockhandler:
459 *
460 *	Handle the hardclock interrupt.
461 */
462int
463clockhandler(void *arg)
464{
465	struct trapframe *frame = arg;
466
467	ticked++;
468	tisr_write(TISR_TMR0);
469	hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
470
471	if (i80321_hardclock_hook != NULL)
472		(*i80321_hardclock_hook)();
473	return (FILTER_HANDLED);
474}
475
476void
477cpu_startprofclock(void)
478{
479}
480
481void
482cpu_stopprofclock(void)
483{
484
485}
486