Home | History | Annotate | Line # | Download | only in tc
      1 /* $NetBSD: ioasic.c,v 1.49 2021/05/07 16:58:34 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center.
     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  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
     35  * All rights reserved.
     36  *
     37  * Author: Keith Bostic, Chris G. Demetriou
     38  *
     39  * Permission to use, copy, modify and distribute this software and
     40  * its documentation is hereby granted, provided that both the copyright
     41  * notice and this permission notice appear in all copies of the
     42  * software, derivative works or modified versions, and any portions
     43  * thereof, and that both notices appear in supporting documentation.
     44  *
     45  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     46  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     47  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     48  *
     49  * Carnegie Mellon requests users of this software to return to
     50  *
     51  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     52  *  School of Computer Science
     53  *  Carnegie Mellon University
     54  *  Pittsburgh PA 15213-3890
     55  *
     56  * any improvements or extensions that they make and grant Carnegie the
     57  * rights to redistribute these changes.
     58  */
     59 
     60 #include "opt_dec_3000_300.h"
     61 
     62 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     63 
     64 __KERNEL_RCSID(0, "$NetBSD: ioasic.c,v 1.49 2021/05/07 16:58:34 thorpej Exp $");
     65 
     66 #include <sys/param.h>
     67 #include <sys/kernel.h>
     68 #include <sys/systm.h>
     69 #include <sys/device.h>
     70 #include <sys/kmem.h>
     71 
     72 #include <machine/autoconf.h>
     73 #include <sys/bus.h>
     74 #include <machine/pte.h>
     75 #include <machine/rpb.h>
     76 
     77 #include <dev/tc/tcvar.h>
     78 #include <dev/tc/ioasicreg.h>
     79 #include <dev/tc/ioasicvar.h>
     80 
     81 /* Definition of the driver for autoconfig. */
     82 static int	ioasicmatch(device_t, cfdata_t, void *);
     83 static void	ioasicattach(device_t, device_t, void *);
     84 
     85 CFATTACH_DECL_NEW(ioasic, sizeof(struct ioasic_softc),
     86     ioasicmatch, ioasicattach, NULL, NULL);
     87 
     88 static int	ioasic_intr(void *);
     89 static int	ioasic_intrnull(void *);
     90 
     91 #define	C(x)	((void *)(x))
     92 
     93 #define	IOASIC_DEV_LANCE	0
     94 #define	IOASIC_DEV_SCC0		1
     95 #define	IOASIC_DEV_SCC1		2
     96 #define	IOASIC_DEV_ISDN		3
     97 
     98 #define	IOASIC_DEV_BOGUS	-1
     99 
    100 #define	IOASIC_NCOOKIES		4
    101 
    102 static const struct ioasic_dev ioasic_devs[] = {
    103 	{ "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE),
    104 	  IOASIC_INTR_LANCE, },
    105 	{ "z8530   ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0),
    106 	  IOASIC_INTR_SCC_0, },
    107 	{ "z8530   ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1),
    108 	  IOASIC_INTR_SCC_1, },
    109 	{ "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS),
    110 	  0, },
    111 	{ "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN),
    112 	  IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD,  },
    113 };
    114 static const int ioasic_ndevs = __arraycount(ioasic_devs);
    115 
    116 static struct ioasicintr {
    117 	int	(*iai_func)(void *);
    118 	void	*iai_arg;
    119 	struct evcnt iai_evcnt;
    120 } ioasicintrs[IOASIC_NCOOKIES];
    121 
    122 tc_addr_t ioasic_base;		/* XXX XXX XXX */
    123 
    124 /* There can be only one. */
    125 static int ioasicfound;
    126 
    127 static int
    128 ioasicmatch(device_t parent, cfdata_t cf, void *aux)
    129 {
    130 	struct tc_attach_args *ta = aux;
    131 
    132 	/* Make sure that we're looking for this type of device. */
    133 	if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
    134 		return (0);
    135 
    136 	/* Check that it can actually exist. */
    137 	if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
    138 		panic("ioasicmatch: how did we get here?");
    139 
    140 	if (ioasicfound)
    141 		return (0);
    142 
    143 	return (1);
    144 }
    145 
    146 static void
    147 ioasicattach(device_t parent, device_t self, void *aux)
    148 {
    149 	struct ioasic_softc *sc = device_private(self);
    150 	struct tc_attach_args *ta = aux;
    151 #ifdef DEC_3000_300
    152 	u_long ssr;
    153 #endif
    154 	u_long i, imsk;
    155 	const struct evcnt *pevcnt;
    156 	char *cp;
    157 
    158 	ioasicfound = 1;
    159 
    160 	sc->sc_dev = self;
    161 	sc->sc_bst = ta->ta_memt;
    162 	if (bus_space_map(ta->ta_memt, ta->ta_addr,
    163 			0x400000, 0, &sc->sc_bsh)) {
    164 		printf("%s: unable to map device\n", device_xname(self));
    165 		return;
    166 	}
    167 	sc->sc_dmat = ta->ta_dmat;
    168 
    169 	ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
    170 
    171 #ifdef DEC_3000_300
    172 	if (cputype == ST_DEC_3000_300) {
    173 		ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
    174 		ssr |= IOASIC_CSR_FASTMODE;
    175 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
    176 		printf(": slow mode\n");
    177 	} else
    178 #endif
    179 		printf(": fast mode\n");
    180 
    181 	/*
    182 	 * Turn off all device interrupt bits.
    183 	 * (This does _not_ include 3000/300 TC option slot bits.
    184 	 */
    185 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    186 	for (i = 0; i < ioasic_ndevs; i++)
    187 		imsk &= ~ioasic_devs[i].iad_intrbits;
    188 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    189 
    190 	/*
    191 	 * Set up interrupt handlers.
    192 	 */
    193 	pevcnt = tc_intr_evcnt(parent, ta->ta_cookie);
    194 	for (i = 0; i < IOASIC_NCOOKIES; i++) {
    195 		ioasicintrs[i].iai_func = ioasic_intrnull;
    196 		ioasicintrs[i].iai_arg = (void *)i;
    197 
    198 		cp = kmem_asprintf("slot %lu", i);
    199 		evcnt_attach_dynamic(&ioasicintrs[i].iai_evcnt,
    200 		    EVCNT_TYPE_INTR, pevcnt, device_xname(self), cp);
    201 	}
    202 	tc_intr_establish(parent, ta->ta_cookie, TC_IPL_NONE, ioasic_intr, sc);
    203 
    204 	/*
    205 	 * Try to configure each device.
    206 	 */
    207 	ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs);
    208 }
    209 
    210 void
    211 ioasic_intr_establish(device_t ioa, void *cookie, tc_intrlevel_t level,
    212 		int (*func)(void *), void *arg)
    213 {
    214 	struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0);
    215 	u_long dev, i, imsk;
    216 
    217 	dev = (u_long)cookie;
    218 #ifdef DIAGNOSTIC
    219 	/* XXX check cookie. */
    220 #endif
    221 
    222 	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
    223 		panic("ioasic_intr_establish: cookie %lu twice", dev);
    224 
    225 	ioasicintrs[dev].iai_func = func;
    226 	ioasicintrs[dev].iai_arg = arg;
    227 
    228 	/* Enable interrupts for the device. */
    229 	for (i = 0; i < ioasic_ndevs; i++)
    230 		if (ioasic_devs[i].iad_cookie == cookie)
    231 			break;
    232 	if (i == ioasic_ndevs)
    233 		panic("ioasic_intr_establish: invalid cookie.");
    234 
    235 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    236 	imsk |= ioasic_devs[i].iad_intrbits;
    237 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    238 }
    239 
    240 void
    241 ioasic_intr_disestablish(device_t ioa, void *cookie)
    242 {
    243 	struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0);
    244 	u_long dev, i, imsk;
    245 
    246 	dev = (u_long)cookie;
    247 #ifdef DIAGNOSTIC
    248 	/* XXX check cookie. */
    249 #endif
    250 
    251 	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
    252 		panic("ioasic_intr_disestablish: cookie %lu missing intr", dev);
    253 
    254 	/* Enable interrupts for the device. */
    255 	for (i = 0; i < ioasic_ndevs; i++)
    256 		if (ioasic_devs[i].iad_cookie == cookie)
    257 			break;
    258 	if (i == ioasic_ndevs)
    259 		panic("ioasic_intr_disestablish: invalid cookie.");
    260 
    261 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    262 	imsk &= ~ioasic_devs[i].iad_intrbits;
    263 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    264 
    265 	ioasicintrs[dev].iai_func = ioasic_intrnull;
    266 	ioasicintrs[dev].iai_arg = (void *)dev;
    267 }
    268 
    269 static int
    270 ioasic_intrnull(void *val)
    271 {
    272 
    273 	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
    274 	    (u_long)val);
    275 }
    276 
    277 /*
    278  * ASIC interrupt handler.
    279  */
    280 static int
    281 ioasic_intr(void *val)
    282 {
    283 	register struct ioasic_softc *sc = val;
    284 	register int ifound;
    285 	int gifound;
    286 	uint32_t sir, osir;
    287 
    288 	gifound = 0;
    289 	do {
    290 		ifound = 0;
    291 		tc_syncbus();
    292 
    293 		osir = sir =
    294 		    bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
    295 
    296 #define	INCRINTRCNT(slot)	ioasicintrs[slot].iai_evcnt.ev_count++
    297 
    298 		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
    299 #define	CHECKINTR(slot, bits, clear)					\
    300 		if (sir & (bits)) {					\
    301 			ifound = 1;					\
    302 			INCRINTRCNT(slot);				\
    303 			(*ioasicintrs[slot].iai_func)			\
    304 			    (ioasicintrs[slot].iai_arg);		\
    305 			if (clear)					\
    306 				sir &= ~(bits);				\
    307 		}
    308 		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0);
    309 		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0);
    310 		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0);
    311 		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD |
    312 		    IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1);
    313 
    314 		if (sir != osir)
    315 			bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    316 			    IOASIC_INTR, sir);
    317 
    318 		gifound |= ifound;
    319 	} while (ifound);
    320 
    321 	return (gifound);
    322 }
    323