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