ioasic.c revision 1.13 1 /* $NetBSD: ioasic.c,v 1.13 1997/04/07 23:40:54 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995, 1996 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 <machine/options.h> /* Config options headers */
31 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
32
33 __KERNEL_RCSID(0, "$NetBSD: ioasic.c,v 1.13 1997/04/07 23:40:54 cgd Exp $");
34
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39
40 #include <machine/autoconf.h>
41 #include <machine/pte.h>
42 #include <machine/rpb.h>
43 #ifndef EVCNT_COUNTERS
44 #include <machine/intrcnt.h>
45 #endif
46
47 #include <dev/tc/tcvar.h>
48 #include <alpha/tc/ioasicreg.h>
49 #include <dev/tc/ioasicvar.h>
50
51 struct ioasic_softc {
52 struct device sc_dv;
53
54 tc_addr_t sc_base;
55 void *sc_cookie;
56 };
57
58 /* Definition of the driver for autoconfig. */
59 int ioasicmatch __P((struct device *, struct cfdata *, void *));
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 struct cfdata *cfdata;
116 void *aux;
117 {
118 struct tc_attach_args *ta = aux;
119
120 /* Make sure that we're looking for this type of device. */
121 if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
122 return (0);
123
124 /* Check that it can actually exist. */
125 if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
126 panic("ioasicmatch: how did we get here?");
127
128 if (ioasicfound)
129 return (0);
130
131 return (1);
132 }
133
134 void
135 ioasicattach(parent, self, aux)
136 struct device *parent, *self;
137 void *aux;
138 {
139 struct ioasic_softc *sc = (struct ioasic_softc *)self;
140 struct tc_attach_args *ta = aux;
141 struct ioasicdev_attach_args ioasicdev;
142 u_long i;
143
144 ioasicfound = 1;
145
146 sc->sc_base = ta->ta_addr;
147 ioasic_base = sc->sc_base; /* XXX XXX XXX */
148 sc->sc_cookie = ta->ta_cookie;
149
150 #ifdef DEC_3000_300
151 if (cputype == ST_DEC_3000_300) {
152 *(volatile u_int *)IOASIC_REG_CSR(sc->sc_base) |=
153 IOASIC_CSR_FASTMODE;
154 tc_mb();
155 printf(": slow mode\n");
156 } else
157 #endif
158 printf(": fast mode\n");
159
160 /*
161 * Turn off all device interrupt bits.
162 * (This does _not_ include 3000/300 TC option slot bits.
163 */
164 for (i = 0; i < ioasic_ndevs; i++)
165 *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
166 ~ioasic_devs[i].iad_intrbits;
167 tc_mb();
168
169 /*
170 * Set up interrupt handlers.
171 */
172 for (i = 0; i < IOASIC_NCOOKIES; i++) {
173 ioasicintrs[i].iai_func = ioasic_intrnull;
174 ioasicintrs[i].iai_arg = (void *)i;
175 }
176 tc_intr_establish(parent, sc->sc_cookie, TC_IPL_NONE, ioasic_intr, sc);
177
178 /*
179 * Try to configure each device.
180 */
181 for (i = 0; i < ioasic_ndevs; i++) {
182 strncpy(ioasicdev.iada_modname, ioasic_devs[i].iad_modname,
183 TC_ROM_LLEN);
184 ioasicdev.iada_modname[TC_ROM_LLEN] = '\0';
185 ioasicdev.iada_offset = ioasic_devs[i].iad_offset;
186 ioasicdev.iada_addr = sc->sc_base + ioasic_devs[i].iad_offset;
187 ioasicdev.iada_cookie = ioasic_devs[i].iad_cookie;
188
189 /* Tell the autoconfig machinery we've found the hardware. */
190 config_found(self, &ioasicdev, ioasicprint);
191 }
192 }
193
194 int
195 ioasicprint(aux, pnp)
196 void *aux;
197 const char *pnp;
198 {
199 struct ioasicdev_attach_args *d = aux;
200
201 if (pnp)
202 printf("%s at %s", d->iada_modname, pnp);
203 printf(" offset 0x%lx", (long)d->iada_offset);
204 return (UNCONF);
205 }
206
207 int
208 ioasic_submatch(match, d)
209 struct cfdata *match;
210 struct ioasicdev_attach_args *d;
211 {
212
213 return ((match->ioasiccf_offset == d->iada_offset) ||
214 (match->ioasiccf_offset == IOASIC_OFFSET_UNKNOWN));
215 }
216
217 void
218 ioasic_intr_establish(ioa, cookie, level, func, arg)
219 struct device *ioa;
220 void *cookie, *arg;
221 tc_intrlevel_t level;
222 int (*func) __P((void *));
223 {
224 u_long dev, i;
225
226 dev = (u_long)cookie;
227 #ifdef DIAGNOSTIC
228 /* XXX check cookie. */
229 #endif
230
231 if (ioasicintrs[dev].iai_func != ioasic_intrnull)
232 panic("ioasic_intr_establish: cookie %d twice", dev);
233
234 ioasicintrs[dev].iai_func = func;
235 ioasicintrs[dev].iai_arg = arg;
236
237 /* Enable interrupts for the device. */
238 for (i = 0; i < ioasic_ndevs; i++)
239 if (ioasic_devs[i].iad_cookie == cookie)
240 break;
241 if (i == ioasic_ndevs)
242 panic("ioasic_intr_establish: invalid cookie.");
243 *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |=
244 ioasic_devs[i].iad_intrbits;
245 tc_mb();
246 }
247
248 void
249 ioasic_intr_disestablish(ioa, cookie)
250 struct device *ioa;
251 void *cookie;
252 {
253 u_long dev, i;
254
255 dev = (u_long)cookie;
256 #ifdef DIAGNOSTIC
257 /* XXX check cookie. */
258 #endif
259
260 if (ioasicintrs[dev].iai_func == ioasic_intrnull)
261 panic("ioasic_intr_disestablish: cookie %d missing intr", dev);
262
263 /* Enable interrupts for the device. */
264 for (i = 0; i < ioasic_ndevs; i++)
265 if (ioasic_devs[i].iad_cookie == cookie)
266 break;
267 if (i == ioasic_ndevs)
268 panic("ioasic_intr_disestablish: invalid cookie.");
269 *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
270 ~ioasic_devs[i].iad_intrbits;
271 tc_mb();
272
273 ioasicintrs[dev].iai_func = ioasic_intrnull;
274 ioasicintrs[dev].iai_arg = (void *)dev;
275 }
276
277 int
278 ioasic_intrnull(val)
279 void *val;
280 {
281
282 panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld\n",
283 (u_long)val);
284 }
285
286 /*
287 * asic_intr --
288 * ASIC interrupt handler.
289 */
290 int
291 ioasic_intr(val)
292 void *val;
293 {
294 register struct ioasic_softc *sc = val;
295 register int ifound;
296 int gifound;
297 u_int32_t sir;
298 volatile u_int32_t *sirp;
299
300 sirp = (volatile u_int32_t *)IOASIC_REG_INTR(sc->sc_base);
301
302 gifound = 0;
303 do {
304 ifound = 0;
305 tc_syncbus();
306
307 sir = *sirp;
308
309 #ifdef EVCNT_COUNTERS
310 /* No interrupt counting via evcnt counters */
311 XXX BREAK HERE XXX
312 #else /* !EVCNT_COUNTERS */
313 #define INCRINTRCNT(slot) intrcnt[INTRCNT_IOASIC + slot]++
314 #endif /* EVCNT_COUNTERS */
315
316 /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
317 #define CHECKINTR(slot, bits) \
318 if (sir & bits) { \
319 ifound = 1; \
320 INCRINTRCNT(slot); \
321 (*ioasicintrs[slot].iai_func) \
322 (ioasicintrs[slot].iai_arg); \
323 }
324 CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0);
325 CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1);
326 CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE);
327 CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN);
328
329 gifound |= ifound;
330 } while (ifound);
331
332 return (gifound);
333 }
334
335 /* XXX */
336 char *
337 ioasic_lance_ether_address()
338 {
339
340 return (u_char *)IOASIC_SYS_ETHER_ADDRESS(ioasic_base);
341 }
342
343 void
344 ioasic_lance_dma_setup(v)
345 void *v;
346 {
347 volatile u_int32_t *ldp;
348 tc_addr_t tca;
349
350 tca = (tc_addr_t)v;
351
352 ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
353 *ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
354 tc_wmb();
355
356 *(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
357 IOASIC_CSR_DMAEN_LANCE;
358 tc_mb();
359 }
360