Home | History | Annotate | Line # | Download | only in sparc
      1 /*	$NetBSD: oclock.c,v 1.21 2021/01/24 07:36:54 mrg Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Paul Kranenburg.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * sun4 intersil time-of-day clock driver. This chip also provides
     34  * the system timer.
     35  *
     36  * Only 4/100's and 4/200's have this old clock device.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: oclock.c,v 1.21 2021/01/24 07:36:54 mrg Exp $");
     41 
     42 #include "opt_sparc_arch.h"
     43 
     44 #include <sys/param.h>
     45 #include <sys/kernel.h>
     46 #include <sys/device.h>
     47 #include <sys/systm.h>
     48 #include <sys/bus.h>
     49 
     50 #include <machine/promlib.h>
     51 #include <machine/autoconf.h>
     52 
     53 #include <sparc/sparc/timervar.h>
     54 
     55 #include <dev/clock_subr.h>
     56 #include <dev/ic/intersil7170reg.h>
     57 #include <dev/ic/intersil7170var.h>
     58 
     59 static int oclockmatch(device_t, cfdata_t, void *);
     60 static void oclockattach(device_t, device_t, void *);
     61 
     62 CFATTACH_DECL_NEW(oclock, sizeof(struct intersil7170_softc),
     63     oclockmatch, oclockattach, NULL, NULL);
     64 
     65 #if defined(SUN4)
     66 static bus_space_tag_t i7_bt;
     67 static bus_space_handle_t i7_bh;
     68 
     69 #define intersil_disable()						\
     70 	bus_space_write_1(i7_bt, i7_bh, INTERSIL_ICMD,			\
     71 	    INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE));
     72 
     73 #define intersil_enable()						\
     74 	bus_space_write_1(i7_bt, i7_bh, INTERSIL_ICMD,			\
     75 	    INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE));
     76 
     77 #define intersil_clear() bus_space_read_1(i7_bt, i7_bh, INTERSIL_IINTR)
     78 
     79 int oclockintr(void *);
     80 static struct intrhand level10 = { oclockintr };
     81 void oclock_init(void);
     82 #endif /* SUN4 */
     83 
     84 /*
     85  * old clock match routine
     86  */
     87 static int
     88 oclockmatch(device_t parent, cfdata_t cf, void *aux)
     89 {
     90 	union obio_attach_args *uoba = aux;
     91 	struct obio4_attach_args *oba;
     92 
     93 	if (uoba->uoba_isobio4 == 0)
     94 		return (0);
     95 
     96 	/* Only these sun4s have oclock */
     97 	if (!CPU_ISSUN4 ||
     98 	    (cpuinfo.cpu_type != CPUTYP_4_100 &&
     99 	     cpuinfo.cpu_type != CPUTYP_4_200))
    100 		return (0);
    101 
    102 	/* Make sure there is something there */
    103 	oba = &uoba->uoba_oba4;
    104 	return (bus_space_probe(oba->oba_bustag, oba->oba_paddr,
    105 				1,	/* probe size */
    106 				0,	/* offset */
    107 				0,	/* flags */
    108 				NULL, NULL));
    109 }
    110 
    111 /* ARGSUSED */
    112 static void
    113 oclockattach(device_t parent, device_t self, void *aux)
    114 {
    115 #if defined(SUN4)
    116 	struct intersil7170_softc *sc = device_private(self);
    117 	union obio_attach_args *uoba = aux;
    118 	struct obio4_attach_args *oba = &uoba->uoba_oba4;
    119 
    120 	oldclk = 1;  /* we've got an oldie! */
    121 
    122 	sc->sc_dev = self;
    123 	sc->sc_bst = oba->oba_bustag;
    124 	if (bus_space_map(sc->sc_bst,
    125 			  oba->oba_paddr,
    126 			  sizeof(struct intersil7170),
    127 			  BUS_SPACE_MAP_LINEAR,	/* flags */
    128 			  &sc->sc_bsh) != 0) {
    129 		aprint_error(": can't map register\n");
    130 		return;
    131 	}
    132 	i7_bt = sc->sc_bst;
    133 	i7_bh = sc->sc_bsh;
    134 
    135 	/*
    136 	 * calibrate delay()
    137 	 */
    138 	ienab_bic(IE_L14 | IE_L10);	/* disable all clock intrs */
    139 	for (timerblurb = 1; ; timerblurb++) {
    140 		int ival;
    141 
    142 		/* Set to 1/100 second interval */
    143 		bus_space_write_1(sc->sc_bst, sc->sc_bsh, INTERSIL_IINTR,
    144 		    INTERSIL_INTER_CSECONDS);
    145 
    146 		/* enable clock */
    147 		intersil_enable();
    148 
    149 		while ((intersil_clear() & INTERSIL_INTER_PENDING) == 0)
    150 			/* sync with interrupt */;
    151 		while ((intersil_clear() & INTERSIL_INTER_PENDING) == 0)
    152 			/* XXX: do it again, seems to need it */;
    153 
    154 		/* Probe 1/100 sec delay */
    155 		delay(10000);
    156 
    157 		/* clear, save value */
    158 		ival = intersil_clear();
    159 
    160 		/* disable clock */
    161 		intersil_disable();
    162 
    163 		if ((ival & INTERSIL_INTER_PENDING) != 0) {
    164 			aprint_normal(" delay constant %d%s\n", timerblurb,
    165 				(timerblurb == 1) ? " [TOO SMALL?]" : "");
    166 			break;
    167 		}
    168 		if (timerblurb > 10) {
    169 			aprint_normal("\n");
    170 			aprint_error_dev(self, "calibration failing; "
    171 			    "clamped at %d\n", timerblurb);
    172 			break;
    173 		}
    174 	}
    175 
    176 	timer_init = oclock_init;
    177 
    178 	/* link interrupt handler */
    179 	intr_establish(10, 0, &level10, NULL, false);
    180 
    181 	/* Our TOD clock year 0 represents 1968 */
    182 	sc->sc_year0 = 1968;
    183 	intersil7170_attach(sc);
    184 
    185 	aprint_normal("\n");
    186 #endif /* SUN4 */
    187 }
    188 
    189 #if defined(SUN4)
    190 /*
    191  * Set up the real-time and statistics clocks.
    192  * Leave stathz 0 only if no alternative timer is available.
    193  *
    194  * The frequencies of these clocks must be an even number of microseconds.
    195  */
    196 void
    197 oclock_init(void)
    198 {
    199 
    200 	profhz = hz = 100;
    201 	tick = 1000000 / hz;
    202 
    203 	/* Select 1/100 second interval */
    204 	bus_space_write_1(i7_bt, i7_bh, INTERSIL_IINTR,
    205 			  INTERSIL_INTER_CSECONDS);
    206 
    207 	ienab_bic(IE_L14 | IE_L10);	/* disable all clock intrs */
    208 	intersil_disable();		/* disable clock */
    209 	(void)intersil_clear();		/* clear interrupts */
    210 	ienab_bis(IE_L10);		/* enable l10 interrupt */
    211 	intersil_enable();		/* enable clock */
    212 }
    213 
    214 /*
    215  * Level 10 (clock) interrupts from system counter.
    216  * If we are using the FORTH PROM for console input, we need to check
    217  * for that here as well, and generate a software interrupt to read it.
    218  */
    219 int
    220 oclockintr(void *cap)
    221 {
    222 	int s;
    223 
    224 	/*
    225 	 * Protect the clearing of the clock interrupt.  If we don't
    226 	 * do this, and we're interrupted (by the zs, for example),
    227 	 * the clock stops!
    228 	 * XXX WHY DOES THIS HAPPEN?
    229 	 */
    230 	s = splhigh();
    231 
    232 	(void)intersil_clear();
    233 	ienab_bic(IE_L10);  /* clear interrupt */
    234 	ienab_bis(IE_L10);  /* enable interrupt */
    235 	splx(s);
    236 
    237 	hardclock((struct clockframe *)cap);
    238 	return (1);
    239 }
    240 #endif /* SUN4 */
    241