1 /* $OpenBSD: ioasic.c,v 1.19 2022/03/13 08:04:13 mpi 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 #include <sys/timeout.h>
67
68 #include <machine/autoconf.h>
69 #include <machine/bus.h>
70 #include <machine/pte.h>
71 #include <machine/rpb.h>
72
73 #include <dev/tc/tcvar.h>
74 #include <dev/tc/ioasicreg.h>
75 #include <dev/tc/ioasicvar.h>
76 #ifdef DEC_3000_300
77 #include <alpha/tc/tc_3000_300.h>
78 #endif
79
80 /* Definition of the driver for autoconfig. */
81 int ioasicmatch(struct device *, void *, void *);
82 void ioasicattach(struct device *, struct device *, void *);
83
84 const struct cfattach ioasic_ca = {
85 sizeof(struct ioasic_softc), ioasicmatch, ioasicattach,
86 };
87
88 struct cfdriver ioasic_cd = {
89 NULL, "ioasic", DV_DULL,
90 };
91
92 int ioasic_intr(void *);
93 int ioasic_intrnull(void *);
94 void ioasic_led_blink(void *);
95
96 #define C(x) ((void *)(u_long)(x))
97 #define KV(x) (ALPHA_PHYS_TO_K0SEG(x))
98
99 #define IOASIC_DEV_LANCE 0
100 #define IOASIC_DEV_SCC0 1
101 #define IOASIC_DEV_SCC1 2
102 #define IOASIC_DEV_ISDN 3
103
104 #define IOASIC_DEV_BOGUS -1
105
106 #define IOASIC_NCOOKIES 4
107
108 struct ioasic_dev ioasic_devs[] = {
109 { "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE),
110 IOASIC_INTR_LANCE, },
111 { "z8530 ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0),
112 IOASIC_INTR_SCC_0, },
113 { "z8530 ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1),
114 IOASIC_INTR_SCC_1, },
115 { "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS),
116 0, },
117 { "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN),
118 IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD, },
119 };
120 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]);
121
122 struct ioasicintr {
123 int (*iai_func)(void *);
124 void *iai_arg;
125 struct evcount iai_count;
126 } ioasicintrs[IOASIC_NCOOKIES];
127
128 tc_addr_t ioasic_base; /* XXX XXX XXX */
129
130 /* There can be only one. */
131 int ioasicfound;
132
133 int
ioasicmatch(parent,cfdata,aux)134 ioasicmatch(parent, cfdata, aux)
135 struct device *parent;
136 void *cfdata, *aux;
137 {
138 struct tc_attach_args *ta = aux;
139
140 /* Make sure that we're looking for this type of device. */
141 if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
142 return (0);
143
144 /* Check that it can actually exist. */
145 if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
146 panic("ioasicmatch: how did we get here?");
147
148 if (ioasicfound)
149 return (0);
150
151 return (1);
152 }
153
154 void
ioasicattach(parent,self,aux)155 ioasicattach(parent, self, aux)
156 struct device *parent, *self;
157 void *aux;
158 {
159 struct ioasic_softc *sc = (struct ioasic_softc *)self;
160 struct tc_attach_args *ta = aux;
161 #ifdef DEC_3000_300
162 u_long ssr;
163 #endif
164 u_long i, imsk;
165
166 ioasicfound = 1;
167
168 sc->sc_bst = ta->ta_memt;
169 if (bus_space_map(ta->ta_memt, ta->ta_addr,
170 0x400000, 0, &sc->sc_bsh)) {
171 printf("%s: unable to map device\n", sc->sc_dv.dv_xname);
172 return;
173 }
174 sc->sc_dmat = ta->ta_dmat;
175
176 ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
177
178 #ifdef DEC_3000_300
179 if (cputype == ST_DEC_3000_300) {
180 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
181 ssr |= IOASIC_CSR_FASTMODE;
182 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
183 printf(": slow mode\n");
184 } else
185 #endif
186 printf(": fast mode\n");
187
188 /*
189 * Turn off all device interrupt bits.
190 * (This does _not_ include 3000/300 TC option slot bits).
191 */
192 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
193 for (i = 0; i < ioasic_ndevs; i++)
194 imsk &= ~ioasic_devs[i].iad_intrbits;
195 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
196
197 /*
198 * Set up interrupt handlers.
199 */
200 for (i = 0; i < IOASIC_NCOOKIES; i++) {
201 ioasicintrs[i].iai_func = ioasic_intrnull;
202 ioasicintrs[i].iai_arg = (void *)i;
203 }
204 tc_intr_establish(parent, ta->ta_cookie, IPL_NONE, ioasic_intr, sc,
205 NULL);
206
207 /*
208 * Try to configure each device.
209 */
210 ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs);
211
212 ioasic_led_blink(NULL);
213 }
214
215 void
ioasic_intr_establish(ioa,cookie,level,func,arg,name)216 ioasic_intr_establish(ioa, cookie, level, func, arg, name)
217 struct device *ioa;
218 void *cookie, *arg;
219 int level;
220 int (*func)(void *);
221 const char *name;
222 {
223 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
224 u_long dev, i, imsk;
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 %lu twice", dev);
233
234 ioasicintrs[dev].iai_func = func;
235 ioasicintrs[dev].iai_arg = arg;
236 evcount_attach(&ioasicintrs[dev].iai_count, name, NULL);
237
238 /* Enable interrupts for the device. */
239 for (i = 0; i < ioasic_ndevs; i++)
240 if (ioasic_devs[i].iad_cookie == cookie)
241 break;
242 if (i == ioasic_ndevs)
243 panic("ioasic_intr_establish: invalid cookie.");
244
245 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
246 imsk |= ioasic_devs[i].iad_intrbits;
247 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
248 }
249
250 void
ioasic_intr_disestablish(ioa,cookie)251 ioasic_intr_disestablish(ioa, cookie)
252 struct device *ioa;
253 void *cookie;
254 {
255 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
256 u_long dev, i, imsk;
257
258 dev = (u_long)cookie;
259 #ifdef DIAGNOSTIC
260 /* XXX check cookie. */
261 #endif
262
263 if (ioasicintrs[dev].iai_func == ioasic_intrnull)
264 panic("ioasic_intr_disestablish: cookie %lu missing intr", dev);
265
266 /* Enable interrupts for the device. */
267 for (i = 0; i < ioasic_ndevs; i++)
268 if (ioasic_devs[i].iad_cookie == cookie)
269 break;
270 if (i == ioasic_ndevs)
271 panic("ioasic_intr_disestablish: invalid cookie.");
272
273 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
274 imsk &= ~ioasic_devs[i].iad_intrbits;
275 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
276
277 ioasicintrs[dev].iai_func = ioasic_intrnull;
278 ioasicintrs[dev].iai_arg = (void *)dev;
279 evcount_detach(&ioasicintrs[dev].iai_count);
280 }
281
282 int
ioasic_intrnull(val)283 ioasic_intrnull(val)
284 void *val;
285 {
286
287 panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
288 (u_long)val);
289 }
290
291 /*
292 * ASIC interrupt handler.
293 */
294 int
ioasic_intr(val)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, osir;
302
303 gifound = 0;
304 do {
305 ifound = 0;
306 tc_syncbus();
307
308 osir = sir =
309 bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
310
311 /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
312 #define CHECKINTR(slot, bits, clear) \
313 if (sir & (bits)) { \
314 ifound = 1; \
315 ioasicintrs[slot].iai_count.ec_count++; \
316 (*ioasicintrs[slot].iai_func) \
317 (ioasicintrs[slot].iai_arg); \
318 if (clear) \
319 sir &= ~(bits); \
320 }
321 CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0);
322 CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0);
323 CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0);
324 CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD |
325 IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1);
326
327 if (sir != osir)
328 bus_space_write_4(sc->sc_bst, sc->sc_bsh,
329 IOASIC_INTR, sir);
330
331 gifound |= ifound;
332 } while (ifound);
333
334 return (gifound);
335 }
336
337 /*
338 * Blink leds
339 */
340
341 struct {
342 int patpos;
343 struct timeout tmo;
344 } led_blink_state;
345
346 static const uint8_t led_pattern8[] = {
347 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
348 0x40, 0x20, 0x10, 0x08, 0x04, 0x02
349 };
350
351 void
ioasic_led_blink(void * unused)352 ioasic_led_blink(void *unused)
353 {
354 extern int alpha_led_blink; /* machdep.c */
355 vaddr_t rw_csr;
356 u_int32_t pattern;
357 int display_loadavg;
358
359 if (alpha_led_blink == 0) {
360 pattern = 0; /* all clear */
361 led_blink_state.patpos = 0;
362 } else {
363 #ifdef DEC_3000_300
364 if (cputype == ST_DEC_3000_300)
365 display_loadavg = 0;
366 else
367 #endif
368 switch (hwrpb->rpb_variation & SV_ST_MASK) {
369 case SV_ST_FLAMINGO:
370 case SV_ST_HOTPINK:
371 case SV_ST_FLAMINGOPLUS:
372 case SV_ST_ULTRA:
373 case SV_ST_FLAMINGO45:
374 /* 500/800/900, 2 7-segment display, display loadavg */
375 display_loadavg = 1;
376 break;
377 case SV_ST_SANDPIPER:
378 case SV_ST_SANDPLUS:
379 case SV_ST_SANDPIPER45:
380 default:
381 /* 400/600/700, 8 leds, display moving pattern */
382 display_loadavg = 0;
383 break;
384 }
385
386 if (display_loadavg)
387 pattern = averunnable.ldavg[0] >> FSHIFT;
388 else {
389 pattern = led_pattern8[led_blink_state.patpos];
390 led_blink_state.patpos =
391 (led_blink_state.patpos + 1) % sizeof(led_pattern8);
392 }
393 }
394
395 /*
396 * The low 8 bits, controlling the leds, are read-only in the
397 * CSR register, but read-write in its image at CSR + 4.
398 *
399 * On model 300, however, the internal 8 leds are at a different
400 * address, but the (better visible) power supply led is actually
401 * bit 5 in CSR (active low).
402 */
403 #ifdef DEC_3000_300
404 if (cputype == ST_DEC_3000_300) {
405 rw_csr = KV(0x1a0000000 + IOASIC_CSR + 4);
406
407 *(volatile uint32_t *)TC_3000_300_LED =
408 (*(volatile uint32_t *)TC_3000_300_LED & ~(0xff << 16)) |
409 (pattern << 16);
410 /*
411 * Blink the power supply led 8x slower. This relies
412 * on led_pattern8[] being a < 16 element array.
413 */
414 *(volatile uint32_t *)rw_csr =
415 (*(volatile uint32_t *)rw_csr & ~(1 << 5)) ^
416 ((led_blink_state.patpos >> 3) << 5);
417 } else
418 #endif
419 {
420 rw_csr = KV(0x1e0000000 + IOASIC_CSR + 4);
421
422 *(volatile uint32_t *)rw_csr =
423 (*(volatile uint32_t *)rw_csr & ~0xff) | pattern;
424 }
425
426 if (alpha_led_blink != 0) {
427 timeout_set(&led_blink_state.tmo, ioasic_led_blink, NULL);
428 timeout_add(&led_blink_state.tmo,
429 (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 3)));
430 }
431 }
432