Annotation of sys/arch/mac68k/mac68k/via.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: via.c,v 1.30 2007/07/29 21:25:23 miod Exp $ */
2: /* $NetBSD: via.c,v 1.62 1997/09/10 04:38:48 scottr Exp $ */
3:
4: /*-
5: * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo,
6: * Michael L. Finch, Bradley A. Grantham, and
7: * Lawrence A. Kesteloot
8: * All rights reserved.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the Alice Group.
21: * 4. The names of the Alice Group or any of its members may not be used
22: * to endorse or promote products derived from this software without
23: * specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
26: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28: * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
29: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35: *
36: */
37:
38: /*
39: * This code handles both the VIA, RBV and OSS functionality.
40: */
41:
42: #include <sys/param.h>
43: #include <sys/kernel.h>
44: #include <sys/syslog.h>
45: #include <sys/systm.h>
46: #include <sys/evcount.h>
47:
48: #include <machine/cpu.h>
49: #include <machine/frame.h>
50: #include <machine/intr.h>
51: #include <machine/viareg.h>
52:
53: int rtclock_intr(void *);
54:
55: int via1_intr(void *);
56: int via2_intr(void *);
57: int rbv_intr(void *);
58: int oss_intr(void *);
59: int via2_nubus_intr(void *);
60: int rbv_nubus_intr(void *);
61:
62: static int slot_ignore(void *);
63:
64: int VIA2 = VIA2OFF; /* default for II, IIx, IIcx, SE/30. */
65:
66: struct intrhand via1intrs[7];
67: via2hand_t via2intrs[7];
68:
69: /*
70: * Nubus slot interrupt routines and parameters for slots 9-15. Note
71: * that for simplicity of code, "v2IRQ0" for internal video is treated
72: * as a slot 15 interrupt; this slot is quite fictitious in real-world
73: * Macs. See also GMFH, pp. 165-167, and "Monster, Loch Ness."
74: */
75: struct intrhand slotintrs[7];
76:
77: static struct via2hand nubus_intr;
78:
79: void
80: via_init()
81: {
82: unsigned int i;
83:
84: /* Initialize VIA1 */
85: /* set all timers to 0 */
86: via_reg(VIA1, vT1L) = 0;
87: via_reg(VIA1, vT1LH) = 0;
88: via_reg(VIA1, vT1C) = 0;
89: via_reg(VIA1, vT1CH) = 0;
90: via_reg(VIA1, vT2C) = 0;
91: via_reg(VIA1, vT2CH) = 0;
92:
93: /* turn off timer latch */
94: via_reg(VIA1, vACR) &= 0x3f;
95:
96: intr_establish(via1_intr, NULL, mac68k_machine.via1_ipl, "via1");
97:
98: /* register default VIA1 interrupts */
99: via1_register_irq(VIA1_T1, rtclock_intr, NULL, "clock");
100:
101: for (i = 0; i < 7; i++)
102: SLIST_INIT(&via2intrs[i]);
103:
104: if (VIA2 == VIA2OFF) {
105: /* Initialize VIA2 */
106: via2_reg(vT1L) = 0;
107: via2_reg(vT1LH) = 0;
108: via2_reg(vT1C) = 0;
109: via2_reg(vT1CH) = 0;
110: via2_reg(vT2C) = 0;
111: via2_reg(vT2CH) = 0;
112:
113: /* turn off timer latch */
114: via2_reg(vACR) &= 0x3f;
115:
116: /* register default VIA2 interrupts */
117: nubus_intr.vh_ipl = 1;
118: nubus_intr.vh_fn = via2_nubus_intr;
119: via2_register_irq(&nubus_intr, NULL);
120: /* 4 snd_intr, 5 via2t2_intr */
121:
122: /*
123: * Turn off SE/30 video interrupts.
124: */
125: if (mac68k_machine.machineid == MACH_MACSE30) {
126: via_reg(VIA1, vBufB) |= (0x40);
127: via_reg(VIA1, vDirB) |= (0x40);
128: }
129:
130: /*
131: * Set vPCR for SCSI interrupts.
132: */
133: via2_reg(vPCR) = 0x66;
134: switch(mac68k_machine.machineid) {
135: case MACH_MACPB140:
136: case MACH_MACPB145:
137: case MACH_MACPB150:
138: case MACH_MACPB160:
139: case MACH_MACPB165:
140: case MACH_MACPB165C:
141: case MACH_MACPB170:
142: case MACH_MACPB180:
143: case MACH_MACPB180C:
144: break;
145: default:
146: via2_reg(vBufB) |= 0x02; /* Unlock NuBus */
147: via2_reg(vDirB) |= 0x02;
148: break;
149: }
150:
151: intr_establish(via2_intr, NULL, 2, "via2");
152: } else if (current_mac_model->class == MACH_CLASSIIfx) { /* OSS */
153: volatile u_char *ossintr;
154: ossintr = (volatile u_char *)Via2Base + 6;
155: *ossintr = 0;
156: intr_establish(oss_intr, NULL, 2, "via2");
157: } else { /* RBV */
158: if (current_mac_model->class == MACH_CLASSIIci) {
159: /*
160: * Disable cache card. (p. 174--GtMFH)
161: */
162: via2_reg(rBufB) |= DB2O_CEnable;
163: }
164: intr_establish(rbv_intr, NULL, 2, "via2");
165:
166: nubus_intr.vh_ipl = 1;
167: nubus_intr.vh_fn = rbv_nubus_intr;
168: via2_register_irq(&nubus_intr, NULL);
169: /* XXX necessary? */
170: add_nubus_intr(0, slot_ignore, (void *)0, "dummy");
171: }
172: }
173:
174: /*
175: * Set the state of the modem serial port's clock source.
176: */
177: void
178: via_set_modem(int onoff)
179: {
180: via_reg(VIA1, vDirA) |= DA1O_vSync;
181: if (onoff)
182: via_reg(VIA1, vBufA) |= DA1O_vSync;
183: else
184: via_reg(VIA1, vBufA) &= ~DA1O_vSync;
185: }
186:
187: int
188: via1_intr(void *arg)
189: {
190: struct intrhand *ih;
191: u_int8_t intbits, bitnum;
192: u_int mask;
193:
194: intbits = via_reg(VIA1, vIFR); /* get interrupts pending */
195: intbits &= via_reg(VIA1, vIER); /* only care about enabled */
196:
197: if (intbits == 0)
198: return (0);
199:
200: /*
201: * Unflag interrupts here. If we do it after each interrupt,
202: * the MRG ADB hangs up.
203: */
204: via_reg(VIA1, vIFR) = intbits;
205:
206: intbits &= 0x7f;
207: mask = 1;
208: for (bitnum = 0, ih = via1intrs; ; bitnum++, ih++) {
209: if ((intbits & mask) != 0 && ih->ih_fn != NULL)
210: if ((*ih->ih_fn)(ih->ih_arg) != 0)
211: ih->ih_count.ec_count++;
212: mask <<= 1;
213: if (intbits < mask)
214: break;
215: }
216:
217: return (1);
218: }
219:
220: int
221: via2_intr(void *arg)
222: {
223: struct via2hand *v2h;
224: via2hand_t *anchor;
225: u_int8_t intbits, bitnum;
226: u_int mask;
227: int handled, rc;
228:
229: intbits = via2_reg(vIFR); /* get interrupts pending */
230: intbits &= via2_reg(vIER); /* only care about enabled */
231:
232: if (intbits == 0)
233: return (0);
234:
235: via2_reg(vIFR) = intbits;
236:
237: intbits &= 0x7f;
238: mask = 1;
239: for (bitnum = 0, anchor = via2intrs; ; bitnum++, anchor++) {
240: if ((intbits & mask) != 0) {
241: handled = 0;
242: SLIST_FOREACH(v2h, anchor, v2h_link) {
243: struct intrhand *ih = &v2h->v2h_ih;
244: rc = (*ih->ih_fn)(ih->ih_arg);
245: if (rc != 0) {
246: ih->ih_count.ec_count++;
247: handled |= rc;
248: }
249: }
250: }
251: mask <<= 1;
252: if (intbits < mask)
253: break;
254: }
255:
256: return (1);
257: }
258:
259: int
260: rbv_intr(void *arg)
261: {
262: struct via2hand *v2h;
263: via2hand_t *anchor;
264: u_int8_t intbits, bitnum;
265: u_int mask;
266: int handled, rc;
267:
268: intbits = via2_reg(vIFR + rIFR);
269: intbits &= via2_reg(vIER + rIER);
270:
271: if (intbits == 0)
272: return (0);
273:
274: via2_reg(rIFR) = intbits;
275:
276: intbits &= 0x7f;
277: mask = 1;
278: for (bitnum = 0, anchor = via2intrs; ; bitnum++, anchor++) {
279: if ((intbits & mask) != 0) {
280: handled = 0;
281: SLIST_FOREACH(v2h, anchor, v2h_link) {
282: struct intrhand *ih = &v2h->v2h_ih;
283: rc = (*ih->ih_fn)(ih->ih_arg);
284: if (rc != 0) {
285: ih->ih_count.ec_count++;
286: handled |= rc;
287: }
288: }
289: }
290: mask <<= 1;
291: if (intbits < mask)
292: break;
293: }
294:
295: return (1);
296: }
297:
298: int nubus_intr_mask = 0;
299:
300: void
301: add_nubus_intr(int slot, int (*func)(void *), void *client_data,
302: const char *name)
303: {
304: struct intrhand *ih;
305: int s;
306:
307: /*
308: * Map Nubus slot 0 to "slot" 15; see note on Nubus slot
309: * interrupt tables.
310: */
311: #ifdef DIAGNOSTIC
312: if (slot != 0 && (slot < 9 || slot > 14))
313: panic("add_nubus_intr: wrong slot %d", slot + 9);
314: #endif
315: if (slot == 0)
316: slot = 15 - 9;
317: else
318: slot -= 9;
319:
320: s = splhigh();
321:
322: ih = &slotintrs[slot];
323:
324: #ifdef DIAGNOSTIC
325: if (ih->ih_fn != NULL)
326: panic("add_nubus_intr: attempt to share slot %d", slot + 9);
327: #endif
328:
329: ih->ih_fn = func;
330: ih->ih_arg = client_data;
331: ih->ih_ipl = slot + 9;
332: evcount_attach(&ih->ih_count, name, (void *)&ih->ih_ipl, &evcount_intr);
333:
334: nubus_intr_mask |= (1 << slot);
335:
336: splx(s);
337: }
338:
339: void
340: enable_nubus_intr()
341: {
342: if ((nubus_intr_mask & 0x3f) == 0)
343: return;
344:
345: if (VIA2 == VIA2OFF)
346: via2_reg(vIER) = 0x80 | V2IF_SLOTINT;
347: else
348: via2_reg(rIER) = 0x80 | V2IF_SLOTINT;
349: }
350:
351: int
352: oss_intr(void *arg)
353: {
354: struct intrhand *ih;
355: u_int8_t intbits, bitnum;
356: u_int mask;
357:
358: intbits = via2_reg(vIFR + rIFR);
359:
360: if (intbits == 0)
361: return (0);
362:
363: intbits &= 0x7f;
364: mask = 1;
365: for (bitnum = 0, ih = slotintrs; ; bitnum++, ih++) {
366: if (intbits & mask) {
367: if (ih->ih_fn != NULL) {
368: if ((*ih->ih_fn)(ih->ih_arg) != 0)
369: ih->ih_count.ec_count++;
370: }
371: via2_reg(rIFR) = mask;
372: }
373: mask <<= 1;
374: if (intbits < mask)
375: break;
376: }
377:
378: return (1);
379: }
380:
381: /*ARGSUSED*/
382: int
383: via2_nubus_intr(void *bitarg)
384: {
385: struct intrhand *ih;
386: u_int8_t i, intbits, mask;
387: int rv = 0;
388:
389: via2_reg(vIFR) = V2IF_SLOTINT;
390: while ((intbits = (~via2_reg(vBufA)) & nubus_intr_mask)) {
391: for (i = 6, ih = &slotintrs[i], mask = 1 << i; mask != 0;
392: i--, ih--, mask >>= 1) {
393: if (intbits & mask) {
394: if (ih->ih_fn != NULL) {
395: if ((*ih->ih_fn)(ih->ih_arg) != 0) {
396: ih->ih_count.ec_count++;
397: rv = 1;
398: }
399: }
400: }
401: }
402: via2_reg(vIFR) = V2IF_SLOTINT;
403: }
404: return (rv);
405: }
406:
407: /*ARGSUSED*/
408: int
409: rbv_nubus_intr(void *bitarg)
410: {
411: struct intrhand *ih;
412: u_int8_t i, intbits, mask;
413: int rv = 0;
414:
415: via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
416: while ((intbits = (~via2_reg(rBufA)) & via2_reg(rSlotInt))) {
417: for (i = 6, ih = &slotintrs[i], mask = 1 << i; mask != 0;
418: i--, ih--, mask >>= 1) {
419: if (intbits & mask) {
420: if (ih->ih_fn != NULL) {
421: if ((*ih->ih_fn)(ih->ih_arg) != 0) {
422: ih->ih_count.ec_count++;
423: rv = 1;
424: }
425: }
426: }
427: }
428: via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
429: }
430: return (rv);
431: }
432:
433: static int
434: slot_ignore(void *client_data)
435: {
436: int mask = (1 << (int)client_data);
437:
438: if (VIA2 == VIA2OFF) {
439: via2_reg(vDirA) |= mask;
440: via2_reg(vBufA) = mask;
441: via2_reg(vDirA) &= ~mask;
442: } else
443: via2_reg(rBufA) = mask;
444:
445: return (1);
446: }
447:
448: void
449: via_powerdown()
450: {
451: if (VIA2 == VIA2OFF) {
452: via2_reg(vDirB) |= 0x04; /* Set write for bit 2 */
453: via2_reg(vBufB) &= ~0x04; /* Shut down */
454: } else if (VIA2 == RBVOFF) {
455: via2_reg(rBufB) &= ~0x04;
456: } else if (VIA2 == OSSOFF) {
457: /*
458: * Thanks to Brad Boyer <flar@cegt201.bradley.edu> for the
459: * Linux/mac68k code that I derived this from.
460: */
461: via2_reg(OSS_oRCR) |= OSS_POWEROFF;
462: }
463: }
464:
465: void
466: via1_register_irq(int irq, int (*irq_func)(void *), void *client_data,
467: const char *name)
468: {
469: struct intrhand *ih;
470:
471: #ifdef DIAGNOSTIC
472: if (irq < 0 || irq > 7)
473: panic("via1_register_irq: bad irq %d", irq);
474: #endif
475:
476: ih = &via1intrs[irq];
477:
478: /*
479: * VIA1 interrupts are special, since we start with temporary handlers,
480: * and later switch to better routines whenever possible.
481: * To avoid a loop in evcount lists, only invoke evcount_attach() if
482: * name is non-NULL, and have the replacements calls in adb_direct.c,
483: * clock.c and pm_direct.c pass a NULL pointer.
484: */
485: #ifdef DIAGNOSTIC
486: if (ih->ih_fn != NULL && name != NULL)
487: panic("via1_register_irq: improper invocation");
488: #endif
489:
490: ih->ih_fn = irq_func;
491: ih->ih_arg = client_data;
492: ih->ih_ipl = irq;
493: if (name != NULL)
494: evcount_attach(&ih->ih_count, name, (void *)&ih->ih_ipl,
495: &evcount_intr);
496: }
497:
498: int
499: via2_register_irq(struct via2hand *vh, const char *name)
500: {
501: int irq = vh->vh_ipl;
502:
503: #ifdef DIAGNOSTIC
504: if (irq < 0 || irq > 7)
505: panic("via2_register_irq: bad irq %d", irq);
506: #endif
507:
508: if (name != NULL)
509: evcount_attach(&vh->vh_count, name, (void *)&vh->vh_ipl,
510: &evcount_intr);
511: SLIST_INSERT_HEAD(&via2intrs[irq], vh, v2h_link);
512: return (0);
513: }
CVSweb