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