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