aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac/via.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mac/via.c')
-rw-r--r--arch/m68k/mac/via.c284
1 files changed, 166 insertions, 118 deletions
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index e27735be2924..d5cac72eb3db 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -13,6 +13,10 @@
13 * for info. A full-text web search on 6522 AND VIA will probably also 13 * for info. A full-text web search on 6522 AND VIA will probably also
14 * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999 14 * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
15 * 15 *
16 * Additional data is here (the SY6522 was used in the Mac II etc):
17 * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf
18 * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf
19 *
16 * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b 20 * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
17 * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org) 21 * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
18 * 22 *
@@ -37,7 +41,7 @@ volatile __u8 *via1, *via2;
37/* See note in mac_via.h about how this is possibly not useful */ 41/* See note in mac_via.h about how this is possibly not useful */
38volatile long *via_memory_bogon=(long *)&via_memory_bogon; 42volatile long *via_memory_bogon=(long *)&via_memory_bogon;
39#endif 43#endif
40int rbv_present,via_alt_mapping; 44int rbv_present, via_alt_mapping;
41__u8 rbv_clear; 45__u8 rbv_clear;
42 46
43/* 47/*
@@ -60,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB;
60#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) 64#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
61#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) 65#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
62 66
63static int nubus_active; 67/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set
68 * high. On RBV we just use the slot interrupt enable register. On Macs with
69 * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
70 * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
71 * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt.
72 * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble,
73 * because closing one of those drivers can mask all of the NuBus interrupts.
74 * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's
75 * possible to get interrupts from cards that MacOS or the ROM has configured
76 * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and
77 * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS.
78 */
79static u8 nubus_disabled;
64 80
65void via_debug_dump(void); 81void via_debug_dump(void);
66irqreturn_t via1_irq(int, void *); 82irqreturn_t via1_irq(int, void *);
@@ -138,11 +154,11 @@ void __init via_init(void)
138 154
139 printk(KERN_INFO "VIA2 at %p is ", via2); 155 printk(KERN_INFO "VIA2 at %p is ", via2);
140 if (rbv_present) { 156 if (rbv_present) {
141 printk(KERN_INFO "an RBV\n"); 157 printk("an RBV\n");
142 } else if (oss_present) { 158 } else if (oss_present) {
143 printk(KERN_INFO "an OSS\n"); 159 printk("an OSS\n");
144 } else { 160 } else {
145 printk(KERN_INFO "a 6522 or clone\n"); 161 printk("a 6522 or clone\n");
146 } 162 }
147 163
148#ifdef DEBUG_VIA 164#ifdef DEBUG_VIA
@@ -163,6 +179,7 @@ void __init via_init(void)
163 via1[vT2CL] = 0; 179 via1[vT2CL] = 0;
164 via1[vT2CH] = 0; 180 via1[vT2CH] = 0;
165 via1[vACR] &= 0x3F; 181 via1[vACR] &= 0x3F;
182 via1[vACR] &= ~0x03; /* disable port A & B latches */
166 183
167 /* 184 /*
168 * SE/30: disable video IRQ 185 * SE/30: disable video IRQ
@@ -193,8 +210,14 @@ void __init via_init(void)
193 /* that the IIfx emulates this alternate mapping using the OSS. */ 210 /* that the IIfx emulates this alternate mapping using the OSS. */
194 211
195 switch(macintosh_config->ident) { 212 switch(macintosh_config->ident) {
213 case MAC_MODEL_P475:
214 case MAC_MODEL_P475F:
215 case MAC_MODEL_P575:
216 case MAC_MODEL_Q605:
217 case MAC_MODEL_Q605_ACC:
196 case MAC_MODEL_C610: 218 case MAC_MODEL_C610:
197 case MAC_MODEL_Q610: 219 case MAC_MODEL_Q610:
220 case MAC_MODEL_Q630:
198 case MAC_MODEL_C650: 221 case MAC_MODEL_C650:
199 case MAC_MODEL_Q650: 222 case MAC_MODEL_Q650:
200 case MAC_MODEL_Q700: 223 case MAC_MODEL_Q700:
@@ -228,6 +251,22 @@ void __init via_init(void)
228 via2[vT2CL] = 0; 251 via2[vT2CL] = 0;
229 via2[vT2CH] = 0; 252 via2[vT2CH] = 0;
230 via2[vACR] &= 0x3F; 253 via2[vACR] &= 0x3F;
254 via2[vACR] &= ~0x03; /* disable port A & B latches */
255 }
256
257 /*
258 * Set vPCR for SCSI interrupts (but not on RBV)
259 */
260 if (!rbv_present) {
261 if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
262 /* CB2 (IRQ) indep. input, positive edge */
263 /* CA2 (DRQ) indep. input, positive edge */
264 via2[vPCR] = 0x66;
265 } else {
266 /* CB2 (IRQ) indep. input, negative edge */
267 /* CA2 (DRQ) indep. input, negative edge */
268 via2[vPCR] = 0x22;
269 }
231 } 270 }
232} 271}
233 272
@@ -356,78 +395,75 @@ int via_get_cache_disable(void)
356 395
357void __init via_nubus_init(void) 396void __init via_nubus_init(void)
358{ 397{
359 /* don't set nubus_active = 0 here, it kills the Baboon */
360 /* interrupt that we've already registered. */
361
362 /* unlock nubus transactions */ 398 /* unlock nubus transactions */
363 399
364 if (!rbv_present) { 400 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
401 (macintosh_config->adb_type != MAC_ADB_PB2)) {
365 /* set the line to be an output on non-RBV machines */ 402 /* set the line to be an output on non-RBV machines */
366 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 403 if (!rbv_present)
367 (macintosh_config->adb_type != MAC_ADB_PB2)) {
368 via2[vDirB] |= 0x02; 404 via2[vDirB] |= 0x02;
369 }
370 }
371 405
372 /* this seems to be an ADB bit on PMU machines */ 406 /* this seems to be an ADB bit on PMU machines */
373 /* according to MkLinux. -- jmt */ 407 /* according to MkLinux. -- jmt */
374
375 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
376 (macintosh_config->adb_type != MAC_ADB_PB2)) {
377 via2[gBufB] |= 0x02; 408 via2[gBufB] |= 0x02;
378 } 409 }
379 410
380 /* disable nubus slot interrupts. */ 411 /* Disable all the slot interrupts (where possible). */
381 if (rbv_present) { 412
413 switch (macintosh_config->via_type) {
414 case MAC_VIA_II:
415 /* Just make the port A lines inputs. */
416 switch(macintosh_config->ident) {
417 case MAC_MODEL_II:
418 case MAC_MODEL_IIX:
419 case MAC_MODEL_IICX:
420 case MAC_MODEL_SE30:
421 /* The top two bits are RAM size outputs. */
422 via2[vDirA] &= 0xC0;
423 break;
424 default:
425 via2[vDirA] &= 0x80;
426 }
427 break;
428 case MAC_VIA_IIci:
429 /* RBV. Disable all the slot interrupts. SIER works like IER. */
382 via2[rSIER] = 0x7F; 430 via2[rSIER] = 0x7F;
383 via2[rSIER] = nubus_active | 0x80; 431 break;
384 } else { 432 case MAC_VIA_QUADRA:
385 /* These are ADB bits on PMU */ 433 /* Disable the inactive slot interrupts by making those lines outputs. */
386 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 434 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
387 (macintosh_config->adb_type != MAC_ADB_PB2)) { 435 (macintosh_config->adb_type != MAC_ADB_PB2)) {
388 switch(macintosh_config->ident) 436 via2[vBufA] |= 0x7F;
389 { 437 via2[vDirA] |= 0x7F;
390 case MAC_MODEL_II:
391 case MAC_MODEL_IIX:
392 case MAC_MODEL_IICX:
393 case MAC_MODEL_SE30:
394 via2[vBufA] |= 0x3F;
395 via2[vDirA] = ~nubus_active | 0xc0;
396 break;
397 default:
398 via2[vBufA] = 0xFF;
399 via2[vDirA] = ~nubus_active;
400 }
401 } 438 }
439 break;
402 } 440 }
403} 441}
404 442
405/* 443/*
406 * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's 444 * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
407 * via6522.c :-), disable/pending masks added. 445 * via6522.c :-), disable/pending masks added.
408 *
409 * The new interrupt architecture in macints.c takes care of a lot of the
410 * gruntwork for us, including tallying the interrupts and calling the
411 * handlers on the linked list. All we need to do here is basically generate
412 * the machspec interrupt number after clearing the interrupt.
413 */ 446 */
414 447
415irqreturn_t via1_irq(int irq, void *dev_id) 448irqreturn_t via1_irq(int irq, void *dev_id)
416{ 449{
417 int irq_bit, i; 450 int irq_num;
418 unsigned char events, mask; 451 unsigned char irq_bit, events;
419 452
420 mask = via1[vIER] & 0x7F; 453 events = via1[vIFR] & via1[vIER] & 0x7F;
421 if (!(events = via1[vIFR] & mask)) 454 if (!events)
422 return IRQ_NONE; 455 return IRQ_NONE;
423 456
424 for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) 457 irq_num = VIA1_SOURCE_BASE;
458 irq_bit = 1;
459 do {
425 if (events & irq_bit) { 460 if (events & irq_bit) {
426 via1[vIER] = irq_bit;
427 m68k_handle_int(VIA1_SOURCE_BASE + i);
428 via1[vIFR] = irq_bit; 461 via1[vIFR] = irq_bit;
429 via1[vIER] = irq_bit | 0x80; 462 m68k_handle_int(irq_num);
430 } 463 }
464 ++irq_num;
465 irq_bit <<= 1;
466 } while (events >= irq_bit);
431 467
432#if 0 /* freakin' pmu is doing weird stuff */ 468#if 0 /* freakin' pmu is doing weird stuff */
433 if (!oss_present) { 469 if (!oss_present) {
@@ -448,20 +484,23 @@ irqreturn_t via1_irq(int irq, void *dev_id)
448 484
449irqreturn_t via2_irq(int irq, void *dev_id) 485irqreturn_t via2_irq(int irq, void *dev_id)
450{ 486{
451 int irq_bit, i; 487 int irq_num;
452 unsigned char events, mask; 488 unsigned char irq_bit, events;
453 489
454 mask = via2[gIER] & 0x7F; 490 events = via2[gIFR] & via2[gIER] & 0x7F;
455 if (!(events = via2[gIFR] & mask)) 491 if (!events)
456 return IRQ_NONE; 492 return IRQ_NONE;
457 493
458 for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) 494 irq_num = VIA2_SOURCE_BASE;
495 irq_bit = 1;
496 do {
459 if (events & irq_bit) { 497 if (events & irq_bit) {
460 via2[gIER] = irq_bit;
461 via2[gIFR] = irq_bit | rbv_clear; 498 via2[gIFR] = irq_bit | rbv_clear;
462 m68k_handle_int(VIA2_SOURCE_BASE + i); 499 m68k_handle_int(irq_num);
463 via2[gIER] = irq_bit | 0x80;
464 } 500 }
501 ++irq_num;
502 irq_bit <<= 1;
503 } while (events >= irq_bit);
465 return IRQ_HANDLED; 504 return IRQ_HANDLED;
466} 505}
467 506
@@ -472,71 +511,75 @@ irqreturn_t via2_irq(int irq, void *dev_id)
472 511
473irqreturn_t via_nubus_irq(int irq, void *dev_id) 512irqreturn_t via_nubus_irq(int irq, void *dev_id)
474{ 513{
475 int irq_bit, i; 514 int slot_irq;
476 unsigned char events; 515 unsigned char slot_bit, events;
477 516
478 if (!(events = ~via2[gBufA] & nubus_active)) 517 events = ~via2[gBufA] & 0x7F;
518 if (rbv_present)
519 events &= via2[rSIER];
520 else
521 events &= ~via2[vDirA];
522 if (!events)
479 return IRQ_NONE; 523 return IRQ_NONE;
480 524
481 for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { 525 do {
482 if (events & irq_bit) { 526 slot_irq = IRQ_NUBUS_F;
483 via_irq_disable(NUBUS_SOURCE_BASE + i); 527 slot_bit = 0x40;
484 m68k_handle_int(NUBUS_SOURCE_BASE + i); 528 do {
485 via_irq_enable(NUBUS_SOURCE_BASE + i); 529 if (events & slot_bit) {
486 } 530 events &= ~slot_bit;
487 } 531 m68k_handle_int(slot_irq);
532 }
533 --slot_irq;
534 slot_bit >>= 1;
535 } while (events);
536
537 /* clear the CA1 interrupt and make certain there's no more. */
538 via2[gIFR] = 0x02 | rbv_clear;
539 events = ~via2[gBufA] & 0x7F;
540 if (rbv_present)
541 events &= via2[rSIER];
542 else
543 events &= ~via2[vDirA];
544 } while (events);
488 return IRQ_HANDLED; 545 return IRQ_HANDLED;
489} 546}
490 547
491void via_irq_enable(int irq) { 548void via_irq_enable(int irq) {
492 int irq_src = IRQ_SRC(irq); 549 int irq_src = IRQ_SRC(irq);
493 int irq_idx = IRQ_IDX(irq); 550 int irq_idx = IRQ_IDX(irq);
494 int irq_bit = 1 << irq_idx;
495 551
496#ifdef DEBUG_IRQUSE 552#ifdef DEBUG_IRQUSE
497 printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); 553 printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
498#endif 554#endif
499 555
500 if (irq_src == 1) { 556 if (irq_src == 1) {
501 via1[vIER] = irq_bit | 0x80; 557 via1[vIER] = IER_SET_BIT(irq_idx);
502 } else if (irq_src == 2) { 558 } else if (irq_src == 2) {
503 /* 559 if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
504 * Set vPCR for SCSI interrupts (but not on RBV) 560 via2[gIER] = IER_SET_BIT(irq_idx);
505 */
506 if ((irq_idx == 0) && !rbv_present) {
507 if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
508 /* CB2 (IRQ) indep. input, positive edge */
509 /* CA2 (DRQ) indep. input, positive edge */
510 via2[vPCR] = 0x66;
511 } else {
512 /* CB2 (IRQ) indep. input, negative edge */
513 /* CA2 (DRQ) indep. input, negative edge */
514 via2[vPCR] = 0x22;
515 }
516 }
517 via2[gIER] = irq_bit | 0x80;
518 } else if (irq_src == 7) { 561 } else if (irq_src == 7) {
519 nubus_active |= irq_bit; 562 switch (macintosh_config->via_type) {
520 if (rbv_present) { 563 case MAC_VIA_II:
521 /* enable the slot interrupt. SIER works like IER. */ 564 nubus_disabled &= ~(1 << irq_idx);
565 /* Enable the CA1 interrupt when no slot is disabled. */
566 if (!nubus_disabled)
567 via2[gIER] = IER_SET_BIT(1);
568 break;
569 case MAC_VIA_IIci:
570 /* On RBV, enable the slot interrupt.
571 * SIER works like IER.
572 */
522 via2[rSIER] = IER_SET_BIT(irq_idx); 573 via2[rSIER] = IER_SET_BIT(irq_idx);
523 } else { 574 break;
524 /* Make sure the bit is an input, to enable the irq */ 575 case MAC_VIA_QUADRA:
525 /* But not on PowerBooks, that's ADB... */ 576 /* Make the port A line an input to enable the slot irq.
577 * But not on PowerBooks, that's ADB.
578 */
526 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 579 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
527 (macintosh_config->adb_type != MAC_ADB_PB2)) { 580 (macintosh_config->adb_type != MAC_ADB_PB2))
528 switch(macintosh_config->ident) 581 via2[vDirA] &= ~(1 << irq_idx);
529 { 582 break;
530 case MAC_MODEL_II:
531 case MAC_MODEL_IIX:
532 case MAC_MODEL_IICX:
533 case MAC_MODEL_SE30:
534 via2[vDirA] &= (~irq_bit | 0xc0);
535 break;
536 default:
537 via2[vDirA] &= ~irq_bit;
538 }
539 }
540 } 583 }
541 } 584 }
542} 585}
@@ -544,29 +587,31 @@ void via_irq_enable(int irq) {
544void via_irq_disable(int irq) { 587void via_irq_disable(int irq) {
545 int irq_src = IRQ_SRC(irq); 588 int irq_src = IRQ_SRC(irq);
546 int irq_idx = IRQ_IDX(irq); 589 int irq_idx = IRQ_IDX(irq);
547 int irq_bit = 1 << irq_idx;
548 590
549#ifdef DEBUG_IRQUSE 591#ifdef DEBUG_IRQUSE
550 printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); 592 printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
551#endif 593#endif
552 594
553 if (irq_src == 1) { 595 if (irq_src == 1) {
554 via1[vIER] = irq_bit; 596 via1[vIER] = IER_CLR_BIT(irq_idx);
555 } else if (irq_src == 2) { 597 } else if (irq_src == 2) {
556 via2[gIER] = irq_bit; 598 via2[gIER] = IER_CLR_BIT(irq_idx);
557 } else if (irq_src == 7) { 599 } else if (irq_src == 7) {
558 if (rbv_present) { 600 switch (macintosh_config->via_type) {
559 /* disable the slot interrupt. SIER works like IER. */ 601 case MAC_VIA_II:
602 nubus_disabled |= 1 << irq_idx;
603 if (nubus_disabled)
604 via2[gIER] = IER_CLR_BIT(1);
605 break;
606 case MAC_VIA_IIci:
560 via2[rSIER] = IER_CLR_BIT(irq_idx); 607 via2[rSIER] = IER_CLR_BIT(irq_idx);
561 } else { 608 break;
562 /* disable the nubus irq by changing dir to output */ 609 case MAC_VIA_QUADRA:
563 /* except on PMU */
564 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 610 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
565 (macintosh_config->adb_type != MAC_ADB_PB2)) { 611 (macintosh_config->adb_type != MAC_ADB_PB2))
566 via2[vDirA] |= irq_bit; 612 via2[vDirA] |= 1 << irq_idx;
567 } 613 break;
568 } 614 }
569 nubus_active &= ~irq_bit;
570 } 615 }
571} 616}
572 617
@@ -580,7 +625,9 @@ void via_irq_clear(int irq) {
580 } else if (irq_src == 2) { 625 } else if (irq_src == 2) {
581 via2[gIFR] = irq_bit | rbv_clear; 626 via2[gIFR] = irq_bit | rbv_clear;
582 } else if (irq_src == 7) { 627 } else if (irq_src == 7) {
583 /* FIXME: hmm.. */ 628 /* FIXME: There is no way to clear an individual nubus slot
629 * IRQ flag, other than getting the device to do it.
630 */
584 } 631 }
585} 632}
586 633
@@ -600,6 +647,7 @@ int via_irq_pending(int irq)
600 } else if (irq_src == 2) { 647 } else if (irq_src == 2) {
601 return via2[gIFR] & irq_bit; 648 return via2[gIFR] & irq_bit;
602 } else if (irq_src == 7) { 649 } else if (irq_src == 7) {
650 /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */
603 return ~via2[gBufA] & irq_bit; 651 return ~via2[gBufA] & irq_bit;
604 } 652 }
605 return 0; 653 return 0;