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