Annotation of sys/arch/hp300/dev/frodo.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: frodo.c,v 1.11 2007/01/14 17:54:45 miod Exp $ */
2: /* $NetBSD: frodo.c,v 1.5 1999/07/31 21:15:20 thorpej Exp $ */
3:
4: /*-
5: * Copyright (c) 1997, 1998, 1999 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.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * Copyright (c) 1997 Michael Smith. All rights reserved.
42: *
43: * Redistribution and use in source and binary forms, with or without
44: * modification, are permitted provided that the following conditions
45: * are met:
46: * 1. Redistributions of source code must retain the above copyright
47: * notice, this list of conditions and the following disclaimer.
48: * 2. Redistributions in binary form must reproduce the above copyright
49: * notice, this list of conditions and the following disclaimer in the
50: * documentation and/or other materials provided with the distribution.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: */
64:
65: /*
66: * Support for the "Frodo" (a.k.a. "Apollo Utility") chip found
67: * in HP Apollo 9000/4xx workstations, as well as HP 9000/362 and 9000/382.
68: */
69:
70: #include <sys/param.h>
71: #include <sys/systm.h>
72: #include <sys/kernel.h>
73: #include <sys/syslog.h>
74: #include <sys/device.h>
75:
76: #include <machine/bus.h>
77: #include <machine/cpu.h>
78: #include <machine/intr.h>
79: #include <machine/hp300spu.h>
80:
81: #include <hp300/dev/intiovar.h>
82:
83: #include <hp300/dev/frodoreg.h>
84: #include <hp300/dev/frodovar.h>
85:
86: #include "isabr.h"
87:
88: #if NISABR > 0
89: #include <uvm/uvm_extern.h>
90:
91: #include <dev/isa/isareg.h>
92: #include <hp300/dev/isabrreg.h>
93: #endif
94:
95: struct frodo_softc {
96: struct device sc_dev; /* generic device glue */
97: volatile u_int8_t *sc_regs; /* register base */
98: struct isr *sc_intr[FRODO_NINTR]; /* interrupt handlers */
99: struct isr sc_isr; /* main interrupt handler */
100: u_int sc_refcnt; /* number of interrupt refs */
101: };
102:
103: int frodomatch(struct device *, void *, void *);
104: void frodoattach(struct device *, struct device *, void *);
105:
106: int frodoprint(void *, const char *);
107: int frodosubmatch(struct device *, void *, void *);
108:
109: int frodointr(void *);
110: void frodo_imask(struct frodo_softc *, u_int16_t, u_int16_t);
111: int frodo_isa_exists(void);
112: void frodo_state(struct frodo_softc *);
113:
114: struct cfattach frodo_ca = {
115: sizeof(struct frodo_softc), frodomatch, frodoattach
116: };
117:
118: struct cfdriver frodo_cd = {
119: NULL, "frodo", DV_DULL
120: };
121:
122: struct frodo_attach_args frodo_subdevs[] = {
123: { "dnkbd", NULL, FRODO_APCI_OFFSET(0), FRODO_INTR_APCI0 },
124: { "apci", NULL, FRODO_APCI_OFFSET(1), FRODO_INTR_APCI1 },
125: { "apci", NULL, FRODO_APCI_OFFSET(2), FRODO_INTR_APCI2 },
126: { "apci", NULL, FRODO_APCI_OFFSET(3), FRODO_INTR_APCI3 },
127: { NULL, NULL, 0, 0 },
128: };
129:
130: #define FRODO_IPL 5
131:
132: int
133: frodomatch(parent, match, aux)
134: struct device *parent;
135: void *match, *aux;
136: {
137: struct intio_attach_args *ia = aux;
138: caddr_t va;
139: static int frodo_matched = 0;
140:
141: /* only allow one instance */
142: if (frodo_matched)
143: return (0);
144:
145: /* only specific workstations can have this */
146: switch (machineid) {
147: case HP_362:
148: case HP_382:
149: case HP_400:
150: case HP_425:
151: case HP_433:
152: break;
153:
154: default:
155: return (0);
156: }
157:
158: /* make sure the hardware is there in any case */
159: va = (caddr_t)IIOV(FRODO_BASE);
160: if (badaddr(va))
161: return (0);
162:
163: frodo_matched = 1;
164: ia->ia_addr = (caddr_t)FRODO_BASE;
165: return (1);
166: }
167:
168: void
169: frodoattach(parent, self, aux)
170: struct device *parent, *self;
171: void *aux;
172: {
173: struct frodo_softc *sc = (struct frodo_softc *)self;
174: struct intio_attach_args *ia = aux;
175: int i;
176:
177: sc->sc_regs = (volatile u_int8_t *)IIOV(ia->ia_addr);
178:
179: printf(" ipl %d", FRODO_IPL);
180: if ((FRODO_READ(sc, FRODO_IISR) & FRODO_IISR_SERVICE) == 0)
181: printf(": service mode enabled");
182: printf("\n");
183:
184: /* Clear all of the interrupt handlers. */
185: bzero(sc->sc_intr, sizeof(sc->sc_intr));
186:
187: /*
188: * Disable all of the interrupt lines; we reenable them
189: * as subdevices attach.
190: */
191: frodo_imask(sc, 0, 0xffff);
192:
193: /* Clear any pending interrupts. */
194: FRODO_WRITE(sc, FRODO_PIC_PU, 0xff);
195: FRODO_WRITE(sc, FRODO_PIC_PL, 0xff);
196:
197: /* Set interrupt polarities... */
198: FRODO_WRITE(sc, FRODO_PIO_IPR, 0x10);
199:
200: /* ...and configure 1-5 for edge triggering. */
201: FRODO_WRITE(sc, FRODO_PIO_IELR, 0xc1);
202:
203: /* Initialize IVR high half to zero so we don't need to mask it later */
204: FRODO_WRITE(sc, FRODO_PIC_IVR, 0x00);
205:
206: /* Mask ISA interrupts until an ISA interrupt handler is registered. */
207: FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x80);
208:
209: /*
210: * We defer hooking up our interrupt handler until
211: * a subdevice hooks up theirs.
212: */
213: sc->sc_refcnt = 0;
214:
215: /* ... and attach subdevices. */
216: for (i = 0; frodo_subdevs[i].fa_name != NULL; i++) {
217: /*
218: * Skip the first serial port if we're not a 425e;
219: * it's mapped to the DCA at select code 9 on all
220: * other models.
221: */
222: if (frodo_subdevs[i].fa_offset == FRODO_APCI_OFFSET(1) &&
223: mmuid != MMUID_425_E)
224: continue;
225: frodo_subdevs[i].fa_tag = ia->ia_tag;
226: config_found_sm(self, &frodo_subdevs[i],
227: frodoprint, frodosubmatch);
228: }
229:
230: #if NISABR > 0
231: /*
232: * Only attempt to attach the isa bridge if it exists on this
233: * machine.
234: */
235: if (frodo_isa_exists()) {
236: struct frodo_attach_args fa;
237:
238: fa.fa_name = "isabr";
239: fa.fa_tag = ia->ia_tag;
240: fa.fa_offset = fa.fa_line = 0;
241: config_found_sm(self, &fa, frodoprint, frodosubmatch);
242: }
243: #endif
244: }
245:
246: int
247: frodosubmatch(parent, match, aux)
248: struct device *parent;
249: void *match, *aux;
250: {
251: struct cfdata *cf = match;
252: struct frodo_attach_args *fa = aux;
253:
254: if (cf->frodocf_offset != FRODO_UNKNOWN_OFFSET &&
255: cf->frodocf_offset != fa->fa_offset)
256: return (0);
257:
258: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
259: }
260:
261: int
262: frodoprint(aux, pnp)
263: void *aux;
264: const char *pnp;
265: {
266: struct frodo_attach_args *fa = aux;
267:
268: if (pnp)
269: printf("%s at %s", fa->fa_name, pnp);
270: printf(" offset 0x%x", fa->fa_offset);
271: return (UNCONF);
272: }
273:
274: int
275: frodo_intr_establish(struct device *frdev, int line, struct isr *isr,
276: const char *name)
277: {
278: struct frodo_softc *sc = (struct frodo_softc *)frdev;
279: int priority = isr->isr_priority;
280:
281: if (line <= 0 || line >= FRODO_NINTR) {
282: panic("%s: bad interrupt line %d",
283: sc->sc_dev.dv_xname, line);
284: }
285: if (sc->sc_intr[line] != NULL) {
286: #ifdef DEBUG
287: printf("%s: interrupt line %d already used\n",
288: sc->sc_dev.dv_xname, line);
289: #endif
290: return (EPERM);
291: }
292:
293: /*
294: * If this is the first one, establish the frodo
295: * interrupt handler. If not, reestablish at a
296: * higher priority if necessary.
297: */
298: if (sc->sc_isr.isr_priority < priority) {
299: if (sc->sc_refcnt != 0)
300: intr_disestablish(&sc->sc_isr);
301: sc->sc_isr.isr_func = frodointr;
302: sc->sc_isr.isr_arg = sc;
303: sc->sc_isr.isr_ipl = FRODO_IPL;
304: sc->sc_isr.isr_priority = priority;
305: intr_establish(&sc->sc_isr, sc->sc_dev.dv_xname);
306: }
307:
308: sc->sc_refcnt++;
309:
310: /* Install the handler. */
311: isr->isr_ipl = sc->sc_isr.isr_ipl;
312: evcount_attach(&isr->isr_count, name, &isr->isr_ipl, &evcount_intr);
313: sc->sc_intr[line] = isr;
314:
315: /* Enable the interrupt line. */
316: frodo_imask(sc, FRODO_INTR_BIT(line), 0);
317:
318: #if NISABR > 0
319: /* Unmask ISA interrupts if necessary. */
320: if (FRODO_INTR_ISA(line))
321: FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x00);
322: #endif
323:
324: return (0);
325: }
326:
327: void
328: frodo_intr_disestablish(frdev, line)
329: struct device *frdev;
330: int line;
331: {
332: struct frodo_softc *sc = (struct frodo_softc *)frdev;
333: int newpri;
334:
335: #ifdef DIAGNOSTIC
336: if (sc->sc_intr[line] == NULL) {
337: printf("%s(%s): no handler for line %d",
338: sc->sc_dev.dv_xname, __func__, line);
339: return;
340: }
341: #endif
342:
343: sc->sc_intr[line] = NULL;
344: frodo_imask(sc, 0, FRODO_INTR_BIT(line));
345:
346: #if NISABR > 0
347: /* Mask ISA interrupts if necessary. */
348: if (FRODO_INTR_ISA(line)) {
349: if (sc->sc_intr[FRODO_INTR_ILOW] == NULL &&
350: sc->sc_intr[FRODO_INTR_IMID] == NULL &&
351: sc->sc_intr[FRODO_INTR_IHI] == NULL)
352: FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x80);
353: }
354: #endif
355:
356: /* If this was the last, unhook ourselves. */
357: if (sc->sc_refcnt-- == 1) {
358: intr_disestablish(&sc->sc_isr);
359: return;
360: }
361:
362: /* Lower our priority, if appropriate. */
363: for (newpri = 0, line = 0; line < FRODO_NINTR; line++)
364: if (sc->sc_intr[line] != NULL &&
365: sc->sc_intr[line]->isr_priority > newpri)
366: newpri = sc->sc_intr[line]->isr_priority;
367:
368: if (newpri != sc->sc_isr.isr_priority) {
369: intr_disestablish(&sc->sc_isr);
370: sc->sc_isr.isr_func = frodointr;
371: sc->sc_isr.isr_arg = sc;
372: sc->sc_isr.isr_ipl = FRODO_IPL;
373: sc->sc_isr.isr_priority = newpri;
374: intr_establish(&sc->sc_isr, sc->sc_dev.dv_xname);
375: }
376: }
377:
378: int
379: frodointr(arg)
380: void *arg;
381: {
382: struct frodo_softc *sc = arg;
383: struct isr *fisr;
384: int pending, line, rc = 0;
385:
386: #ifdef DEBUG
387: frodo_state(sc);
388: #endif
389:
390: /* Any interrupts pending? */
391: while ((pending = FRODO_GETPEND(sc)) != 0) {
392: rc++;
393:
394: /*
395: * Get pending interrupt; this also clears it for us.
396: */
397: line = FRODO_READ(sc, FRODO_PIC_ACK) /* & 0x0f */;
398:
399: fisr = sc->sc_intr[line];
400: if (fisr == NULL) {
401: printf("%s: unhandled interrupt on line %d\n",
402: sc->sc_dev.dv_xname, line);
403: #ifdef DEBUG
404: /* Disable interrupt source */
405: frodo_imask(sc, 0, FRODO_INTR_BIT(line));
406: #endif
407: } else {
408: if ((*fisr->isr_func)(fisr->isr_arg) != 0) {
409: fisr->isr_count.ec_count++;
410: } else {
411: printf("%s: spurious interrupt on line %d\n",
412: sc->sc_dev.dv_xname, line);
413: }
414: }
415:
416: if (rc > 100)
417: panic("frodointr: looping, pending %x line %d fisr %p",
418: pending, line, fisr);
419:
420: #ifdef DEBUG
421: frodo_state(sc);
422: #endif
423: }
424:
425: return (rc);
426: }
427:
428: void
429: frodo_imask(sc, set, clear)
430: struct frodo_softc *sc;
431: u_int16_t set, clear;
432: {
433: u_int16_t imask;
434:
435: imask = FRODO_GETMASK(sc);
436:
437: imask |= set;
438: imask &= ~clear;
439:
440: FRODO_SETMASK(sc, imask);
441: }
442:
443: #ifdef DEBUG
444: void
445: frodo_state(struct frodo_softc *sc)
446: {
447: int i;
448:
449: printf("%s state:", sc->sc_dev.dv_xname);
450: for (i = 0xc0; i < 0x100; i += 4) {
451: printf(" %02x", FRODO_READ(sc, i));
452: if (i == 0xcc || i == 0xdc || i == 0xec)
453: printf(" /");
454: }
455: printf("\n");
456: }
457: #endif
458:
459: #if NISABR > 0
460: int
461: frodo_isa_exists()
462: {
463: vaddr_t va;
464: int rv;
465:
466: va = uvm_km_valloc(kernel_map, PAGE_SIZE);
467: if (va == NULL)
468: return (0);
469:
470: /*
471: * Check that the iomem space answers probes
472: */
473: pmap_kenter_cache(va, ISABR_IOMEM_BASE, PG_RW | PG_CI);
474: pmap_update(pmap_kernel());
475: rv = badbaddr((caddr_t)va);
476: pmap_kremove(va, PAGE_SIZE);
477: pmap_update(pmap_kernel());
478:
479: /*
480: * Check that the ioport space answers probes
481: */
482: pmap_kenter_cache(va, ISABR_IOPORT_BASE, PG_RW | PG_CI);
483: pmap_update(pmap_kernel());
484: rv |= badbaddr((caddr_t)va);
485: pmap_kremove(va, PAGE_SIZE);
486: pmap_update(pmap_kernel());
487:
488: uvm_km_free(kernel_map, va, PAGE_SIZE);
489:
490: return (!rv);
491: }
492: #endif
CVSweb