xref: /linux/arch/m68k/atari/ataints.c (revision 827634added7f38b7d724cab1dccdb2b004c13c3)
1 /*
2  * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code
3  *
4  * 5/2/94 Roman Hodek:
5  *  Added support for TT interrupts; setup for TT SCU (may someone has
6  *  twiddled there and we won't get the right interrupts :-()
7  *
8  *  Major change: The device-independent code in m68k/ints.c didn't know
9  *  about non-autovec ints yet. It hardcoded the number of possible ints to
10  *  7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
11  *  number of possible ints a constant defined in interrupt.h, which is
12  *  47 for the Atari. So we can call request_irq() for all Atari interrupts
13  *  just the normal way. Additionally, all vectors >= 48 are initialized to
14  *  call trap() instead of inthandler(). This must be changed here, too.
15  *
16  * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>:
17  *  Corrected a bug in atari_add_isr() which rejected all SCC
18  *  interrupt sources if there were no TT MFP!
19  *
20  * 12/13/95: New interface functions atari_level_triggered_int() and
21  *  atari_register_vme_int() as support for level triggered VME interrupts.
22  *
23  * 02/12/96: (Roman)
24  *  Total rewrite of Atari interrupt handling, for new scheme see comments
25  *  below.
26  *
27  * 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>:
28  *  Added new function atari_unregister_vme_int(), and
29  *  modified atari_register_vme_int() as well as IS_VALID_INTNO()
30  *  to work with it.
31  *
32  * This file is subject to the terms and conditions of the GNU General Public
33  * License.  See the file COPYING in the main directory of this archive
34  * for more details.
35  *
36  */
37 
38 #include <linux/types.h>
39 #include <linux/kernel.h>
40 #include <linux/kernel_stat.h>
41 #include <linux/init.h>
42 #include <linux/seq_file.h>
43 #include <linux/module.h>
44 #include <linux/irq.h>
45 
46 #include <asm/traps.h>
47 
48 #include <asm/atarihw.h>
49 #include <asm/atariints.h>
50 #include <asm/atari_stdma.h>
51 #include <asm/irq.h>
52 #include <asm/entry.h>
53 #include <asm/io.h>
54 
55 
56 /*
57  * Atari interrupt handling scheme:
58  * --------------------------------
59  *
60  * All interrupt source have an internal number (defined in
61  * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP,
62  * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can
63  * be allocated by atari_register_vme_int().
64  */
65 
66 /*
67  * Bitmap for free interrupt vector numbers
68  * (new vectors starting from 0x70 can be allocated by
69  * atari_register_vme_int())
70  */
71 static int free_vme_vec_bitmap;
72 
73 /* GK:
74  * HBL IRQ handler for Falcon. Nobody needs it :-)
75  * ++andreas: raise ipl to disable further HBLANK interrupts.
76  */
77 asmlinkage void falcon_hblhandler(void);
78 asm(".text\n"
79 __ALIGN_STR "\n\t"
80 "falcon_hblhandler:\n\t"
81 	"orw	#0x200,%sp@\n\t"	/* set saved ipl to 2 */
82 	"rte");
83 
84 extern void atari_microwire_cmd(int cmd);
85 
86 static unsigned int atari_irq_startup(struct irq_data *data)
87 {
88 	unsigned int irq = data->irq;
89 
90 	m68k_irq_startup(data);
91 	atari_turnon_irq(irq);
92 	atari_enable_irq(irq);
93 	return 0;
94 }
95 
96 static void atari_irq_shutdown(struct irq_data *data)
97 {
98 	unsigned int irq = data->irq;
99 
100 	atari_disable_irq(irq);
101 	atari_turnoff_irq(irq);
102 	m68k_irq_shutdown(data);
103 
104 	if (irq == IRQ_AUTO_4)
105 	    vectors[VEC_INT4] = falcon_hblhandler;
106 }
107 
108 static void atari_irq_enable(struct irq_data *data)
109 {
110 	atari_enable_irq(data->irq);
111 }
112 
113 static void atari_irq_disable(struct irq_data *data)
114 {
115 	atari_disable_irq(data->irq);
116 }
117 
118 static struct irq_chip atari_irq_chip = {
119 	.name		= "atari",
120 	.irq_startup	= atari_irq_startup,
121 	.irq_shutdown	= atari_irq_shutdown,
122 	.irq_enable	= atari_irq_enable,
123 	.irq_disable	= atari_irq_disable,
124 };
125 
126 /*
127  * ST-MFP timer D chained interrupts - each driver gets its own timer
128  * interrupt instance.
129  */
130 
131 struct mfptimerbase {
132 	volatile struct MFP *mfp;
133 	unsigned char mfp_mask, mfp_data;
134 	unsigned short int_mask;
135 	int handler_irq, mfptimer_irq, server_irq;
136 	char *name;
137 } stmfp_base = {
138 	.mfp		= &st_mfp,
139 	.int_mask	= 0x0,
140 	.handler_irq	= IRQ_MFP_TIMD,
141 	.mfptimer_irq	= IRQ_MFP_TIMER1,
142 	.name		= "MFP Timer D"
143 };
144 
145 static irqreturn_t mfptimer_handler(int irq, void *dev_id)
146 {
147 	struct mfptimerbase *base = dev_id;
148 	int mach_irq;
149 	unsigned char ints;
150 
151 	mach_irq = base->mfptimer_irq;
152 	ints = base->int_mask;
153 	for (; ints; mach_irq++, ints >>= 1) {
154 		if (ints & 1)
155 			generic_handle_irq(mach_irq);
156 	}
157 	return IRQ_HANDLED;
158 }
159 
160 
161 static void atari_mfptimer_enable(struct irq_data *data)
162 {
163 	int mfp_num = data->irq - IRQ_MFP_TIMER1;
164 	stmfp_base.int_mask |= 1 << mfp_num;
165 	atari_enable_irq(IRQ_MFP_TIMD);
166 }
167 
168 static void atari_mfptimer_disable(struct irq_data *data)
169 {
170 	int mfp_num = data->irq - IRQ_MFP_TIMER1;
171 	stmfp_base.int_mask &= ~(1 << mfp_num);
172 	if (!stmfp_base.int_mask)
173 		atari_disable_irq(IRQ_MFP_TIMD);
174 }
175 
176 static struct irq_chip atari_mfptimer_chip = {
177 	.name		= "timer_d",
178 	.irq_enable	= atari_mfptimer_enable,
179 	.irq_disable	= atari_mfptimer_disable,
180 };
181 
182 
183 /*
184  * EtherNAT CPLD interrupt handling
185  * CPLD interrupt register is at phys. 0x80000023
186  * Need this mapped in at interrupt startup time
187  * Possibly need this mapped on demand anyway -
188  * EtherNAT USB driver needs to disable IRQ before
189  * startup!
190  */
191 
192 static unsigned char *enat_cpld;
193 
194 static unsigned int atari_ethernat_startup(struct irq_data *data)
195 {
196 	int enat_num = 140 - data->irq + 1;
197 
198 	m68k_irq_startup(data);
199 	/*
200 	* map CPLD interrupt register
201 	*/
202 	if (!enat_cpld)
203 		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
204 	/*
205 	 * do _not_ enable the USB chip interrupt here - causes interrupt storm
206 	 * and triggers dead interrupt watchdog
207 	 * Need to reset the USB chip to a sane state in early startup before
208 	 * removing this hack
209 	 */
210 	if (enat_num == 1)
211 		*enat_cpld |= 1 << enat_num;
212 
213 	return 0;
214 }
215 
216 static void atari_ethernat_enable(struct irq_data *data)
217 {
218 	int enat_num = 140 - data->irq + 1;
219 	/*
220 	* map CPLD interrupt register
221 	*/
222 	if (!enat_cpld)
223 		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
224 	*enat_cpld |= 1 << enat_num;
225 }
226 
227 static void atari_ethernat_disable(struct irq_data *data)
228 {
229 	int enat_num = 140 - data->irq + 1;
230 	/*
231 	* map CPLD interrupt register
232 	*/
233 	if (!enat_cpld)
234 		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
235 	*enat_cpld &= ~(1 << enat_num);
236 }
237 
238 static void atari_ethernat_shutdown(struct irq_data *data)
239 {
240 	int enat_num = 140 - data->irq + 1;
241 	if (enat_cpld) {
242 		*enat_cpld &= ~(1 << enat_num);
243 		iounmap(enat_cpld);
244 		enat_cpld = NULL;
245 	}
246 }
247 
248 static struct irq_chip atari_ethernat_chip = {
249 	.name		= "ethernat",
250 	.irq_startup	= atari_ethernat_startup,
251 	.irq_shutdown	= atari_ethernat_shutdown,
252 	.irq_enable	= atari_ethernat_enable,
253 	.irq_disable	= atari_ethernat_disable,
254 };
255 
256 /*
257  * void atari_init_IRQ (void)
258  *
259  * Parameters:	None
260  *
261  * Returns:	Nothing
262  *
263  * This function should be called during kernel startup to initialize
264  * the atari IRQ handling routines.
265  */
266 
267 void __init atari_init_IRQ(void)
268 {
269 	m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER);
270 	m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1,
271 				  NUM_ATARI_SOURCES - 1);
272 
273 	/* Initialize the MFP(s) */
274 
275 #ifdef ATARI_USE_SOFTWARE_EOI
276 	st_mfp.vec_adr  = 0x48;	/* Software EOI-Mode */
277 #else
278 	st_mfp.vec_adr  = 0x40;	/* Automatic EOI-Mode */
279 #endif
280 	st_mfp.int_en_a = 0x00;	/* turn off MFP-Ints */
281 	st_mfp.int_en_b = 0x00;
282 	st_mfp.int_mk_a = 0xff;	/* no Masking */
283 	st_mfp.int_mk_b = 0xff;
284 
285 	if (ATARIHW_PRESENT(TT_MFP)) {
286 #ifdef ATARI_USE_SOFTWARE_EOI
287 		tt_mfp.vec_adr  = 0x58;		/* Software EOI-Mode */
288 #else
289 		tt_mfp.vec_adr  = 0x50;		/* Automatic EOI-Mode */
290 #endif
291 		tt_mfp.int_en_a = 0x00;		/* turn off MFP-Ints */
292 		tt_mfp.int_en_b = 0x00;
293 		tt_mfp.int_mk_a = 0xff;		/* no Masking */
294 		tt_mfp.int_mk_b = 0xff;
295 	}
296 
297 	if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) {
298 		atari_scc.cha_a_ctrl = 9;
299 		MFPDELAY();
300 		atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
301 	}
302 
303 	if (ATARIHW_PRESENT(SCU)) {
304 		/* init the SCU if present */
305 		tt_scu.sys_mask = 0x10;		/* enable VBL (for the cursor) and
306 									 * disable HSYNC interrupts (who
307 									 * needs them?)  MFP and SCC are
308 									 * enabled in VME mask
309 									 */
310 		tt_scu.vme_mask = 0x60;		/* enable MFP and SCC ints */
311 	} else {
312 		/* If no SCU and no Hades, the HSYNC interrupt needs to be
313 		 * disabled this way. (Else _inthandler in kernel/sys_call.S
314 		 * gets overruns)
315 		 */
316 
317 		vectors[VEC_INT2] = falcon_hblhandler;
318 		vectors[VEC_INT4] = falcon_hblhandler;
319 	}
320 
321 	if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
322 		/* Initialize the LM1992 Sound Controller to enable
323 		   the PSG sound.  This is misplaced here, it should
324 		   be in an atasound_init(), that doesn't exist yet. */
325 		atari_microwire_cmd(MW_LM1992_PSG_HIGH);
326 	}
327 
328 	stdma_init();
329 
330 	/* Initialize the PSG: all sounds off, both ports output */
331 	sound_ym.rd_data_reg_sel = 7;
332 	sound_ym.wd_data = 0xff;
333 
334 	m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq,
335 				  IRQ_MFP_TIMER1, 8);
336 
337 	irq_set_status_flags(IRQ_MFP_TIMER1, IRQ_IS_POLLED);
338 	irq_set_status_flags(IRQ_MFP_TIMER2, IRQ_IS_POLLED);
339 
340 	/* prepare timer D data for use as poll interrupt */
341 	/* set Timer D data Register - needs to be > 0 */
342 	st_mfp.tim_dt_d = 254;	/* < 100 Hz */
343 	/* start timer D, div = 1:100 */
344 	st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
345 
346 	/* request timer D dispatch handler */
347 	if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
348 			stmfp_base.name, &stmfp_base))
349 		pr_err("Couldn't register %s interrupt\n", stmfp_base.name);
350 
351 	/*
352 	 * EtherNAT ethernet / USB interrupt handlers
353 	 */
354 
355 	m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq,
356 				  139, 2);
357 }
358 
359 
360 /*
361  * atari_register_vme_int() returns the number of a free interrupt vector for
362  * hardware with a programmable int vector (probably a VME board).
363  */
364 
365 unsigned int atari_register_vme_int(void)
366 {
367 	int i;
368 
369 	for (i = 0; i < 32; i++)
370 		if ((free_vme_vec_bitmap & (1 << i)) == 0)
371 			break;
372 
373 	if (i == 16)
374 		return 0;
375 
376 	free_vme_vec_bitmap |= 1 << i;
377 	return VME_SOURCE_BASE + i;
378 }
379 EXPORT_SYMBOL(atari_register_vme_int);
380 
381 
382 void atari_unregister_vme_int(unsigned int irq)
383 {
384 	if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
385 		irq -= VME_SOURCE_BASE;
386 		free_vme_vec_bitmap &= ~(1 << irq);
387 	}
388 }
389 EXPORT_SYMBOL(atari_unregister_vme_int);
390 
391 
392