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