xref: /netbsd/sys/arch/sun2/sun2/clock.c (revision bf9ec67e)
1 /*	$NetBSD: clock.c,v 1.2 2001/06/27 02:59:26 fredette 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 struct cfattach clock_ca = {
102 	sizeof(struct device), clock_match, clock_attach
103 };
104 
105 static int
106 clock_match(parent, cf, args)
107     struct device *parent;
108 	struct cfdata *cf;
109     void *args;
110 {
111 	struct obio_attach_args *oba = args;
112 	bus_space_handle_t bh;
113 	int matched;
114 
115 	/* This driver only supports one unit. */
116 	if (cf->cf_unit != 0)
117 		return (0);
118 
119 	/* Make sure there is something there... */
120 	if (bus_space_map(oba->oba_bustag, oba->oba_paddr, sizeof(struct am9513),
121 			  0, &bh))
122 		return (0);
123 	matched = (bus_space_peek_2(oba->oba_bustag, bh, 0, NULL) == 0);
124 	bus_space_unmap(oba->oba_bustag, bh, sizeof(struct am9513));
125 	if (!matched)
126 		return (0);
127 
128 	/* Default interrupt priority. */
129 	if (oba->oba_pri == -1)
130 		oba->oba_pri = CLOCK_PRI;
131 
132 	return (1);
133 }
134 
135 static void
136 clock_attach(parent, self, args)
137 	struct device *parent;
138 	struct device *self;
139 	void *args;
140 {
141 	struct obio_attach_args *oba = args;
142 	bus_space_handle_t bh;
143 
144 	printf("\n");
145 
146 	/* Get a mapping for it. */
147 	if (bus_space_map(oba->oba_bustag, oba->oba_paddr, sizeof(struct am9513), 0, &bh))
148 		panic("clock_attach");
149 	am9513_bt = oba->oba_bustag;
150 	am9513_bh = bh;
151 
152 	/*
153 	 * Set the clock to the correct interrupt rate, but
154 	 * do not enable the interrupt until cpu_initclocks.
155 	 */
156 
157 	/* Disarm the timer and NMI. */
158 	am9513_write_clk_cmd(AM9513_CMD_DISARM(SUN2_CLK_TIMER | SUN2_CLK_NMI));
159 	am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_TIMER));
160 	am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_NMI));
161 
162 	/* Set the clock to 100 Hz, but do not enable it yet. */
163 	am9513_write_clk_cmd(AM9513_CMD_LOAD_MODE(SUN2_CLK_TIMER));
164 	am9513_write_clk_data((AM9513_CM_MODE_D
165 			       | AM9513_CM_SOURCE_F2
166 			       | AM9513_CM_OUTPUT_TC_TOGGLED));
167 	am9513_write_clk_cmd(AM9513_CMD_LOAD_LOAD(SUN2_CLK_TIMER));
168 	am9513_write_clk_data(SUN2_CLK_TICKS(AM9513_CM_SOURCE_F2, 100));
169 
170 	/*
171 	 * Can not hook up the ISR until cpu_initclocks()
172 	 * because hardclock is not ready until then.
173 	 * For now, the handler is _isr_autovec(), which
174 	 * will complain if it gets clock interrupts.
175 	 */
176 }
177 
178 /*
179  * Set or clear the desired clock bits in the interrupt
180  * register.  We have to be extremely careful that we do it
181  * in such a manner that we don't get ourselves lost.
182  * XXX:  Watch out!  It's really easy to break this!
183  */
184 void
185 set_clk_mode(prom_clock, on)
186 	int prom_clock;
187 	int on;
188 {
189 	int timer;
190 
191 #ifdef	DIAGNOSTIC
192 	/* Assertion: were are at splhigh! */
193 	if ((getsr() & PSL_IPL) < PSL_IPL7)
194 		panic("set_clk_mode: bad ipl");
195 #endif
196 
197 	/* Get the timer we're talking about. */
198 	timer = (prom_clock ? SUN2_CLK_NMI : SUN2_CLK_TIMER);
199 
200 	/* First, turn off the "master" enable bit. */
201 	enable_reg_and(~ENA_INTS);
202 
203 	/*
204 	 * Arm the timer we're supposed to turn on.
205 	 */
206 	if (on) {
207 		am9513_write_clk_cmd(AM9513_CMD_ARM(timer));
208 	}
209 
210 	/*
211 	 * Disarm and clear the timers we're supposed to turn off.
212 	 */
213 	else {
214 		am9513_write_clk_cmd(AM9513_CMD_DISARM(timer));
215 		am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(timer));
216 	}
217 
218 	/* Finally, turn the "master" enable back on. */
219 	enable_reg_or(ENA_INTS);
220 }
221 
222 /*
223  * Set up the real-time clock (enable clock interrupts).
224  * Leave stathz 0 since there is no secondary clock available.
225  * Note that clock interrupts MUST STAY DISABLED until here.
226  */
227 void
228 cpu_initclocks(void)
229 {
230 	int s;
231 
232 	s = splhigh();
233 
234 	/* Install isr (in locore.s) that calls clock_intr(). */
235 	isr_add_custom(5, (void*)_isr_clock);
236 
237 	/* Now enable the clock at level 5 in the interrupt reg. */
238 	set_clk_mode(0, 1);
239 
240 	splx(s);
241 }
242 
243 /*
244  * This doesn't need to do anything, as we have only one timer and
245  * profhz==stathz==hz.
246  */
247 void
248 setstatclockrate(newhz)
249 	int newhz;
250 {
251 	/* nothing */
252 }
253 
254 /*
255  * This is is called by the "custom" interrupt handler.
256  * Note that we can get ZS interrupts while this runs,
257  * and zshard may touch the interrupt_reg, so we must
258  * be careful to use the single_inst_* macros to modify
259  * the interrupt register atomically.
260  */
261 void
262 clock_intr(cf)
263 	struct clockframe cf;
264 {
265 
266 	/* Read the clock interrupt register. */
267 	am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_TIMER));
268 
269 	{ /* Entertainment! */
270 #ifdef	LED_IDLE_CHECK
271 		/* With this option, LEDs move only when CPU is idle. */
272 		extern char _Idle[];	/* locore.s */
273 		if (cf.cf_pc == (long)_Idle)
274 #endif
275 			leds_intr();
276 	}
277 
278 	/* Call common clock interrupt handler. */
279 	hardclock(&cf);
280 }
281 
282 
283 /*
284  * Return the best possible estimate of the time in the timeval
285  * to which tvp points.  We do this by returning the current time
286  * plus the amount of time since the last clock interrupt.
287  *
288  * Check that this time is no less than any previously-reported time,
289  * which could happen around the time of a clock adjustment.  Just for
290  * fun, we guarantee that the time will be greater than the value
291  * obtained by a previous call.
292  */
293 void
294 microtime(tvp)
295 	register struct timeval *tvp;
296 {
297 	int s = splhigh();
298 	static struct timeval lasttime;
299 
300 	*tvp = time;
301 	tvp->tv_usec++; 	/* XXX */
302 	while (tvp->tv_usec >= 1000000) {
303 		tvp->tv_sec++;
304 		tvp->tv_usec -= 1000000;
305 	}
306 	if (tvp->tv_sec == lasttime.tv_sec &&
307 		tvp->tv_usec <= lasttime.tv_usec &&
308 		(tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000)
309 	{
310 		tvp->tv_sec++;
311 		tvp->tv_usec -= 1000000;
312 	}
313 	lasttime = *tvp;
314 	splx(s);
315 }
316