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