diff options
Diffstat (limited to 'arch/m68k/mac/via.c')
-rw-r--r-- | arch/m68k/mac/via.c | 255 |
1 files changed, 122 insertions, 133 deletions
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index f1600ad26621..2d85662715fb 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -63,24 +63,50 @@ static int gIER,gIFR,gBufA,gBufB; #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) -/* To disable a NuBus slot on Quadras we make that slot IRQ line an output set - * high. On RBV we just use the slot interrupt enable register. On Macs with - * genuine VIA chips we must use nubus_disabled to keep track of disabled slot - * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1 - * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt. - * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble, - * because closing one of those drivers can mask all of the NuBus interrupts. - * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's - * possible to get interrupts from cards that MacOS or the ROM has configured - * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and - * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS. + +/* + * On Macs with a genuine VIA chip there is no way to mask an individual slot + * interrupt. This limitation also seems to apply to VIA clone logic cores in + * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.) + * + * We used to fake it by configuring the relevent VIA pin as an output + * (to mask the interrupt) or input (to unmask). That scheme did not work on + * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector + * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE, + * p. 10-11 etc) but VIA outputs are not (see datasheet). + * + * Driving these outputs high must cause the VIA to source current and the + * card to sink current when it asserts /NMRQ. Current will flow but the pin + * voltage is uncertain and so the /NMRQ condition may still cause a transition + * at the VIA2 CA1 input (which explains the lost interrupts). A side effect + * is that a disabled slot IRQ can never be tested as pending or not. + * + * Driving these outputs low doesn't work either. All the slot /NMRQ lines are + * (active low) OR'd together to generate the CA1 (aka "SLOTS") interrupt (see + * The Guide To Macintosh Family Hardware, 2nd edition p. 167). If we drive a + * disabled /NMRQ line low, the falling edge immediately triggers a CA1 + * interrupt and all slot interrupts after that will generate no transition + * and therefore no interrupt, even after being re-enabled. + * + * So we make the VIA port A I/O lines inputs and use nubus_disabled to keep + * track of their states. When any slot IRQ becomes disabled we mask the CA1 + * umbrella interrupt. Only when all slot IRQs become enabled do we unmask + * the CA1 interrupt. It must remain enabled even when cards have no interrupt + * handler registered. Drivers must therefore disable a slot interrupt at the + * device before they call free_irq (like shared and autovector interrupts). + * + * There is also a related problem when MacOS is used to boot Linux. A network + * card brought up by a MacOS driver may raise an interrupt while Linux boots. + * This can be fatal since it can't be handled until the right driver loads + * (if such a driver exists at all). Apparently related to this hardware + * limitation, "Designing Cards and Drivers", p. 9-8, says that a slot + * interrupt with no driver would crash MacOS (the book was written before + * the appearance of Macs with RBV or OSS). */ + static u8 nubus_disabled; void via_debug_dump(void); -void via_irq_enable(int irq); -void via_irq_disable(int irq); -void via_irq_clear(int irq); /* * Initialize the VIAs @@ -100,7 +126,7 @@ void __init via_init(void) /* IIci, IIsi, IIvx, IIvi (P6xx), LC series */ - case MAC_VIA_IIci: + case MAC_VIA_IICI: via1 = (void *) VIA1_BASE; if (macintosh_config->ident == MAC_MODEL_IIFX) { via2 = NULL; @@ -197,38 +223,17 @@ void __init via_init(void) if (oss_present) return; - /* Some machines support an alternate IRQ mapping that spreads */ - /* Ethernet and Sound out to their own autolevel IRQs and moves */ - /* VIA1 to level 6. A/UX uses this mapping and we do too. Note */ - /* that the IIfx emulates this alternate mapping using the OSS. */ - - via_alt_mapping = 0; - if (macintosh_config->via_type == MAC_VIA_QUADRA) - switch (macintosh_config->ident) { - case MAC_MODEL_C660: - case MAC_MODEL_Q840: - /* not applicable */ - break; - case MAC_MODEL_P588: - case MAC_MODEL_TV: - case MAC_MODEL_PB140: - case MAC_MODEL_PB145: - case MAC_MODEL_PB160: - case MAC_MODEL_PB165: - case MAC_MODEL_PB165C: - case MAC_MODEL_PB170: - case MAC_MODEL_PB180: - case MAC_MODEL_PB180C: - case MAC_MODEL_PB190: - case MAC_MODEL_PB520: - /* not yet tested */ - break; - default: - via_alt_mapping = 1; - via1[vDirB] |= 0x40; - via1[vBufB] &= ~0x40; - break; - } + if ((macintosh_config->via_type == MAC_VIA_QUADRA) && + (macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2) && + (macintosh_config->ident != MAC_MODEL_C660) && + (macintosh_config->ident != MAC_MODEL_Q840)) { + via_alt_mapping = 1; + via1[vDirB] |= 0x40; + via1[vBufB] &= ~0x40; + } else { + via_alt_mapping = 0; + } /* * Now initialize VIA2. For RBV we just kill all interrupts; @@ -248,22 +253,28 @@ void __init via_init(void) via2[vACR] &= ~0x03; /* disable port A & B latches */ } + /* Everything below this point is VIA2 only... */ + + if (rbv_present) + return; + /* - * Set vPCR for control line interrupts (but not on RBV) + * Set vPCR for control line interrupts. + * + * CA1 (SLOTS IRQ), CB1 (ASC IRQ): negative edge trigger. + * + * Macs with ESP SCSI have a negative edge triggered SCSI interrupt. + * Testing reveals that PowerBooks do too. However, the SE/30 + * schematic diagram shows an active high NCR5380 IRQ line. */ - if (!rbv_present) { - /* For all VIA types, CA1 (SLOTS IRQ) and CB1 (ASC IRQ) - * are made negative edge triggered here. - */ - if (macintosh_config->scsi_type == MAC_SCSI_OLD) { - /* CB2 (IRQ) indep. input, positive edge */ - /* CA2 (DRQ) indep. input, positive edge */ - via2[vPCR] = 0x66; - } else { - /* CB2 (IRQ) indep. input, negative edge */ - /* CA2 (DRQ) indep. input, negative edge */ - via2[vPCR] = 0x22; - } + + pr_debug("VIA2 vPCR is 0x%02X\n", via2[vPCR]); + if (macintosh_config->via_type == MAC_VIA_II) { + /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, pos. edge */ + via2[vPCR] = 0x66; + } else { + /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, neg. edge */ + via2[vPCR] = 0x22; } } @@ -378,34 +389,55 @@ void __init via_nubus_init(void) via2[gBufB] |= 0x02; } - /* Disable all the slot interrupts (where possible). */ + /* + * Disable the slot interrupts. On some hardware that's not possible. + * On some hardware it's unclear what all of these I/O lines do. + */ switch (macintosh_config->via_type) { case MAC_VIA_II: - /* Just make the port A lines inputs. */ - switch(macintosh_config->ident) { - case MAC_MODEL_II: - case MAC_MODEL_IIX: - case MAC_MODEL_IICX: - case MAC_MODEL_SE30: - /* The top two bits are RAM size outputs. */ - via2[vDirA] &= 0xC0; - break; - default: - via2[vDirA] &= 0x80; - } + case MAC_VIA_QUADRA: + pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]); break; - case MAC_VIA_IIci: + case MAC_VIA_IICI: /* RBV. Disable all the slot interrupts. SIER works like IER. */ via2[rSIER] = 0x7F; break; + } +} + +void via_nubus_irq_startup(int irq) +{ + int irq_idx = IRQ_IDX(irq); + + switch (macintosh_config->via_type) { + case MAC_VIA_II: case MAC_VIA_QUADRA: - /* Disable the inactive slot interrupts by making those lines outputs. */ - if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { - via2[vBufA] |= 0x7F; - via2[vDirA] |= 0x7F; + /* Make the port A line an input. Probably redundant. */ + if (macintosh_config->via_type == MAC_VIA_II) { + /* The top two bits are RAM size outputs. */ + via2[vDirA] &= 0xC0 | ~(1 << irq_idx); + } else { + /* Allow NuBus slots 9 through F. */ + via2[vDirA] &= 0x80 | ~(1 << irq_idx); } + /* fall through */ + case MAC_VIA_IICI: + via_irq_enable(irq); + break; + } +} + +void via_nubus_irq_shutdown(int irq) +{ + switch (macintosh_config->via_type) { + case MAC_VIA_II: + case MAC_VIA_QUADRA: + /* Ensure that the umbrella CA1 interrupt remains enabled. */ + via_irq_enable(irq); + break; + case MAC_VIA_IICI: + via_irq_disable(irq); break; } } @@ -531,25 +563,18 @@ void via_irq_enable(int irq) { } else if (irq_src == 7) { switch (macintosh_config->via_type) { case MAC_VIA_II: + case MAC_VIA_QUADRA: nubus_disabled &= ~(1 << irq_idx); /* Enable the CA1 interrupt when no slot is disabled. */ if (!nubus_disabled) via2[gIER] = IER_SET_BIT(1); break; - case MAC_VIA_IIci: + case MAC_VIA_IICI: /* On RBV, enable the slot interrupt. * SIER works like IER. */ via2[rSIER] = IER_SET_BIT(irq_idx); break; - case MAC_VIA_QUADRA: - /* Make the port A line an input to enable the slot irq. - * But not on PowerBooks, that's ADB. - */ - if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) - via2[vDirA] &= ~(1 << irq_idx); - break; } } } @@ -569,60 +594,18 @@ void via_irq_disable(int irq) { } else if (irq_src == 7) { switch (macintosh_config->via_type) { case MAC_VIA_II: + case MAC_VIA_QUADRA: nubus_disabled |= 1 << irq_idx; if (nubus_disabled) via2[gIER] = IER_CLR_BIT(1); break; - case MAC_VIA_IIci: + case MAC_VIA_IICI: via2[rSIER] = IER_CLR_BIT(irq_idx); break; - case MAC_VIA_QUADRA: - if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) - via2[vDirA] |= 1 << irq_idx; - break; } } } -void via_irq_clear(int irq) { - int irq_src = IRQ_SRC(irq); - int irq_idx = IRQ_IDX(irq); - int irq_bit = 1 << irq_idx; - - if (irq_src == 1) { - via1[vIFR] = irq_bit; - } else if (irq_src == 2) { - via2[gIFR] = irq_bit | rbv_clear; - } else if (irq_src == 7) { - /* FIXME: There is no way to clear an individual nubus slot - * IRQ flag, other than getting the device to do it. - */ - } -} - -/* - * Returns nonzero if an interrupt is pending on the given - * VIA/IRQ combination. - */ - -int via_irq_pending(int irq) -{ - int irq_src = IRQ_SRC(irq); - int irq_idx = IRQ_IDX(irq); - int irq_bit = 1 << irq_idx; - - if (irq_src == 1) { - return via1[vIFR] & irq_bit; - } else if (irq_src == 2) { - return via2[gIFR] & irq_bit; - } else if (irq_src == 7) { - /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */ - return ~via2[gBufA] & irq_bit; - } - return 0; -} - void via1_set_head(int head) { if (head == 0) @@ -631,3 +614,9 @@ void via1_set_head(int head) via1[vBufA] |= VIA1A_vHeadSel; } EXPORT_SYMBOL(via1_set_head); + +int via2_scsi_drq_pending(void) +{ + return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ)); +} +EXPORT_SYMBOL(via2_scsi_drq_pending); |