Home | History | Annotate | Line # | Download | only in mac68k
      1 /*	$NetBSD: via.c,v 1.77 2024/02/28 13:05:40 thorpej 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 <sys/cdefs.h>
     42 __KERNEL_RCSID(0, "$NetBSD: via.c,v 1.77 2024/02/28 13:05:40 thorpej Exp $");
     43 
     44 #include "opt_mac68k.h"
     45 
     46 #include <sys/param.h>
     47 #include <sys/kernel.h>
     48 #include <sys/syslog.h>
     49 #include <sys/systm.h>
     50 #include <machine/cpu.h>
     51 #include <machine/frame.h>
     52 #include <machine/intr.h>
     53 #include <machine/viareg.h>
     54 
     55 void	mrg_adbintr(void *);
     56 void	mrg_pmintr(void *);
     57 void	rtclock_intr(void *);
     58 void	profclock(void *);
     59 
     60 void	via1_intr(void *);
     61 void	via2_intr(void *);
     62 void	rbv_intr(void *);
     63 void	oss_intr(void *);
     64 void	via2_nubus_intr(void *);
     65 void	rbv_nubus_intr(void *);
     66 
     67 static void	via1_noint(void *);
     68 static void	via2_noint(void *);
     69 static void	slot_ignore(void *);
     70 static void	slot_noint(void *);
     71 
     72 int	VIA2 = VIA2OFF;		/* default for II, IIx, IIcx, SE/30. */
     73 
     74 /* VIA1 interrupt handler table */
     75 void (*via1itab[7])(void *) = {
     76 	via1_noint,
     77 	via1_noint,
     78 	mrg_adbintr,
     79 	via1_noint,
     80 	mrg_pmintr,
     81 	via1_noint,
     82 	rtclock_intr,
     83 };
     84 
     85 /* Arg array for VIA1 interrupts. */
     86 void *via1iarg[7] = {
     87 	(void *)0,
     88 	(void *)1,
     89 	(void *)2,
     90 	(void *)3,
     91 	(void *)4,
     92 	(void *)5,
     93 	(void *)6
     94 };
     95 
     96 /* VIA2 interrupt handler table */
     97 void (*via2itab[7])(void *) = {
     98 	via2_noint,
     99 	via2_nubus_intr,
    100 	via2_noint,
    101 	via2_noint,
    102 	via2_noint,	/* snd_intr */
    103 	via2_noint,	/* via2t2_intr */
    104 	via2_noint,
    105 };
    106 
    107 /* Arg array for VIA2 interrupts. */
    108 void *via2iarg[7] = {
    109 	(void *)0,
    110 	(void *)1,
    111 	(void *)2,
    112 	(void *)3,
    113 	(void *)4,
    114 	(void *)5,
    115 	(void *)6
    116 };
    117 
    118 /*
    119  * Nubus slot interrupt routines and parameters for slots 9-15.  Note
    120  * that for simplicity of code, "v2IRQ0" for internal video is treated
    121  * as a slot 15 interrupt; this slot is quite fictitious in real-world
    122  * Macs.  See also GMFH, pp. 165-167, and "Monster, Loch Ness."
    123  */
    124 void (*slotitab[7])(void *) = {
    125 	slot_noint,
    126 	slot_noint,
    127 	slot_noint,
    128 	slot_noint,
    129 	slot_noint,
    130 	slot_noint,
    131 	slot_noint	/* int_video_intr */
    132 };
    133 
    134 void *slotptab[7] = {
    135 	(void *)0,
    136 	(void *)1,
    137 	(void *)2,
    138 	(void *)3,
    139 	(void *)4,
    140 	(void *)5,
    141 	(void *)6
    142 };
    143 
    144 static int	nubus_intr_mask = 0;
    145 
    146 void
    147 via_init(void)
    148 {
    149 	/* Initialize VIA1 */
    150 	/* set all timers to 0 */
    151 	via_reg(VIA1, vT1L) = 0;
    152 	via_reg(VIA1, vT1LH) = 0;
    153 	via_reg(VIA1, vT1C) = 0;
    154 	via_reg(VIA1, vT1CH) = 0;
    155 	via_reg(VIA1, vT2C) = 0;
    156 	via_reg(VIA1, vT2CH) = 0;
    157 
    158 	/* turn off timer latch */
    159 	via_reg(VIA1, vACR) &= 0x3f;
    160 
    161 	intr_establish((int (*)(void *)) via1_intr, NULL, mac68k_machine.via1_ipl);
    162 
    163 	if (VIA2 == VIA2OFF) {
    164 		/* Initialize VIA2 */
    165 		via2_reg(vT1L) = 0;
    166 		via2_reg(vT1LH) = 0;
    167 		via2_reg(vT1C) = 0;
    168 		via2_reg(vT1CH) = 0;
    169 		via2_reg(vT2C) = 0;
    170 		via2_reg(vT2CH) = 0;
    171 
    172 		/* turn off timer latch */
    173 		via2_reg(vACR) &= 0x3f;
    174 
    175 		/*
    176 		 * Turn off SE/30 video interrupts.
    177 		 */
    178 		if (mac68k_machine.machineid == MACH_MACSE30) {
    179 			via_reg(VIA1, vBufB) |= (0x40);
    180 			via_reg(VIA1, vDirB) |= (0x40);
    181 		}
    182 
    183 		/*
    184 		 * Set vPCR for SCSI interrupts.
    185 		 */
    186 		via2_reg(vPCR) = 0x66;
    187 		switch(mac68k_machine.machineid) {
    188 		case MACH_MACPB140:
    189 		case MACH_MACPB145:
    190 		case MACH_MACPB150:
    191 		case MACH_MACPB160:
    192 		case MACH_MACPB165:
    193 		case MACH_MACPB165C:
    194 		case MACH_MACPB170:
    195 		case MACH_MACPB180:
    196 		case MACH_MACPB180C:
    197 			break;
    198 		default:
    199 			via2_reg(vBufB) |= 0x02;	/* Unlock NuBus */
    200 			via2_reg(vDirB) |= 0x02;
    201 			break;
    202 		}
    203 
    204 		intr_establish((int (*)(void*))via2_intr, NULL,
    205 				mac68k_machine.via2_ipl);
    206 		via2itab[1] = via2_nubus_intr;
    207 	} else if (current_mac_model->class == MACH_CLASSIIfx) { /* OSS */
    208 		volatile u_char *ossintr;
    209 		ossintr = (volatile u_char *)IOBase + 0x1a006;
    210 		*ossintr = 0;
    211 		intr_establish((int (*)(void*))oss_intr, NULL,
    212 	 			mac68k_machine.via2_ipl);
    213 	} else {	/* RBV */
    214 #ifdef DISABLE_EXT_CACHE
    215 		if (current_mac_model->class == MACH_CLASSIIci) {
    216 			/*
    217 			 * Disable cache card. (p. 174 -- GMFH)
    218 			 */
    219 			via2_reg(rBufB) |= DB2O_CEnable;
    220 		}
    221 #endif
    222 		intr_establish((int (*)(void*))rbv_intr, NULL,
    223 				mac68k_machine.via2_ipl);
    224 		via2itab[1] = rbv_nubus_intr;
    225 		add_nubus_intr(0, slot_ignore, NULL);
    226 	}
    227 }
    228 
    229 /*
    230  * Set the state of the modem serial port's clock source.
    231  */
    232 void
    233 via_set_modem(int onoff)
    234 {
    235 	via_reg(VIA1, vDirA) |= DA1O_vSync;
    236 	if (onoff)
    237 		via_reg(VIA1, vBufA) |= DA1O_vSync;
    238 	else
    239 		via_reg(VIA1, vBufA) &= ~DA1O_vSync;
    240 }
    241 
    242 void
    243 via1_intr(void *intr_arg /* struct clockframe * */)
    244 {
    245 	u_int8_t intbits, bitnum;
    246 	u_int mask;
    247 
    248 	intbits = via_reg(VIA1, vIFR);		/* get interrupts pending */
    249 	intbits &= via_reg(VIA1, vIER);		/* only care about enabled */
    250 
    251 	if (intbits == 0)
    252 		return;
    253 
    254 	/*
    255 	 * Unflag interrupts here.  If we do it after each interrupt,
    256 	 * the MRG ADB hangs up.
    257 	 */
    258 	via_reg(VIA1, vIFR) = intbits;
    259 
    260 	intbits &= 0x7f;
    261 	mask = 1;
    262 	bitnum = 0;
    263 	do {
    264 		if (intbits & mask) {
    265 			/*
    266 			 * We want to pass the clockframe on to
    267 			 * rtclock_intr().
    268 			 */
    269 			void *arg = via1itab[bitnum] == rtclock_intr
    270 			    ? intr_arg : via1iarg[bitnum];
    271 			via1itab[bitnum](arg);
    272 			/* via_reg(VIA1, vIFR) = mask; */
    273 		}
    274 		mask <<= 1;
    275 		++bitnum;
    276 	} while (intbits >= mask);
    277 }
    278 
    279 void
    280 via2_intr(void *intr_arg)
    281 {
    282 	u_int8_t intbits, bitnum;
    283 	u_int mask;
    284 
    285 	intbits = via2_reg(vIFR);		/* get interrupts pending */
    286 	intbits &= via2_reg(vIER);		/* only care about enabled */
    287 
    288 	if (intbits == 0)
    289 		return;
    290 
    291 	via2_reg(vIFR) = intbits;
    292 
    293 	intbits &= 0x7f;
    294 	mask = 1;
    295 	bitnum = 0;
    296 	do {
    297 		if (intbits & mask)
    298 			via2itab[bitnum](via2iarg[bitnum]);
    299 		mask <<= 1;
    300 		++bitnum;
    301 	} while (intbits >= mask);
    302 }
    303 
    304 void
    305 rbv_intr(void *intr_arg)
    306 {
    307 	u_int8_t intbits, bitnum;
    308 	u_int mask;
    309 
    310 	intbits = (via2_reg(vIFR + rIFR) & via2_reg(vIER + rIER));
    311 
    312 	if (intbits == 0)
    313 		return;
    314 
    315 	via2_reg(rIFR) = intbits;
    316 
    317 	intbits &= 0x7f;
    318 	mask = 1;
    319 	bitnum = 0;
    320 	do {
    321 		if (intbits & mask)
    322 			via2itab[bitnum](via2iarg[bitnum]);
    323 		mask <<= 1;
    324 		++bitnum;
    325 	} while (intbits >= mask);
    326 }
    327 
    328 void
    329 oss_intr(void *intr_arg)
    330 {
    331 	u_int8_t intbits, bitnum;
    332 	u_int mask;
    333 
    334 	intbits = via2_reg(vIFR + rIFR);
    335 
    336 	if (intbits == 0)
    337 		return;
    338 
    339 	intbits &= 0x7f;
    340 	mask = 1;
    341 	bitnum = 0;
    342 	do {
    343 		if (intbits & mask) {
    344 			(*slotitab[bitnum])(slotptab[bitnum]);
    345 			via2_reg(rIFR) = mask;
    346 		}
    347 		mask <<= 1;
    348 		++bitnum;
    349 	} while (intbits >= mask);
    350 }
    351 
    352 static void
    353 via1_noint(void *bitnum)
    354 {
    355 	printf("via1_noint(%d)\n", (int)bitnum);
    356 }
    357 
    358 static void
    359 via2_noint(void *bitnum)
    360 {
    361 	printf("via2_noint(%d)\n", (int)bitnum);
    362 }
    363 
    364 int
    365 add_nubus_intr(int slot, void (*func)(void *), void *client_data)
    366 {
    367 	int	s;
    368 
    369 	/*
    370 	 * Map Nubus slot 0 to "slot" 15; see note on Nubus slot
    371 	 * interrupt tables.
    372 	 */
    373 	if (slot == 0)
    374 		slot = 15;
    375 	if (slot < 9 || slot > 15)
    376 		return 0;
    377 
    378 	s = splhigh();
    379 
    380 	if (func == NULL) {
    381 		slotitab[slot - 9] = slot_noint;
    382 		nubus_intr_mask &= ~(1 << (slot - 9));
    383 	} else {
    384 		slotitab[slot - 9] = func;
    385 		nubus_intr_mask |= (1 << (slot - 9));
    386 	}
    387 	if (client_data == NULL)
    388 		slotptab[slot - 9] = (void *)(slot - 9);
    389 	else
    390 		slotptab[slot - 9] = client_data;
    391 
    392 	splx(s);
    393 
    394 	return 1;
    395 }
    396 
    397 void
    398 enable_nubus_intr(void)
    399 {
    400 	if ((nubus_intr_mask & 0x3f) == 0)
    401 		return;
    402 
    403 	if (VIA2 == VIA2OFF)
    404 		via2_reg(vIER) = 0x80 | V2IF_SLOTINT;
    405 	else
    406 		via2_reg(rIER) = 0x80 | V2IF_SLOTINT;
    407 }
    408 
    409 /*ARGSUSED*/
    410 void
    411 via2_nubus_intr(void *bitarg)
    412 {
    413 	u_int8_t i, intbits, mask;
    414 
    415 	via2_reg(vIFR) = V2IF_SLOTINT;
    416 	while ((intbits = (~via2_reg(vBufA)) & nubus_intr_mask)) {
    417 		i = 6;
    418 		mask = (1 << i);
    419 		do {
    420 			if (intbits & mask)
    421 				(*slotitab[i])(slotptab[i]);
    422 			i--;
    423 			mask >>= 1;
    424 		} while (mask);
    425 		via2_reg(vIFR) = V2IF_SLOTINT;
    426 	}
    427 }
    428 
    429 /*ARGSUSED*/
    430 void
    431 rbv_nubus_intr(void *bitarg)
    432 {
    433 	u_int8_t i, intbits, mask;
    434 
    435 	via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
    436 	while ((intbits = (~via2_reg(rBufA)) & via2_reg(rSlotInt))) {
    437 		i = 6;
    438 		mask = (1 << i);
    439 		do {
    440 			if (intbits & mask)
    441 				(*slotitab[i])(slotptab[i]);
    442 			i--;
    443 			mask >>= 1;
    444 		} while (mask);
    445 		via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
    446 	}
    447 }
    448 
    449 static void
    450 slot_ignore(void *client_data)
    451 {
    452 	int mask = (1 << (int)client_data);
    453 
    454 	if (VIA2 == VIA2OFF) {
    455 		via2_reg(vDirA) |= mask;
    456 		via2_reg(vBufA) = mask;
    457 		via2_reg(vDirA) &= ~mask;
    458 	} else
    459 		via2_reg(rBufA) = mask;
    460 }
    461 
    462 static void
    463 slot_noint(void *client_data)
    464 {
    465 	int slot = (int)client_data + 9;
    466 
    467 	printf("slot_noint() slot %x\n", slot);
    468 
    469 	/* attempt to clear the interrupt */
    470 	slot_ignore(client_data);
    471 }
    472 
    473 void
    474 via_powerdown(void)
    475 {
    476 	if (VIA2 == VIA2OFF) {
    477 		via2_reg(vDirB) |= 0x04;  /* Set write for bit 2 */
    478 		via2_reg(vBufB) &= ~0x04; /* Shut down */
    479 	} else if (VIA2 == RBVOFF) {
    480 		via2_reg(rBufB) &= ~0x04;
    481 	} else if (VIA2 == OSSOFF) {
    482 		/*
    483 		 * Thanks to Brad Boyer <flar (at) cegt201.bradley.edu> for the
    484 		 * Linux/mac68k code that I derived this from.
    485 		 */
    486 		via2_reg(OSS_oRCR) |= OSS_POWEROFF;
    487 	}
    488 }
    489 
    490 void
    491 via1_register_irq(int irq, void (*irq_func)(void *), void *client_data)
    492 {
    493 	if (irq_func) {
    494  		via1itab[irq] = irq_func;
    495  		via1iarg[irq] = client_data;
    496 	} else {
    497  		via1itab[irq] = via1_noint;
    498  		via1iarg[irq] = (void *)0;
    499 	}
    500 }
    501 
    502 void
    503 via2_register_irq(int irq, void (*irq_func)(void *), void *client_data)
    504 {
    505 	if (irq_func) {
    506  		via2itab[irq] = irq_func;
    507 		via2iarg[irq] = client_data;
    508 	} else {
    509  		via2itab[irq] = via2_noint;
    510 		via2iarg[irq] = (void *)0;
    511 	}
    512 }
    513