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