xref: /openbsd-src/sys/arch/alpha/tc/ioasic.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: ioasic.c,v 1.7 1999/01/11 05:11:04 millert Exp $	*/
2 /*	$NetBSD: ioasic.c,v 1.10 1996/12/05 01:39:41 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
6  * All rights reserved.
7  *
8  * Author: Keith Bostic, Chris G. Demetriou
9  *
10  * Permission to use, copy, modify and distribute this software and
11  * its documentation is hereby granted, provided that both the copyright
12  * notice and this permission notice appear in all copies of the
13  * software, derivative works or modified versions, and any portions
14  * thereof, and that both notices appear in supporting documentation.
15  *
16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19  *
20  * Carnegie Mellon requests users of this software to return to
21  *
22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23  *  School of Computer Science
24  *  Carnegie Mellon University
25  *  Pittsburgh PA 15213-3890
26  *
27  * any improvements or extensions that they make and grant Carnegie the
28  * rights to redistribute these changes.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 
36 #include <machine/autoconf.h>
37 #include <machine/pte.h>
38 #include <machine/rpb.h>
39 #ifndef EVCNT_COUNTERS
40 #include <machine/intrcnt.h>
41 #endif
42 
43 #include <dev/tc/tcvar.h>
44 #include <alpha/tc/ioasicreg.h>
45 #include <dev/tc/ioasicvar.h>
46 
47 struct ioasic_softc {
48 	struct	device sc_dv;
49 
50 	tc_addr_t sc_base;
51 	void	*sc_cookie;
52 };
53 
54 /* Definition of the driver for autoconfig. */
55 #ifdef __BROKEN_INDIRECT_CONFIG
56 int	ioasicmatch __P((struct device *, void *, void *));
57 #else
58 int	ioasicmatch __P((struct device *, struct cfdata *, void *));
59 #endif
60 void	ioasicattach __P((struct device *, struct device *, void *));
61 int     ioasicprint(void *, const char *);
62 
63 struct cfattach ioasic_ca = {
64 	sizeof(struct ioasic_softc), ioasicmatch, ioasicattach,
65 };
66 
67 struct cfdriver ioasic_cd = {
68 	NULL, "ioasic", DV_DULL,
69 };
70 
71 int	ioasic_intr __P((void *));
72 int	ioasic_intrnull __P((void *));
73 
74 #define	C(x)	((void *)(x))
75 
76 #define	IOASIC_DEV_LANCE	0
77 #define	IOASIC_DEV_SCC0		1
78 #define	IOASIC_DEV_SCC1		2
79 #define	IOASIC_DEV_ISDN		3
80 
81 #define	IOASIC_DEV_BOGUS	-1
82 
83 #define	IOASIC_NCOOKIES		4
84 
85 struct ioasic_dev {
86 	char		*iad_modname;
87 	tc_offset_t	iad_offset;
88 	void		*iad_cookie;
89 	u_int32_t	iad_intrbits;
90 } ioasic_devs[] = {
91 	/* XXX lance name */
92 	{ "lance",    0x000c0000, C(IOASIC_DEV_LANCE), IOASIC_INTR_LANCE, },
93 	{ "z8530   ", 0x00100000, C(IOASIC_DEV_SCC0),  IOASIC_INTR_SCC_0, },
94 	{ "z8530   ", 0x00180000, C(IOASIC_DEV_SCC1),  IOASIC_INTR_SCC_1, },
95 	{ "TOY_RTC ", 0x00200000, C(IOASIC_DEV_BOGUS), 0,                 },
96 	{ "AMD79c30", 0x00240000, C(IOASIC_DEV_ISDN),  IOASIC_INTR_ISDN,  },
97 };
98 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]);
99 
100 struct ioasicintr {
101 	int	(*iai_func) __P((void *));
102 	void	*iai_arg;
103 } ioasicintrs[IOASIC_NCOOKIES];
104 
105 tc_addr_t ioasic_base;		/* XXX XXX XXX */
106 
107 /* There can be only one. */
108 int ioasicfound;
109 
110 extern int cputype;
111 
112 int
113 ioasicmatch(parent, cfdata, aux)
114 	struct device *parent;
115 #ifdef __BROKEN_INDIRECT_CONFIG
116 	void *cfdata;
117 #else
118 	struct cfdata *cfdata;
119 #endif
120 	void *aux;
121 {
122 	struct tc_attach_args *ta = aux;
123 
124 	/* Make sure that we're looking for this type of device. */
125 	if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
126 		return (0);
127 
128 	/* Check that it can actually exist. */
129 	if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
130 		panic("ioasicmatch: how did we get here?");
131 
132 	if (ioasicfound)
133 		return (0);
134 
135 	return (1);
136 }
137 
138 void
139 ioasicattach(parent, self, aux)
140 	struct device *parent, *self;
141 	void *aux;
142 {
143 	struct ioasic_softc *sc = (struct ioasic_softc *)self;
144 	struct tc_attach_args *ta = aux;
145 	struct ioasicdev_attach_args ioasicdev;
146 	u_long i;
147 
148 	ioasicfound = 1;
149 
150 	sc->sc_base = ta->ta_addr;
151 	ioasic_base = sc->sc_base;			/* XXX XXX XXX */
152 	sc->sc_cookie = ta->ta_cookie;
153 
154 #ifdef DEC_3000_300
155 	if (cputype == ST_DEC_3000_300) {
156 		*(volatile u_int *)IOASIC_REG_CSR(sc->sc_base) |=
157 		    IOASIC_CSR_FASTMODE;
158 		tc_mb();
159 		printf(": slow mode\n");
160 	} else
161 #endif
162 		printf(": fast mode\n");
163 
164 	/*
165 	 * Turn off all device interrupt bits.
166 	 * (This does _not_ include 3000/300 TC option slot bits.
167 	 */
168 	for (i = 0; i < ioasic_ndevs; i++)
169 		*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
170 			~ioasic_devs[i].iad_intrbits;
171 	tc_mb();
172 
173 	/*
174 	 * Set up interrupt handlers.
175 	 */
176 	for (i = 0; i < IOASIC_NCOOKIES; i++) {
177 		ioasicintrs[i].iai_func = ioasic_intrnull;
178 		ioasicintrs[i].iai_arg = (void *)i;
179 	}
180 	tc_intr_establish(parent, sc->sc_cookie, TC_IPL_NONE, ioasic_intr, sc);
181 
182         /*
183 	 * Try to configure each device.
184 	 */
185         for (i = 0; i < ioasic_ndevs; i++) {
186 		strncpy(ioasicdev.iada_modname, ioasic_devs[i].iad_modname,
187 			TC_ROM_LLEN);
188 		ioasicdev.iada_modname[TC_ROM_LLEN] = '\0';
189 		ioasicdev.iada_offset = ioasic_devs[i].iad_offset;
190 		ioasicdev.iada_addr = sc->sc_base + ioasic_devs[i].iad_offset;
191 		ioasicdev.iada_cookie = ioasic_devs[i].iad_cookie;
192 
193                 /* Tell the autoconfig machinery we've found the hardware. */
194                 config_found(self, &ioasicdev, ioasicprint);
195         }
196 }
197 
198 int
199 ioasicprint(aux, pnp)
200 	void *aux;
201 	const char *pnp;
202 {
203 	struct ioasicdev_attach_args *d = aux;
204 
205         if (pnp)
206                 printf("%s at %s", d->iada_modname, pnp);
207         printf(" offset 0x%lx", (long)d->iada_offset);
208         return (UNCONF);
209 }
210 
211 int
212 ioasic_submatch(match, d)
213 	struct cfdata *match;
214 	struct ioasicdev_attach_args *d;
215 {
216 
217 	return ((match->ioasiccf_offset == d->iada_offset) ||
218 		(match->ioasiccf_offset == IOASIC_OFFSET_UNKNOWN));
219 }
220 
221 void
222 ioasic_intr_establish(ioa, cookie, level, func, arg)
223 	struct device *ioa;
224 	void *cookie, *arg;
225 	tc_intrlevel_t level;
226 	int (*func) __P((void *));
227 {
228 	u_long dev, i;
229 
230 	dev = (u_long)cookie;
231 #ifdef DIAGNOSTIC
232 	/* XXX check cookie. */
233 #endif
234 
235 	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
236 		panic("ioasic_intr_establish: cookie %d twice", dev);
237 
238 	ioasicintrs[dev].iai_func = func;
239 	ioasicintrs[dev].iai_arg = arg;
240 
241 	/* Enable interrupts for the device. */
242 	for (i = 0; i < ioasic_ndevs; i++)
243 		if (ioasic_devs[i].iad_cookie == cookie)
244 			break;
245 	if (i == ioasic_ndevs)
246 		panic("ioasic_intr_establish: invalid cookie.");
247 	*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |=
248 		ioasic_devs[i].iad_intrbits;
249 	tc_mb();
250 }
251 
252 void
253 ioasic_intr_disestablish(ioa, cookie)
254 	struct device *ioa;
255 	void *cookie;
256 {
257 	u_long dev, i;
258 
259 	dev = (u_long)cookie;
260 #ifdef DIAGNOSTIC
261 	/* XXX check cookie. */
262 #endif
263 
264 	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
265 		panic("ioasic_intr_disestablish: cookie %d missing intr", dev);
266 
267 	/* Enable interrupts for the device. */
268 	for (i = 0; i < ioasic_ndevs; i++)
269 		if (ioasic_devs[i].iad_cookie == cookie)
270 			break;
271 	if (i == ioasic_ndevs)
272 		panic("ioasic_intr_disestablish: invalid cookie.");
273 	*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
274 		~ioasic_devs[i].iad_intrbits;
275 	tc_mb();
276 
277 	ioasicintrs[dev].iai_func = ioasic_intrnull;
278 	ioasicintrs[dev].iai_arg = (void *)dev;
279 }
280 
281 int
282 ioasic_intrnull(val)
283 	void *val;
284 {
285 
286 	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
287 	    (u_long)val);
288 }
289 
290 /*
291  * asic_intr --
292  *	ASIC interrupt handler.
293  */
294 int
295 ioasic_intr(val)
296 	void *val;
297 {
298 	register struct ioasic_softc *sc = val;
299 	register int ifound;
300 	int gifound;
301 	u_int32_t sir;
302 	volatile u_int32_t *sirp;
303 
304 	sirp = (volatile u_int32_t *)IOASIC_REG_INTR(sc->sc_base);
305 
306 	gifound = 0;
307 	do {
308 		ifound = 0;
309 		tc_syncbus();
310 
311 		sir = *sirp;
312 
313 #ifdef EVCNT_COUNTERS
314 	/* No interrupt counting via evcnt counters */
315 	XXX BREAK HERE XXX
316 #else /* !EVCNT_COUNTERS */
317 #define	INCRINTRCNT(slot)	intrcnt[INTRCNT_IOASIC + slot]++
318 #endif /* EVCNT_COUNTERS */
319 
320 		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
321 #define	CHECKINTR(slot, bits)						\
322 		if (sir & bits) {					\
323 			ifound = 1;					\
324 			INCRINTRCNT(slot);				\
325 			(*ioasicintrs[slot].iai_func)			\
326 			    (ioasicintrs[slot].iai_arg);		\
327 		}
328 		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0);
329 		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1);
330 		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE);
331 		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN);
332 
333 		gifound |= ifound;
334 	} while (ifound);
335 
336 	return (gifound);
337 }
338 
339 /* XXX */
340 char *
341 ioasic_lance_ether_address()
342 {
343 
344 	return (u_char *)IOASIC_SYS_ETHER_ADDRESS(ioasic_base);
345 }
346 
347 void
348 ioasic_lance_dma_setup(v)
349 	void *v;
350 {
351 	volatile u_int32_t *ldp;
352 	tc_addr_t tca;
353 
354 	tca = (tc_addr_t)v;
355 
356 	ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
357 	*ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
358 	tc_wmb();
359 
360 	*(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
361 	    IOASIC_CSR_DMAEN_LANCE;
362 	tc_mb();
363 }
364