xref: /netbsd/sys/arch/sun2/sun2/clock.c (revision c4a72b64)
1 /*	$NetBSD: clock.c,v 1.5 2002/10/02 16:02:23 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Matthew Fredette
5  * Copyright (c) 1994 Gordon W. Ross
6  * Copyright (c) 1993 Adam Glass
7  * Copyright (c) 1988 University of Utah.
8  * Copyright (c) 1982, 1990, 1993
9  *	The Regents of the University of California.  All rights reserved.
10  *
11  * This code is derived from software contributed to Berkeley by
12  * the Systems Programming Group of the University of Utah Computer
13  * Science Department.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  * 3. All advertising materials mentioning features or use of this software
24  *    must display the following acknowledgement:
25  *	This product includes software developed by the University of
26  *	California, Berkeley and its contributors.
27  * 4. Neither the name of the University nor the names of its contributors
28  *    may be used to endorse or promote products derived from this software
29  *    without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
32  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41  * SUCH DAMAGE.
42  *
43  *	from: Utah Hdr: clock.c 1.18 91/01/21$
44  *	from: @(#)clock.c	8.2 (Berkeley) 1/12/94
45  */
46 
47 /*
48  * Machine-dependent clock routines for the Am9513
49  * Written by Matthew Fredette, based on the sun3 clock.c by
50  * Adam Glass and Gordon Ross.
51  */
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/time.h>
56 #include <sys/kernel.h>
57 #include <sys/device.h>
58 
59 #include <machine/autoconf.h>
60 #include <machine/cpu.h>
61 #include <machine/leds.h>
62 
63 #include <sun2/sun2/control.h>
64 #include <sun2/sun2/enable.h>
65 #include <sun2/sun2/machdep.h>
66 
67 #include <dev/clock_subr.h>
68 #include <dev/ic/am9513reg.h>
69 
70 /*
71  * Carefully define the basic CPU clock rate so
72  * that time-of-day calculations don't float
73  *
74  * Note that the CLK_BASIC is divided by 4 before we can count with it,
75  * e.g. F1 ticks CLK_BASIC/4 times a second.
76  */
77 #define	SUN2_CLK_BASIC		(19660800)
78 #define SUN2_CLK_TICKS(func, hz) (((SUN2_CLK_BASIC / 4) / AM9513_CM_SOURCE_Fn_DIV(func)) / (hz))
79 
80 /* These define which counters are used for what. */
81 #define	SUN2_CLK_NMI		AM9513_TIMER1	/* Non Maskable Interrupts */
82 #define	SUN2_CLK_TIMER		AM9513_TIMER2	/* Timer 2 */
83 #define	SUN2_CLK_UNUSED		AM9513_TIMER3	/* Unused timer */
84 #define	SUN2_CLK_FAST_LO	AM9513_TIMER4	/* Timer 4 for realtime, low  order */
85 #define	SUN2_CLK_FAST_HI	AM9513_TIMER5	/* Timer 5 for realtime, high order */
86 
87 #define	CLOCK_PRI	5
88 #define IREG_CLK_BITS	(IREG_CLOCK_ENAB_7 | IREG_CLOCK_ENAB_5)
89 
90 void _isr_clock __P((void));	/* in locore.s */
91 void clock_intr __P((struct clockframe));
92 
93 static bus_space_tag_t am9513_bt;
94 static bus_space_handle_t am9513_bh;
95 #define am9513_write_clk_cmd(val) bus_space_write_2(am9513_bt, am9513_bh, AM9513_CLK_CMD, val)
96 #define am9513_write_clk_data(val) bus_space_write_2(am9513_bt, am9513_bh, AM9513_CLK_DATA, val)
97 
98 static int  clock_match __P((struct device *, struct cfdata *, void *args));
99 static void clock_attach __P((struct device *, struct device *, void *));
100 
101 CFATTACH_DECL(clock, sizeof(struct device),
102     clock_match, clock_attach, NULL, NULL);
103 
104 static int
105 clock_match(parent, cf, args)
106     struct device *parent;
107 	struct cfdata *cf;
108     void *args;
109 {
110 	struct obio_attach_args *oba = args;
111 	bus_space_handle_t bh;
112 	int matched;
113 
114 	/* This driver only supports one unit. */
115 	if (cf->cf_unit != 0)
116 		return (0);
117 
118 	/* Make sure there is something there... */
119 	if (bus_space_map(oba->oba_bustag, oba->oba_paddr, sizeof(struct am9513),
120 			  0, &bh))
121 		return (0);
122 	matched = (bus_space_peek_2(oba->oba_bustag, bh, 0, NULL) == 0);
123 	bus_space_unmap(oba->oba_bustag, bh, sizeof(struct am9513));
124 	if (!matched)
125 		return (0);
126 
127 	/* Default interrupt priority. */
128 	if (oba->oba_pri == -1)
129 		oba->oba_pri = CLOCK_PRI;
130 
131 	return (1);
132 }
133 
134 static void
135 clock_attach(parent, self, args)
136 	struct device *parent;
137 	struct device *self;
138 	void *args;
139 {
140 	struct obio_attach_args *oba = args;
141 	bus_space_handle_t bh;
142 
143 	printf("\n");
144 
145 	/* Get a mapping for it. */
146 	if (bus_space_map(oba->oba_bustag, oba->oba_paddr, sizeof(struct am9513), 0, &bh))
147 		panic("clock_attach");
148 	am9513_bt = oba->oba_bustag;
149 	am9513_bh = bh;
150 
151 	/*
152 	 * Set the clock to the correct interrupt rate, but
153 	 * do not enable the interrupt until cpu_initclocks.
154 	 */
155 
156 	/* Disarm the timer and NMI. */
157 	am9513_write_clk_cmd(AM9513_CMD_DISARM(SUN2_CLK_TIMER | SUN2_CLK_NMI));
158 	am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_TIMER));
159 	am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_NMI));
160 
161 	/* Set the clock to 100 Hz, but do not enable it yet. */
162 	am9513_write_clk_cmd(AM9513_CMD_LOAD_MODE(SUN2_CLK_TIMER));
163 	am9513_write_clk_data((AM9513_CM_MODE_D
164 			       | AM9513_CM_SOURCE_F2
165 			       | AM9513_CM_OUTPUT_TC_TOGGLED));
166 	am9513_write_clk_cmd(AM9513_CMD_LOAD_LOAD(SUN2_CLK_TIMER));
167 	am9513_write_clk_data(SUN2_CLK_TICKS(AM9513_CM_SOURCE_F2, 100));
168 
169 	/*
170 	 * Can not hook up the ISR until cpu_initclocks()
171 	 * because hardclock is not ready until then.
172 	 * For now, the handler is _isr_autovec(), which
173 	 * will complain if it gets clock interrupts.
174 	 */
175 }
176 
177 /*
178  * Set or clear the desired clock bits in the interrupt
179  * register.  We have to be extremely careful that we do it
180  * in such a manner that we don't get ourselves lost.
181  * XXX:  Watch out!  It's really easy to break this!
182  */
183 void
184 set_clk_mode(prom_clock, on)
185 	int prom_clock;
186 	int on;
187 {
188 	int timer;
189 
190 #ifdef	DIAGNOSTIC
191 	/* Assertion: were are at splhigh! */
192 	if ((getsr() & PSL_IPL) < PSL_IPL7)
193 		panic("set_clk_mode: bad ipl");
194 #endif
195 
196 	/* Get the timer we're talking about. */
197 	timer = (prom_clock ? SUN2_CLK_NMI : SUN2_CLK_TIMER);
198 
199 	/* First, turn off the "master" enable bit. */
200 	enable_reg_and(~ENA_INTS);
201 
202 	/*
203 	 * Arm the timer we're supposed to turn on.
204 	 */
205 	if (on) {
206 		am9513_write_clk_cmd(AM9513_CMD_ARM(timer));
207 	}
208 
209 	/*
210 	 * Disarm and clear the timers we're supposed to turn off.
211 	 */
212 	else {
213 		am9513_write_clk_cmd(AM9513_CMD_DISARM(timer));
214 		am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(timer));
215 	}
216 
217 	/* Finally, turn the "master" enable back on. */
218 	enable_reg_or(ENA_INTS);
219 }
220 
221 /*
222  * Set up the real-time clock (enable clock interrupts).
223  * Leave stathz 0 since there is no secondary clock available.
224  * Note that clock interrupts MUST STAY DISABLED until here.
225  */
226 void
227 cpu_initclocks(void)
228 {
229 	int s;
230 
231 	s = splhigh();
232 
233 	/* Install isr (in locore.s) that calls clock_intr(). */
234 	isr_add_custom(5, (void*)_isr_clock);
235 
236 	/* Now enable the clock at level 5 in the interrupt reg. */
237 	set_clk_mode(0, 1);
238 
239 	splx(s);
240 }
241 
242 /*
243  * This doesn't need to do anything, as we have only one timer and
244  * profhz==stathz==hz.
245  */
246 void
247 setstatclockrate(newhz)
248 	int newhz;
249 {
250 	/* nothing */
251 }
252 
253 /*
254  * This is is called by the "custom" interrupt handler.
255  * Note that we can get ZS interrupts while this runs,
256  * and zshard may touch the interrupt_reg, so we must
257  * be careful to use the single_inst_* macros to modify
258  * the interrupt register atomically.
259  */
260 void
261 clock_intr(cf)
262 	struct clockframe cf;
263 {
264 
265 	/* Read the clock interrupt register. */
266 	am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_TIMER));
267 
268 	{ /* Entertainment! */
269 #ifdef	LED_IDLE_CHECK
270 		/* With this option, LEDs move only when CPU is idle. */
271 		extern char _Idle[];	/* locore.s */
272 		if (cf.cf_pc == (long)_Idle)
273 #endif
274 			leds_intr();
275 	}
276 
277 	/* Call common clock interrupt handler. */
278 	hardclock(&cf);
279 }
280 
281 
282 /*
283  * Return the best possible estimate of the time in the timeval
284  * to which tvp points.  We do this by returning the current time
285  * plus the amount of time since the last clock interrupt.
286  *
287  * Check that this time is no less than any previously-reported time,
288  * which could happen around the time of a clock adjustment.  Just for
289  * fun, we guarantee that the time will be greater than the value
290  * obtained by a previous call.
291  */
292 void
293 microtime(tvp)
294 	register struct timeval *tvp;
295 {
296 	int s = splhigh();
297 	static struct timeval lasttime;
298 
299 	*tvp = time;
300 	tvp->tv_usec++; 	/* XXX */
301 	while (tvp->tv_usec >= 1000000) {
302 		tvp->tv_sec++;
303 		tvp->tv_usec -= 1000000;
304 	}
305 	if (tvp->tv_sec == lasttime.tv_sec &&
306 		tvp->tv_usec <= lasttime.tv_usec &&
307 		(tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000)
308 	{
309 		tvp->tv_sec++;
310 		tvp->tv_usec -= 1000000;
311 	}
312 	lasttime = *tvp;
313 	splx(s);
314 }
315