xref: /OK3568_Linux_fs/kernel/arch/m68k/mac/via.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *	6522 Versatile Interface Adapter (VIA)
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *	There are two of these on the Mac II. Some IRQs are vectored
6*4882a593Smuzhiyun  *	via them as are assorted bits and bobs - eg RTC, ADB.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * CSA: Motorola seems to have removed documentation on the 6522 from
9*4882a593Smuzhiyun  * their web site; try
10*4882a593Smuzhiyun  *     http://nerini.drf.com/vectrex/other/text/chips/6522/
11*4882a593Smuzhiyun  *     http://www.zymurgy.net/classic/vic20/vicdet1.htm
12*4882a593Smuzhiyun  * and
13*4882a593Smuzhiyun  *     http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html
14*4882a593Smuzhiyun  * for info.  A full-text web search on 6522 AND VIA will probably also
15*4882a593Smuzhiyun  * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * Additional data is here (the SY6522 was used in the Mac II etc):
18*4882a593Smuzhiyun  *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf
19*4882a593Smuzhiyun  *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
22*4882a593Smuzhiyun  * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <linux/clocksource.h>
27*4882a593Smuzhiyun #include <linux/types.h>
28*4882a593Smuzhiyun #include <linux/kernel.h>
29*4882a593Smuzhiyun #include <linux/mm.h>
30*4882a593Smuzhiyun #include <linux/delay.h>
31*4882a593Smuzhiyun #include <linux/init.h>
32*4882a593Smuzhiyun #include <linux/module.h>
33*4882a593Smuzhiyun #include <linux/irq.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #include <asm/macintosh.h>
36*4882a593Smuzhiyun #include <asm/macints.h>
37*4882a593Smuzhiyun #include <asm/mac_via.h>
38*4882a593Smuzhiyun #include <asm/mac_psc.h>
39*4882a593Smuzhiyun #include <asm/mac_oss.h>
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun volatile __u8 *via1, *via2;
42*4882a593Smuzhiyun int rbv_present;
43*4882a593Smuzhiyun int via_alt_mapping;
44*4882a593Smuzhiyun EXPORT_SYMBOL(via_alt_mapping);
45*4882a593Smuzhiyun static __u8 rbv_clear;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun  * Globals for accessing the VIA chip registers without having to
49*4882a593Smuzhiyun  * check if we're hitting a real VIA or an RBV. Normally you could
50*4882a593Smuzhiyun  * just hit the combined register (ie, vIER|rIER) but that seems to
51*4882a593Smuzhiyun  * break on AV Macs...probably because they actually decode more than
52*4882a593Smuzhiyun  * eight address bits. Why can't Apple engineers at least be
53*4882a593Smuzhiyun  * _consistently_ lazy?                          - 1999-05-21 (jmt)
54*4882a593Smuzhiyun  */
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun static int gIER,gIFR,gBufA,gBufB;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * On Macs with a genuine VIA chip there is no way to mask an individual slot
60*4882a593Smuzhiyun  * interrupt. This limitation also seems to apply to VIA clone logic cores in
61*4882a593Smuzhiyun  * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.)
62*4882a593Smuzhiyun  *
63*4882a593Smuzhiyun  * We used to fake it by configuring the relevant VIA pin as an output
64*4882a593Smuzhiyun  * (to mask the interrupt) or input (to unmask). That scheme did not work on
65*4882a593Smuzhiyun  * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector
66*4882a593Smuzhiyun  * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE,
67*4882a593Smuzhiyun  * p. 10-11 etc) but VIA outputs are not (see datasheet).
68*4882a593Smuzhiyun  *
69*4882a593Smuzhiyun  * Driving these outputs high must cause the VIA to source current and the
70*4882a593Smuzhiyun  * card to sink current when it asserts /NMRQ. Current will flow but the pin
71*4882a593Smuzhiyun  * voltage is uncertain and so the /NMRQ condition may still cause a transition
72*4882a593Smuzhiyun  * at the VIA2 CA1 input (which explains the lost interrupts). A side effect
73*4882a593Smuzhiyun  * is that a disabled slot IRQ can never be tested as pending or not.
74*4882a593Smuzhiyun  *
75*4882a593Smuzhiyun  * Driving these outputs low doesn't work either. All the slot /NMRQ lines are
76*4882a593Smuzhiyun  * (active low) OR'd together to generate the CA1 (aka "SLOTS") interrupt (see
77*4882a593Smuzhiyun  * The Guide To Macintosh Family Hardware, 2nd edition p. 167). If we drive a
78*4882a593Smuzhiyun  * disabled /NMRQ line low, the falling edge immediately triggers a CA1
79*4882a593Smuzhiyun  * interrupt and all slot interrupts after that will generate no transition
80*4882a593Smuzhiyun  * and therefore no interrupt, even after being re-enabled.
81*4882a593Smuzhiyun  *
82*4882a593Smuzhiyun  * So we make the VIA port A I/O lines inputs and use nubus_disabled to keep
83*4882a593Smuzhiyun  * track of their states. When any slot IRQ becomes disabled we mask the CA1
84*4882a593Smuzhiyun  * umbrella interrupt. Only when all slot IRQs become enabled do we unmask
85*4882a593Smuzhiyun  * the CA1 interrupt. It must remain enabled even when cards have no interrupt
86*4882a593Smuzhiyun  * handler registered. Drivers must therefore disable a slot interrupt at the
87*4882a593Smuzhiyun  * device before they call free_irq (like shared and autovector interrupts).
88*4882a593Smuzhiyun  *
89*4882a593Smuzhiyun  * There is also a related problem when MacOS is used to boot Linux. A network
90*4882a593Smuzhiyun  * card brought up by a MacOS driver may raise an interrupt while Linux boots.
91*4882a593Smuzhiyun  * This can be fatal since it can't be handled until the right driver loads
92*4882a593Smuzhiyun  * (if such a driver exists at all). Apparently related to this hardware
93*4882a593Smuzhiyun  * limitation, "Designing Cards and Drivers", p. 9-8, says that a slot
94*4882a593Smuzhiyun  * interrupt with no driver would crash MacOS (the book was written before
95*4882a593Smuzhiyun  * the appearance of Macs with RBV or OSS).
96*4882a593Smuzhiyun  */
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun static u8 nubus_disabled;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun void via_debug_dump(void);
101*4882a593Smuzhiyun static void via_nubus_init(void);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * Initialize the VIAs
105*4882a593Smuzhiyun  *
106*4882a593Smuzhiyun  * First we figure out where they actually _are_ as well as what type of
107*4882a593Smuzhiyun  * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.)
108*4882a593Smuzhiyun  * Then we pretty much clear them out and disable all IRQ sources.
109*4882a593Smuzhiyun  */
110*4882a593Smuzhiyun 
via_init(void)111*4882a593Smuzhiyun void __init via_init(void)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	via1 = (void *)VIA1_BASE;
114*4882a593Smuzhiyun 	pr_debug("VIA1 detected at %p\n", via1);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (oss_present) {
117*4882a593Smuzhiyun 		via2 = NULL;
118*4882a593Smuzhiyun 		rbv_present = 0;
119*4882a593Smuzhiyun 	} else {
120*4882a593Smuzhiyun 		switch (macintosh_config->via_type) {
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		/* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 		case MAC_VIA_IICI:
125*4882a593Smuzhiyun 			via2 = (void *)RBV_BASE;
126*4882a593Smuzhiyun 			pr_debug("VIA2 (RBV) detected at %p\n", via2);
127*4882a593Smuzhiyun 			rbv_present = 1;
128*4882a593Smuzhiyun 			if (macintosh_config->ident == MAC_MODEL_LCIII) {
129*4882a593Smuzhiyun 				rbv_clear = 0x00;
130*4882a593Smuzhiyun 			} else {
131*4882a593Smuzhiyun 				/* on most RBVs (& unlike the VIAs), you   */
132*4882a593Smuzhiyun 				/* need to set bit 7 when you write to IFR */
133*4882a593Smuzhiyun 				/* in order for your clear to occur.       */
134*4882a593Smuzhiyun 				rbv_clear = 0x80;
135*4882a593Smuzhiyun 			}
136*4882a593Smuzhiyun 			gIER = rIER;
137*4882a593Smuzhiyun 			gIFR = rIFR;
138*4882a593Smuzhiyun 			gBufA = rSIFR;
139*4882a593Smuzhiyun 			gBufB = rBufB;
140*4882a593Smuzhiyun 			break;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 		/* Quadra and early MacIIs agree on the VIA locations */
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		case MAC_VIA_QUADRA:
145*4882a593Smuzhiyun 		case MAC_VIA_II:
146*4882a593Smuzhiyun 			via2 = (void *) VIA2_BASE;
147*4882a593Smuzhiyun 			pr_debug("VIA2 detected at %p\n", via2);
148*4882a593Smuzhiyun 			rbv_present = 0;
149*4882a593Smuzhiyun 			rbv_clear = 0x00;
150*4882a593Smuzhiyun 			gIER = vIER;
151*4882a593Smuzhiyun 			gIFR = vIFR;
152*4882a593Smuzhiyun 			gBufA = vBufA;
153*4882a593Smuzhiyun 			gBufB = vBufB;
154*4882a593Smuzhiyun 			break;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 		default:
157*4882a593Smuzhiyun 			panic("UNKNOWN VIA TYPE");
158*4882a593Smuzhiyun 		}
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun #ifdef DEBUG_VIA
162*4882a593Smuzhiyun 	via_debug_dump();
163*4882a593Smuzhiyun #endif
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/*
166*4882a593Smuzhiyun 	 * Shut down all IRQ sources, reset the timers, and
167*4882a593Smuzhiyun 	 * kill the timer latch on VIA1.
168*4882a593Smuzhiyun 	 */
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	via1[vIER] = 0x7F;
171*4882a593Smuzhiyun 	via1[vIFR] = 0x7F;
172*4882a593Smuzhiyun 	via1[vT1LL] = 0;
173*4882a593Smuzhiyun 	via1[vT1LH] = 0;
174*4882a593Smuzhiyun 	via1[vT1CL] = 0;
175*4882a593Smuzhiyun 	via1[vT1CH] = 0;
176*4882a593Smuzhiyun 	via1[vT2CL] = 0;
177*4882a593Smuzhiyun 	via1[vT2CH] = 0;
178*4882a593Smuzhiyun 	via1[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
179*4882a593Smuzhiyun 	via1[vACR] &= ~0x03; /* disable port A & B latches */
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	/*
182*4882a593Smuzhiyun 	 * SE/30: disable video IRQ
183*4882a593Smuzhiyun 	 */
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (macintosh_config->ident == MAC_MODEL_SE30) {
186*4882a593Smuzhiyun 		via1[vDirB] |= 0x40;
187*4882a593Smuzhiyun 		via1[vBufB] |= 0x40;
188*4882a593Smuzhiyun 	}
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	switch (macintosh_config->adb_type) {
191*4882a593Smuzhiyun 	case MAC_ADB_IOP:
192*4882a593Smuzhiyun 	case MAC_ADB_II:
193*4882a593Smuzhiyun 	case MAC_ADB_PB1:
194*4882a593Smuzhiyun 		/*
195*4882a593Smuzhiyun 		 * Set the RTC bits to a known state: all lines to outputs and
196*4882a593Smuzhiyun 		 * RTC disabled (yes that's 0 to enable and 1 to disable).
197*4882a593Smuzhiyun 		 */
198*4882a593Smuzhiyun 		via1[vDirB] |= VIA1B_vRTCEnb | VIA1B_vRTCClk | VIA1B_vRTCData;
199*4882a593Smuzhiyun 		via1[vBufB] |= VIA1B_vRTCEnb | VIA1B_vRTCClk;
200*4882a593Smuzhiyun 		break;
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/* Everything below this point is VIA2/RBV only... */
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if (oss_present)
206*4882a593Smuzhiyun 		return;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	if ((macintosh_config->via_type == MAC_VIA_QUADRA) &&
209*4882a593Smuzhiyun 	    (macintosh_config->adb_type != MAC_ADB_PB1) &&
210*4882a593Smuzhiyun 	    (macintosh_config->adb_type != MAC_ADB_PB2) &&
211*4882a593Smuzhiyun 	    (macintosh_config->ident    != MAC_MODEL_C660) &&
212*4882a593Smuzhiyun 	    (macintosh_config->ident    != MAC_MODEL_Q840)) {
213*4882a593Smuzhiyun 		via_alt_mapping = 1;
214*4882a593Smuzhiyun 		via1[vDirB] |= 0x40;
215*4882a593Smuzhiyun 		via1[vBufB] &= ~0x40;
216*4882a593Smuzhiyun 	} else {
217*4882a593Smuzhiyun 		via_alt_mapping = 0;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/*
221*4882a593Smuzhiyun 	 * Now initialize VIA2. For RBV we just kill all interrupts;
222*4882a593Smuzhiyun 	 * for a regular VIA we also reset the timers and stuff.
223*4882a593Smuzhiyun 	 */
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	via2[gIER] = 0x7F;
226*4882a593Smuzhiyun 	via2[gIFR] = 0x7F | rbv_clear;
227*4882a593Smuzhiyun 	if (!rbv_present) {
228*4882a593Smuzhiyun 		via2[vT1LL] = 0;
229*4882a593Smuzhiyun 		via2[vT1LH] = 0;
230*4882a593Smuzhiyun 		via2[vT1CL] = 0;
231*4882a593Smuzhiyun 		via2[vT1CH] = 0;
232*4882a593Smuzhiyun 		via2[vT2CL] = 0;
233*4882a593Smuzhiyun 		via2[vT2CH] = 0;
234*4882a593Smuzhiyun 		via2[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
235*4882a593Smuzhiyun 		via2[vACR] &= ~0x03; /* disable port A & B latches */
236*4882a593Smuzhiyun 	}
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	via_nubus_init();
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	/* Everything below this point is VIA2 only... */
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (rbv_present)
243*4882a593Smuzhiyun 		return;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	/*
246*4882a593Smuzhiyun 	 * Set vPCR for control line interrupts.
247*4882a593Smuzhiyun 	 *
248*4882a593Smuzhiyun 	 * CA1 (SLOTS IRQ), CB1 (ASC IRQ): negative edge trigger.
249*4882a593Smuzhiyun 	 *
250*4882a593Smuzhiyun 	 * Macs with ESP SCSI have a negative edge triggered SCSI interrupt.
251*4882a593Smuzhiyun 	 * Testing reveals that PowerBooks do too. However, the SE/30
252*4882a593Smuzhiyun 	 * schematic diagram shows an active high NCR5380 IRQ line.
253*4882a593Smuzhiyun 	 */
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	pr_debug("VIA2 vPCR is 0x%02X\n", via2[vPCR]);
256*4882a593Smuzhiyun 	if (macintosh_config->via_type == MAC_VIA_II) {
257*4882a593Smuzhiyun 		/* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, pos. edge */
258*4882a593Smuzhiyun 		via2[vPCR] = 0x66;
259*4882a593Smuzhiyun 	} else {
260*4882a593Smuzhiyun 		/* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, neg. edge */
261*4882a593Smuzhiyun 		via2[vPCR] = 0x22;
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun /*
266*4882a593Smuzhiyun  * Debugging dump, used in various places to see what's going on.
267*4882a593Smuzhiyun  */
268*4882a593Smuzhiyun 
via_debug_dump(void)269*4882a593Smuzhiyun void via_debug_dump(void)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
272*4882a593Smuzhiyun 		(uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
273*4882a593Smuzhiyun 	printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
274*4882a593Smuzhiyun 		(uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
275*4882a593Smuzhiyun 	if (!via2)
276*4882a593Smuzhiyun 		return;
277*4882a593Smuzhiyun 	if (rbv_present) {
278*4882a593Smuzhiyun 		printk(KERN_DEBUG "VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
279*4882a593Smuzhiyun 			(uint) via2[rIFR], (uint) via2[rIER]);
280*4882a593Smuzhiyun 		printk(KERN_DEBUG "      SIFR = 0x%02X SIER = 0x%02X\n",
281*4882a593Smuzhiyun 			(uint) via2[rSIFR], (uint) via2[rSIER]);
282*4882a593Smuzhiyun 	} else {
283*4882a593Smuzhiyun 		printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
284*4882a593Smuzhiyun 			(uint) via2[vDirA], (uint) via2[vDirB],
285*4882a593Smuzhiyun 			(uint) via2[vACR]);
286*4882a593Smuzhiyun 		printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
287*4882a593Smuzhiyun 			(uint) via2[vPCR],
288*4882a593Smuzhiyun 			(uint) via2[vIFR], (uint) via2[vIER]);
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun /*
293*4882a593Smuzhiyun  * Flush the L2 cache on Macs that have it by flipping
294*4882a593Smuzhiyun  * the system into 24-bit mode for an instant.
295*4882a593Smuzhiyun  */
296*4882a593Smuzhiyun 
via_l2_flush(int writeback)297*4882a593Smuzhiyun void via_l2_flush(int writeback)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	unsigned long flags;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	local_irq_save(flags);
302*4882a593Smuzhiyun 	via2[gBufB] &= ~VIA2B_vMode32;
303*4882a593Smuzhiyun 	via2[gBufB] |= VIA2B_vMode32;
304*4882a593Smuzhiyun 	local_irq_restore(flags);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun /*
308*4882a593Smuzhiyun  * Return the status of the L2 cache on a IIci
309*4882a593Smuzhiyun  */
310*4882a593Smuzhiyun 
via_get_cache_disable(void)311*4882a593Smuzhiyun int via_get_cache_disable(void)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	/* Safeguard against being called accidentally */
314*4882a593Smuzhiyun 	if (!via2) {
315*4882a593Smuzhiyun 		printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n");
316*4882a593Smuzhiyun 		return 1;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	return (int) via2[gBufB] & VIA2B_vCDis;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun /*
323*4882a593Smuzhiyun  * Initialize VIA2 for Nubus access
324*4882a593Smuzhiyun  */
325*4882a593Smuzhiyun 
via_nubus_init(void)326*4882a593Smuzhiyun static void __init via_nubus_init(void)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	/* unlock nubus transactions */
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
331*4882a593Smuzhiyun 	    (macintosh_config->adb_type != MAC_ADB_PB2)) {
332*4882a593Smuzhiyun 		/* set the line to be an output on non-RBV machines */
333*4882a593Smuzhiyun 		if (!rbv_present)
334*4882a593Smuzhiyun 			via2[vDirB] |= 0x02;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 		/* this seems to be an ADB bit on PMU machines */
337*4882a593Smuzhiyun 		/* according to MkLinux.  -- jmt               */
338*4882a593Smuzhiyun 		via2[gBufB] |= 0x02;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	/*
342*4882a593Smuzhiyun 	 * Disable the slot interrupts. On some hardware that's not possible.
343*4882a593Smuzhiyun 	 * On some hardware it's unclear what all of these I/O lines do.
344*4882a593Smuzhiyun 	 */
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	switch (macintosh_config->via_type) {
347*4882a593Smuzhiyun 	case MAC_VIA_II:
348*4882a593Smuzhiyun 	case MAC_VIA_QUADRA:
349*4882a593Smuzhiyun 		pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]);
350*4882a593Smuzhiyun 		break;
351*4882a593Smuzhiyun 	case MAC_VIA_IICI:
352*4882a593Smuzhiyun 		/* RBV. Disable all the slot interrupts. SIER works like IER. */
353*4882a593Smuzhiyun 		via2[rSIER] = 0x7F;
354*4882a593Smuzhiyun 		break;
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
via_nubus_irq_startup(int irq)358*4882a593Smuzhiyun void via_nubus_irq_startup(int irq)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	int irq_idx = IRQ_IDX(irq);
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	switch (macintosh_config->via_type) {
363*4882a593Smuzhiyun 	case MAC_VIA_II:
364*4882a593Smuzhiyun 	case MAC_VIA_QUADRA:
365*4882a593Smuzhiyun 		/* Make the port A line an input. Probably redundant. */
366*4882a593Smuzhiyun 		if (macintosh_config->via_type == MAC_VIA_II) {
367*4882a593Smuzhiyun 			/* The top two bits are RAM size outputs. */
368*4882a593Smuzhiyun 			via2[vDirA] &= 0xC0 | ~(1 << irq_idx);
369*4882a593Smuzhiyun 		} else {
370*4882a593Smuzhiyun 			/* Allow NuBus slots 9 through F. */
371*4882a593Smuzhiyun 			via2[vDirA] &= 0x80 | ~(1 << irq_idx);
372*4882a593Smuzhiyun 		}
373*4882a593Smuzhiyun 		fallthrough;
374*4882a593Smuzhiyun 	case MAC_VIA_IICI:
375*4882a593Smuzhiyun 		via_irq_enable(irq);
376*4882a593Smuzhiyun 		break;
377*4882a593Smuzhiyun 	}
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
via_nubus_irq_shutdown(int irq)380*4882a593Smuzhiyun void via_nubus_irq_shutdown(int irq)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	switch (macintosh_config->via_type) {
383*4882a593Smuzhiyun 	case MAC_VIA_II:
384*4882a593Smuzhiyun 	case MAC_VIA_QUADRA:
385*4882a593Smuzhiyun 		/* Ensure that the umbrella CA1 interrupt remains enabled. */
386*4882a593Smuzhiyun 		via_irq_enable(irq);
387*4882a593Smuzhiyun 		break;
388*4882a593Smuzhiyun 	case MAC_VIA_IICI:
389*4882a593Smuzhiyun 		via_irq_disable(irq);
390*4882a593Smuzhiyun 		break;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun /*
395*4882a593Smuzhiyun  * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
396*4882a593Smuzhiyun  * via6522.c :-), disable/pending masks added.
397*4882a593Smuzhiyun  */
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun #define VIA_TIMER_1_INT BIT(6)
400*4882a593Smuzhiyun 
via1_irq(struct irq_desc * desc)401*4882a593Smuzhiyun void via1_irq(struct irq_desc *desc)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	int irq_num;
404*4882a593Smuzhiyun 	unsigned char irq_bit, events;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	events = via1[vIFR] & via1[vIER] & 0x7F;
407*4882a593Smuzhiyun 	if (!events)
408*4882a593Smuzhiyun 		return;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	irq_num = IRQ_MAC_TIMER_1;
411*4882a593Smuzhiyun 	irq_bit = VIA_TIMER_1_INT;
412*4882a593Smuzhiyun 	if (events & irq_bit) {
413*4882a593Smuzhiyun 		unsigned long flags;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 		local_irq_save(flags);
416*4882a593Smuzhiyun 		via1[vIFR] = irq_bit;
417*4882a593Smuzhiyun 		generic_handle_irq(irq_num);
418*4882a593Smuzhiyun 		local_irq_restore(flags);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 		events &= ~irq_bit;
421*4882a593Smuzhiyun 		if (!events)
422*4882a593Smuzhiyun 			return;
423*4882a593Smuzhiyun 	}
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	irq_num = VIA1_SOURCE_BASE;
426*4882a593Smuzhiyun 	irq_bit = 1;
427*4882a593Smuzhiyun 	do {
428*4882a593Smuzhiyun 		if (events & irq_bit) {
429*4882a593Smuzhiyun 			via1[vIFR] = irq_bit;
430*4882a593Smuzhiyun 			generic_handle_irq(irq_num);
431*4882a593Smuzhiyun 		}
432*4882a593Smuzhiyun 		++irq_num;
433*4882a593Smuzhiyun 		irq_bit <<= 1;
434*4882a593Smuzhiyun 	} while (events >= irq_bit);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
via2_irq(struct irq_desc * desc)437*4882a593Smuzhiyun static void via2_irq(struct irq_desc *desc)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	int irq_num;
440*4882a593Smuzhiyun 	unsigned char irq_bit, events;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	events = via2[gIFR] & via2[gIER] & 0x7F;
443*4882a593Smuzhiyun 	if (!events)
444*4882a593Smuzhiyun 		return;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	irq_num = VIA2_SOURCE_BASE;
447*4882a593Smuzhiyun 	irq_bit = 1;
448*4882a593Smuzhiyun 	do {
449*4882a593Smuzhiyun 		if (events & irq_bit) {
450*4882a593Smuzhiyun 			via2[gIFR] = irq_bit | rbv_clear;
451*4882a593Smuzhiyun 			generic_handle_irq(irq_num);
452*4882a593Smuzhiyun 		}
453*4882a593Smuzhiyun 		++irq_num;
454*4882a593Smuzhiyun 		irq_bit <<= 1;
455*4882a593Smuzhiyun 	} while (events >= irq_bit);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun /*
459*4882a593Smuzhiyun  * Dispatch Nubus interrupts. We are called as a secondary dispatch by the
460*4882a593Smuzhiyun  * VIA2 dispatcher as a fast interrupt handler.
461*4882a593Smuzhiyun  */
462*4882a593Smuzhiyun 
via_nubus_irq(struct irq_desc * desc)463*4882a593Smuzhiyun static void via_nubus_irq(struct irq_desc *desc)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	int slot_irq;
466*4882a593Smuzhiyun 	unsigned char slot_bit, events;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	events = ~via2[gBufA] & 0x7F;
469*4882a593Smuzhiyun 	if (rbv_present)
470*4882a593Smuzhiyun 		events &= via2[rSIER];
471*4882a593Smuzhiyun 	else
472*4882a593Smuzhiyun 		events &= ~via2[vDirA];
473*4882a593Smuzhiyun 	if (!events)
474*4882a593Smuzhiyun 		return;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	do {
477*4882a593Smuzhiyun 		slot_irq = IRQ_NUBUS_F;
478*4882a593Smuzhiyun 		slot_bit = 0x40;
479*4882a593Smuzhiyun 		do {
480*4882a593Smuzhiyun 			if (events & slot_bit) {
481*4882a593Smuzhiyun 				events &= ~slot_bit;
482*4882a593Smuzhiyun 				generic_handle_irq(slot_irq);
483*4882a593Smuzhiyun 			}
484*4882a593Smuzhiyun 			--slot_irq;
485*4882a593Smuzhiyun 			slot_bit >>= 1;
486*4882a593Smuzhiyun 		} while (events);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun  		/* clear the CA1 interrupt and make certain there's no more. */
489*4882a593Smuzhiyun 		via2[gIFR] = 0x02 | rbv_clear;
490*4882a593Smuzhiyun 		events = ~via2[gBufA] & 0x7F;
491*4882a593Smuzhiyun 		if (rbv_present)
492*4882a593Smuzhiyun 			events &= via2[rSIER];
493*4882a593Smuzhiyun 		else
494*4882a593Smuzhiyun 			events &= ~via2[vDirA];
495*4882a593Smuzhiyun 	} while (events);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun /*
499*4882a593Smuzhiyun  * Register the interrupt dispatchers for VIA or RBV machines only.
500*4882a593Smuzhiyun  */
501*4882a593Smuzhiyun 
via_register_interrupts(void)502*4882a593Smuzhiyun void __init via_register_interrupts(void)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun 	if (via_alt_mapping) {
505*4882a593Smuzhiyun 		/* software interrupt */
506*4882a593Smuzhiyun 		irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
507*4882a593Smuzhiyun 		/* via1 interrupt */
508*4882a593Smuzhiyun 		irq_set_chained_handler(IRQ_AUTO_6, via1_irq);
509*4882a593Smuzhiyun 	} else {
510*4882a593Smuzhiyun 		irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
511*4882a593Smuzhiyun 	}
512*4882a593Smuzhiyun 	irq_set_chained_handler(IRQ_AUTO_2, via2_irq);
513*4882a593Smuzhiyun 	irq_set_chained_handler(IRQ_MAC_NUBUS, via_nubus_irq);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
via_irq_enable(int irq)516*4882a593Smuzhiyun void via_irq_enable(int irq) {
517*4882a593Smuzhiyun 	int irq_src	= IRQ_SRC(irq);
518*4882a593Smuzhiyun 	int irq_idx	= IRQ_IDX(irq);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (irq_src == 1) {
521*4882a593Smuzhiyun 		via1[vIER] = IER_SET_BIT(irq_idx);
522*4882a593Smuzhiyun 	} else if (irq_src == 2) {
523*4882a593Smuzhiyun 		if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
524*4882a593Smuzhiyun 			via2[gIER] = IER_SET_BIT(irq_idx);
525*4882a593Smuzhiyun 	} else if (irq_src == 7) {
526*4882a593Smuzhiyun 		switch (macintosh_config->via_type) {
527*4882a593Smuzhiyun 		case MAC_VIA_II:
528*4882a593Smuzhiyun 		case MAC_VIA_QUADRA:
529*4882a593Smuzhiyun 			nubus_disabled &= ~(1 << irq_idx);
530*4882a593Smuzhiyun 			/* Enable the CA1 interrupt when no slot is disabled. */
531*4882a593Smuzhiyun 			if (!nubus_disabled)
532*4882a593Smuzhiyun 				via2[gIER] = IER_SET_BIT(1);
533*4882a593Smuzhiyun 			break;
534*4882a593Smuzhiyun 		case MAC_VIA_IICI:
535*4882a593Smuzhiyun 			/* On RBV, enable the slot interrupt.
536*4882a593Smuzhiyun 			 * SIER works like IER.
537*4882a593Smuzhiyun 			 */
538*4882a593Smuzhiyun 			via2[rSIER] = IER_SET_BIT(irq_idx);
539*4882a593Smuzhiyun 			break;
540*4882a593Smuzhiyun 		}
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
via_irq_disable(int irq)544*4882a593Smuzhiyun void via_irq_disable(int irq) {
545*4882a593Smuzhiyun 	int irq_src	= IRQ_SRC(irq);
546*4882a593Smuzhiyun 	int irq_idx	= IRQ_IDX(irq);
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	if (irq_src == 1) {
549*4882a593Smuzhiyun 		via1[vIER] = IER_CLR_BIT(irq_idx);
550*4882a593Smuzhiyun 	} else if (irq_src == 2) {
551*4882a593Smuzhiyun 		via2[gIER] = IER_CLR_BIT(irq_idx);
552*4882a593Smuzhiyun 	} else if (irq_src == 7) {
553*4882a593Smuzhiyun 		switch (macintosh_config->via_type) {
554*4882a593Smuzhiyun 		case MAC_VIA_II:
555*4882a593Smuzhiyun 		case MAC_VIA_QUADRA:
556*4882a593Smuzhiyun 			nubus_disabled |= 1 << irq_idx;
557*4882a593Smuzhiyun 			if (nubus_disabled)
558*4882a593Smuzhiyun 				via2[gIER] = IER_CLR_BIT(1);
559*4882a593Smuzhiyun 			break;
560*4882a593Smuzhiyun 		case MAC_VIA_IICI:
561*4882a593Smuzhiyun 			via2[rSIER] = IER_CLR_BIT(irq_idx);
562*4882a593Smuzhiyun 			break;
563*4882a593Smuzhiyun 		}
564*4882a593Smuzhiyun 	}
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun 
via1_set_head(int head)567*4882a593Smuzhiyun void via1_set_head(int head)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	if (head == 0)
570*4882a593Smuzhiyun 		via1[vBufA] &= ~VIA1A_vHeadSel;
571*4882a593Smuzhiyun 	else
572*4882a593Smuzhiyun 		via1[vBufA] |= VIA1A_vHeadSel;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun EXPORT_SYMBOL(via1_set_head);
575*4882a593Smuzhiyun 
via2_scsi_drq_pending(void)576*4882a593Smuzhiyun int via2_scsi_drq_pending(void)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ));
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun EXPORT_SYMBOL(via2_scsi_drq_pending);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun /* timer and clock source */
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun #define VIA_CLOCK_FREQ     783360                /* VIA "phase 2" clock in Hz */
585*4882a593Smuzhiyun #define VIA_TIMER_CYCLES   (VIA_CLOCK_FREQ / HZ) /* clock cycles per jiffy */
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun #define VIA_TC             (VIA_TIMER_CYCLES - 2) /* including 0 and -1 */
588*4882a593Smuzhiyun #define VIA_TC_LOW         (VIA_TC & 0xFF)
589*4882a593Smuzhiyun #define VIA_TC_HIGH        (VIA_TC >> 8)
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun static u64 mac_read_clk(struct clocksource *cs);
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun static struct clocksource mac_clk = {
594*4882a593Smuzhiyun 	.name   = "via1",
595*4882a593Smuzhiyun 	.rating = 250,
596*4882a593Smuzhiyun 	.read   = mac_read_clk,
597*4882a593Smuzhiyun 	.mask   = CLOCKSOURCE_MASK(32),
598*4882a593Smuzhiyun 	.flags  = CLOCK_SOURCE_IS_CONTINUOUS,
599*4882a593Smuzhiyun };
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun static u32 clk_total, clk_offset;
602*4882a593Smuzhiyun 
via_timer_handler(int irq,void * dev_id)603*4882a593Smuzhiyun static irqreturn_t via_timer_handler(int irq, void *dev_id)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	irq_handler_t timer_routine = dev_id;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	clk_total += VIA_TIMER_CYCLES;
608*4882a593Smuzhiyun 	clk_offset = 0;
609*4882a593Smuzhiyun 	timer_routine(0, NULL);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	return IRQ_HANDLED;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
via_init_clock(irq_handler_t timer_routine)614*4882a593Smuzhiyun void __init via_init_clock(irq_handler_t timer_routine)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun 	if (request_irq(IRQ_MAC_TIMER_1, via_timer_handler, IRQF_TIMER, "timer",
617*4882a593Smuzhiyun 			timer_routine)) {
618*4882a593Smuzhiyun 		pr_err("Couldn't register %s interrupt\n", "timer");
619*4882a593Smuzhiyun 		return;
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	via1[vT1LL] = VIA_TC_LOW;
623*4882a593Smuzhiyun 	via1[vT1LH] = VIA_TC_HIGH;
624*4882a593Smuzhiyun 	via1[vT1CL] = VIA_TC_LOW;
625*4882a593Smuzhiyun 	via1[vT1CH] = VIA_TC_HIGH;
626*4882a593Smuzhiyun 	via1[vACR] |= 0x40;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	clocksource_register_hz(&mac_clk, VIA_CLOCK_FREQ);
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun 
mac_read_clk(struct clocksource * cs)631*4882a593Smuzhiyun static u64 mac_read_clk(struct clocksource *cs)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun 	unsigned long flags;
634*4882a593Smuzhiyun 	u8 count_high;
635*4882a593Smuzhiyun 	u16 count;
636*4882a593Smuzhiyun 	u32 ticks;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	/*
639*4882a593Smuzhiyun 	 * Timer counter wrap-around is detected with the timer interrupt flag
640*4882a593Smuzhiyun 	 * but reading the counter low byte (vT1CL) would reset the flag.
641*4882a593Smuzhiyun 	 * Also, accessing both counter registers is essentially a data race.
642*4882a593Smuzhiyun 	 * These problems are avoided by ignoring the low byte. Clock accuracy
643*4882a593Smuzhiyun 	 * is 256 times worse (error can reach 0.327 ms) but CPU overhead is
644*4882a593Smuzhiyun 	 * reduced by avoiding slow VIA register accesses.
645*4882a593Smuzhiyun 	 */
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	local_irq_save(flags);
648*4882a593Smuzhiyun 	count_high = via1[vT1CH];
649*4882a593Smuzhiyun 	if (count_high == 0xFF)
650*4882a593Smuzhiyun 		count_high = 0;
651*4882a593Smuzhiyun 	if (count_high > 0 && (via1[vIFR] & VIA_TIMER_1_INT))
652*4882a593Smuzhiyun 		clk_offset = VIA_TIMER_CYCLES;
653*4882a593Smuzhiyun 	count = count_high << 8;
654*4882a593Smuzhiyun 	ticks = VIA_TIMER_CYCLES - count;
655*4882a593Smuzhiyun 	ticks += clk_offset + clk_total;
656*4882a593Smuzhiyun 	local_irq_restore(flags);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	return ticks;
659*4882a593Smuzhiyun }
660