xref: /netbsd-src/sys/arch/alpha/tc/ioasic.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /* $NetBSD: ioasic.c,v 1.37 2002/10/02 04:06:40 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.37 2002/10/02 04:06:40 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 CFATTACH_DECL(ioasic, sizeof(struct ioasic_softc),
93     ioasicmatch, ioasicattach, NULL, NULL);
94 
95 int	ioasic_intr __P((void *));
96 int	ioasic_intrnull __P((void *));
97 
98 #define	C(x)	((void *)(x))
99 
100 #define	IOASIC_DEV_LANCE	0
101 #define	IOASIC_DEV_SCC0		1
102 #define	IOASIC_DEV_SCC1		2
103 #define	IOASIC_DEV_ISDN		3
104 
105 #define	IOASIC_DEV_BOGUS	-1
106 
107 #define	IOASIC_NCOOKIES		4
108 
109 struct ioasic_dev ioasic_devs[] = {
110 	{ "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE),
111 	  IOASIC_INTR_LANCE, },
112 	{ "z8530   ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0),
113 	  IOASIC_INTR_SCC_0, },
114 	{ "z8530   ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1),
115 	  IOASIC_INTR_SCC_1, },
116 	{ "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS),
117 	  0, },
118 	{ "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN),
119 	  IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD,  },
120 };
121 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]);
122 
123 struct ioasicintr {
124 	int	(*iai_func) __P((void *));
125 	void	*iai_arg;
126 	struct evcnt iai_evcnt;
127 } ioasicintrs[IOASIC_NCOOKIES];
128 
129 tc_addr_t ioasic_base;		/* XXX XXX XXX */
130 
131 /* There can be only one. */
132 int ioasicfound;
133 
134 int
135 ioasicmatch(parent, cfdata, aux)
136 	struct device *parent;
137 	struct cfdata *cfdata;
138 	void *aux;
139 {
140 	struct tc_attach_args *ta = aux;
141 
142 	/* Make sure that we're looking for this type of device. */
143 	if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
144 		return (0);
145 
146 	/* Check that it can actually exist. */
147 	if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
148 		panic("ioasicmatch: how did we get here?");
149 
150 	if (ioasicfound)
151 		return (0);
152 
153 	return (1);
154 }
155 
156 void
157 ioasicattach(parent, self, aux)
158 	struct device *parent, *self;
159 	void *aux;
160 {
161 	struct ioasic_softc *sc = (struct ioasic_softc *)self;
162 	struct tc_attach_args *ta = aux;
163 #ifdef DEC_3000_300
164 	u_long ssr;
165 #endif
166 	u_long i, imsk;
167 	const struct evcnt *pevcnt;
168 	char *cp;
169 
170 	ioasicfound = 1;
171 
172 	sc->sc_bst = ta->ta_memt;
173 	if (bus_space_map(ta->ta_memt, ta->ta_addr,
174 			0x400000, 0, &sc->sc_bsh)) {
175 		printf("%s: unable to map device\n", sc->sc_dv.dv_xname);
176 		return;
177 	}
178 	sc->sc_dmat = ta->ta_dmat;
179 
180 	ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
181 
182 #ifdef DEC_3000_300
183 	if (cputype == ST_DEC_3000_300) {
184 		ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
185 		ssr |= IOASIC_CSR_FASTMODE;
186 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
187 		printf(": slow mode\n");
188 	} else
189 #endif
190 		printf(": fast mode\n");
191 
192 	/*
193 	 * Turn off all device interrupt bits.
194 	 * (This does _not_ include 3000/300 TC option slot bits.
195 	 */
196 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
197 	for (i = 0; i < ioasic_ndevs; i++)
198 		imsk &= ~ioasic_devs[i].iad_intrbits;
199 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
200 
201 	/*
202 	 * Set up interrupt handlers.
203 	 */
204 	pevcnt = tc_intr_evcnt(parent, ta->ta_cookie);
205 	for (i = 0; i < IOASIC_NCOOKIES; i++) {
206 		ioasicintrs[i].iai_func = ioasic_intrnull;
207 		ioasicintrs[i].iai_arg = (void *)i;
208 
209 		cp = malloc(12, M_DEVBUF, M_NOWAIT);
210 		if (cp == NULL)
211 			panic("ioasicattach");
212 		sprintf(cp, "slot %lu", i);
213 		evcnt_attach_dynamic(&ioasicintrs[i].iai_evcnt,
214 		    EVCNT_TYPE_INTR, pevcnt, self->dv_xname, cp);
215 	}
216 	tc_intr_establish(parent, ta->ta_cookie, TC_IPL_NONE, ioasic_intr, sc);
217 
218 	/*
219 	 * Try to configure each device.
220 	 */
221 	ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs);
222 }
223 
224 void
225 ioasic_intr_establish(ioa, cookie, level, func, arg)
226 	struct device *ioa;
227 	void *cookie, *arg;
228 	tc_intrlevel_t level;
229 	int (*func) __P((void *));
230 {
231 	struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
232 	u_long dev, i, imsk;
233 
234 	dev = (u_long)cookie;
235 #ifdef DIAGNOSTIC
236 	/* XXX check cookie. */
237 #endif
238 
239 	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
240 		panic("ioasic_intr_establish: cookie %lu twice", dev);
241 
242 	ioasicintrs[dev].iai_func = func;
243 	ioasicintrs[dev].iai_arg = arg;
244 
245 	/* Enable interrupts for the device. */
246 	for (i = 0; i < ioasic_ndevs; i++)
247 		if (ioasic_devs[i].iad_cookie == cookie)
248 			break;
249 	if (i == ioasic_ndevs)
250 		panic("ioasic_intr_establish: invalid cookie.");
251 
252 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
253         imsk |= ioasic_devs[i].iad_intrbits;
254         bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
255 }
256 
257 void
258 ioasic_intr_disestablish(ioa, cookie)
259 	struct device *ioa;
260 	void *cookie;
261 {
262 	struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
263 	u_long dev, i, imsk;
264 
265 	dev = (u_long)cookie;
266 #ifdef DIAGNOSTIC
267 	/* XXX check cookie. */
268 #endif
269 
270 	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
271 		panic("ioasic_intr_disestablish: cookie %lu missing intr", dev);
272 
273 	/* Enable interrupts for the device. */
274 	for (i = 0; i < ioasic_ndevs; i++)
275 		if (ioasic_devs[i].iad_cookie == cookie)
276 			break;
277 	if (i == ioasic_ndevs)
278 		panic("ioasic_intr_disestablish: invalid cookie.");
279 
280 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
281 	imsk &= ~ioasic_devs[i].iad_intrbits;
282 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
283 
284 	ioasicintrs[dev].iai_func = ioasic_intrnull;
285 	ioasicintrs[dev].iai_arg = (void *)dev;
286 }
287 
288 int
289 ioasic_intrnull(val)
290 	void *val;
291 {
292 
293 	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
294 	    (u_long)val);
295 }
296 
297 /*
298  * ASIC interrupt handler.
299  */
300 int
301 ioasic_intr(val)
302 	void *val;
303 {
304 	register struct ioasic_softc *sc = val;
305 	register int ifound;
306 	int gifound;
307 	u_int32_t sir, osir;
308 
309 	gifound = 0;
310 	do {
311 		ifound = 0;
312 		tc_syncbus();
313 
314 		osir = sir =
315 		    bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
316 
317 #define	INCRINTRCNT(slot)	ioasicintrs[slot].iai_evcnt.ev_count++
318 
319 		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
320 #define	CHECKINTR(slot, bits, clear)					\
321 		if (sir & (bits)) {					\
322 			ifound = 1;					\
323 			INCRINTRCNT(slot);				\
324 			(*ioasicintrs[slot].iai_func)			\
325 			    (ioasicintrs[slot].iai_arg);		\
326 			if (clear)					\
327 				sir &= ~(bits);				\
328 		}
329 		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0);
330 		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0);
331 		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0);
332 		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD |
333 		    IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1);
334 
335 		if (sir != osir)
336 			bus_space_write_4(sc->sc_bst, sc->sc_bsh,
337 			    IOASIC_INTR, sir);
338 
339 		gifound |= ifound;
340 	} while (ifound);
341 
342 	return (gifound);
343 }
344