Commit | Line | Data |
---|---|---|
1da177e4 LT |
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> | |
a3b2004a | 43 | #include <linux/module.h> |
b718102e | 44 | #include <linux/irq.h> |
1da177e4 | 45 | |
1da177e4 LT |
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> | |
e6f80e87 | 53 | #include <asm/io.h> |
1da177e4 | 54 | |
56422360 | 55 | #include "atari.h" |
1da177e4 LT |
56 | |
57 | /* | |
58 | * Atari interrupt handling scheme: | |
59 | * -------------------------------- | |
60 | * | |
61 | * All interrupt source have an internal number (defined in | |
62 | * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP, | |
63 | * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can | |
64 | * be allocated by atari_register_vme_int(). | |
1da177e4 | 65 | */ |
73408565 RZ |
66 | |
67 | /* | |
68 | * Bitmap for free interrupt vector numbers | |
69 | * (new vectors starting from 0x70 can be allocated by | |
70 | * atari_register_vme_int()) | |
71 | */ | |
72 | static int free_vme_vec_bitmap; | |
1da177e4 LT |
73 | |
74 | /* GK: | |
75 | * HBL IRQ handler for Falcon. Nobody needs it :-) | |
76 | * ++andreas: raise ipl to disable further HBLANK interrupts. | |
77 | */ | |
78 | asmlinkage void falcon_hblhandler(void); | |
79 | asm(".text\n" | |
80 | __ALIGN_STR "\n\t" | |
81 | "falcon_hblhandler:\n\t" | |
82 | "orw #0x200,%sp@\n\t" /* set saved ipl to 2 */ | |
83 | "rte"); | |
84 | ||
e8abf5e7 | 85 | static unsigned int atari_irq_startup(struct irq_data *data) |
73408565 | 86 | { |
e8abf5e7 GU |
87 | unsigned int irq = data->irq; |
88 | ||
89 | m68k_irq_startup(data); | |
73408565 RZ |
90 | atari_turnon_irq(irq); |
91 | atari_enable_irq(irq); | |
92 | return 0; | |
93 | } | |
94 | ||
e8abf5e7 | 95 | static void atari_irq_shutdown(struct irq_data *data) |
73408565 | 96 | { |
e8abf5e7 GU |
97 | unsigned int irq = data->irq; |
98 | ||
73408565 RZ |
99 | atari_disable_irq(irq); |
100 | atari_turnoff_irq(irq); | |
e8abf5e7 | 101 | m68k_irq_shutdown(data); |
69961c37 GU |
102 | |
103 | if (irq == IRQ_AUTO_4) | |
104 | vectors[VEC_INT4] = falcon_hblhandler; | |
73408565 RZ |
105 | } |
106 | ||
e8abf5e7 GU |
107 | static void atari_irq_enable(struct irq_data *data) |
108 | { | |
109 | atari_enable_irq(data->irq); | |
110 | } | |
111 | ||
112 | static void atari_irq_disable(struct irq_data *data) | |
113 | { | |
114 | atari_disable_irq(data->irq); | |
115 | } | |
116 | ||
c288bf25 | 117 | static struct irq_chip atari_irq_chip = { |
73408565 | 118 | .name = "atari", |
e8abf5e7 GU |
119 | .irq_startup = atari_irq_startup, |
120 | .irq_shutdown = atari_irq_shutdown, | |
121 | .irq_enable = atari_irq_enable, | |
122 | .irq_disable = atari_irq_disable, | |
73408565 RZ |
123 | }; |
124 | ||
b1ae432c MS |
125 | /* |
126 | * ST-MFP timer D chained interrupts - each driver gets its own timer | |
127 | * interrupt instance. | |
128 | */ | |
129 | ||
130 | struct mfptimerbase { | |
131 | volatile struct MFP *mfp; | |
132 | unsigned char mfp_mask, mfp_data; | |
133 | unsigned short int_mask; | |
134 | int handler_irq, mfptimer_irq, server_irq; | |
135 | char *name; | |
136 | } stmfp_base = { | |
137 | .mfp = &st_mfp, | |
138 | .int_mask = 0x0, | |
139 | .handler_irq = IRQ_MFP_TIMD, | |
140 | .mfptimer_irq = IRQ_MFP_TIMER1, | |
141 | .name = "MFP Timer D" | |
142 | }; | |
143 | ||
1efdd4bd | 144 | static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id) |
b1ae432c MS |
145 | { |
146 | struct mfptimerbase *base = dev_id; | |
147 | int mach_irq; | |
148 | unsigned char ints; | |
149 | ||
150 | mach_irq = base->mfptimer_irq; | |
151 | ints = base->int_mask; | |
152 | for (; ints; mach_irq++, ints >>= 1) { | |
153 | if (ints & 1) | |
154 | generic_handle_irq(mach_irq); | |
155 | } | |
156 | return IRQ_HANDLED; | |
157 | } | |
158 | ||
159 | ||
160 | static void atari_mfptimer_enable(struct irq_data *data) | |
161 | { | |
162 | int mfp_num = data->irq - IRQ_MFP_TIMER1; | |
163 | stmfp_base.int_mask |= 1 << mfp_num; | |
164 | atari_enable_irq(IRQ_MFP_TIMD); | |
165 | } | |
166 | ||
167 | static void atari_mfptimer_disable(struct irq_data *data) | |
168 | { | |
169 | int mfp_num = data->irq - IRQ_MFP_TIMER1; | |
170 | stmfp_base.int_mask &= ~(1 << mfp_num); | |
171 | if (!stmfp_base.int_mask) | |
172 | atari_disable_irq(IRQ_MFP_TIMD); | |
173 | } | |
174 | ||
175 | static struct irq_chip atari_mfptimer_chip = { | |
176 | .name = "timer_d", | |
177 | .irq_enable = atari_mfptimer_enable, | |
178 | .irq_disable = atari_mfptimer_disable, | |
179 | }; | |
180 | ||
e6f80e87 MS |
181 | |
182 | /* | |
183 | * EtherNAT CPLD interrupt handling | |
184 | * CPLD interrupt register is at phys. 0x80000023 | |
185 | * Need this mapped in at interrupt startup time | |
186 | * Possibly need this mapped on demand anyway - | |
187 | * EtherNAT USB driver needs to disable IRQ before | |
188 | * startup! | |
189 | */ | |
190 | ||
191 | static unsigned char *enat_cpld; | |
192 | ||
193 | static unsigned int atari_ethernat_startup(struct irq_data *data) | |
194 | { | |
195 | int enat_num = 140 - data->irq + 1; | |
196 | ||
197 | m68k_irq_startup(data); | |
198 | /* | |
199 | * map CPLD interrupt register | |
200 | */ | |
201 | if (!enat_cpld) | |
202 | enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); | |
203 | /* | |
204 | * do _not_ enable the USB chip interrupt here - causes interrupt storm | |
205 | * and triggers dead interrupt watchdog | |
206 | * Need to reset the USB chip to a sane state in early startup before | |
207 | * removing this hack | |
208 | */ | |
209 | if (enat_num == 1) | |
210 | *enat_cpld |= 1 << enat_num; | |
211 | ||
212 | return 0; | |
213 | } | |
214 | ||
215 | static void atari_ethernat_enable(struct irq_data *data) | |
216 | { | |
217 | int enat_num = 140 - data->irq + 1; | |
218 | /* | |
219 | * map CPLD interrupt register | |
220 | */ | |
221 | if (!enat_cpld) | |
222 | enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); | |
223 | *enat_cpld |= 1 << enat_num; | |
224 | } | |
225 | ||
226 | static void atari_ethernat_disable(struct irq_data *data) | |
227 | { | |
228 | int enat_num = 140 - data->irq + 1; | |
229 | /* | |
230 | * map CPLD interrupt register | |
231 | */ | |
232 | if (!enat_cpld) | |
233 | enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); | |
234 | *enat_cpld &= ~(1 << enat_num); | |
235 | } | |
236 | ||
237 | static void atari_ethernat_shutdown(struct irq_data *data) | |
238 | { | |
239 | int enat_num = 140 - data->irq + 1; | |
240 | if (enat_cpld) { | |
241 | *enat_cpld &= ~(1 << enat_num); | |
242 | iounmap(enat_cpld); | |
243 | enat_cpld = NULL; | |
244 | } | |
245 | } | |
246 | ||
247 | static struct irq_chip atari_ethernat_chip = { | |
248 | .name = "ethernat", | |
249 | .irq_startup = atari_ethernat_startup, | |
250 | .irq_shutdown = atari_ethernat_shutdown, | |
251 | .irq_enable = atari_ethernat_enable, | |
252 | .irq_disable = atari_ethernat_disable, | |
253 | }; | |
254 | ||
1da177e4 LT |
255 | /* |
256 | * void atari_init_IRQ (void) | |
257 | * | |
258 | * Parameters: None | |
259 | * | |
260 | * Returns: Nothing | |
261 | * | |
262 | * This function should be called during kernel startup to initialize | |
263 | * the atari IRQ handling routines. | |
264 | */ | |
265 | ||
266 | void __init atari_init_IRQ(void) | |
267 | { | |
f30a6484 | 268 | m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER); |
edb34725 GU |
269 | m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1, |
270 | NUM_ATARI_SOURCES - 1); | |
1da177e4 LT |
271 | |
272 | /* Initialize the MFP(s) */ | |
273 | ||
274 | #ifdef ATARI_USE_SOFTWARE_EOI | |
3d92e8f3 | 275 | st_mfp.vec_adr = 0x48; /* Software EOI-Mode */ |
1da177e4 | 276 | #else |
3d92e8f3 | 277 | st_mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ |
1da177e4 | 278 | #endif |
3d92e8f3 GU |
279 | st_mfp.int_en_a = 0x00; /* turn off MFP-Ints */ |
280 | st_mfp.int_en_b = 0x00; | |
281 | st_mfp.int_mk_a = 0xff; /* no Masking */ | |
282 | st_mfp.int_mk_b = 0xff; | |
1da177e4 LT |
283 | |
284 | if (ATARIHW_PRESENT(TT_MFP)) { | |
285 | #ifdef ATARI_USE_SOFTWARE_EOI | |
286 | tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */ | |
287 | #else | |
288 | tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */ | |
289 | #endif | |
290 | tt_mfp.int_en_a = 0x00; /* turn off MFP-Ints */ | |
291 | tt_mfp.int_en_b = 0x00; | |
292 | tt_mfp.int_mk_a = 0xff; /* no Masking */ | |
293 | tt_mfp.int_mk_b = 0xff; | |
294 | } | |
295 | ||
296 | if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) { | |
de339e4b | 297 | atari_scc.cha_a_ctrl = 9; |
1da177e4 | 298 | MFPDELAY(); |
de339e4b | 299 | atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ |
1da177e4 LT |
300 | } |
301 | ||
302 | if (ATARIHW_PRESENT(SCU)) { | |
303 | /* init the SCU if present */ | |
f70065a9 | 304 | tt_scu.sys_mask = 0x0; /* disable all interrupts */ |
1da177e4 | 305 | tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ |
73408565 | 306 | } else { |
1da177e4 LT |
307 | /* If no SCU and no Hades, the HSYNC interrupt needs to be |
308 | * disabled this way. (Else _inthandler in kernel/sys_call.S | |
309 | * gets overruns) | |
310 | */ | |
311 | ||
29c8a246 AB |
312 | vectors[VEC_INT2] = falcon_hblhandler; |
313 | vectors[VEC_INT4] = falcon_hblhandler; | |
1da177e4 LT |
314 | } |
315 | ||
316 | if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { | |
317 | /* Initialize the LM1992 Sound Controller to enable | |
318 | the PSG sound. This is misplaced here, it should | |
319 | be in an atasound_init(), that doesn't exist yet. */ | |
320 | atari_microwire_cmd(MW_LM1992_PSG_HIGH); | |
321 | } | |
322 | ||
323 | stdma_init(); | |
324 | ||
325 | /* Initialize the PSG: all sounds off, both ports output */ | |
326 | sound_ym.rd_data_reg_sel = 7; | |
327 | sound_ym.wd_data = 0xff; | |
b1ae432c MS |
328 | |
329 | m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq, | |
330 | IRQ_MFP_TIMER1, 8); | |
331 | ||
a0b7b242 MS |
332 | irq_set_status_flags(IRQ_MFP_TIMER1, IRQ_IS_POLLED); |
333 | irq_set_status_flags(IRQ_MFP_TIMER2, IRQ_IS_POLLED); | |
334 | ||
b1ae432c MS |
335 | /* prepare timer D data for use as poll interrupt */ |
336 | /* set Timer D data Register - needs to be > 0 */ | |
337 | st_mfp.tim_dt_d = 254; /* < 100 Hz */ | |
338 | /* start timer D, div = 1:100 */ | |
339 | st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6; | |
340 | ||
341 | /* request timer D dispatch handler */ | |
1efdd4bd | 342 | if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED, |
b1ae432c MS |
343 | stmfp_base.name, &stmfp_base)) |
344 | pr_err("Couldn't register %s interrupt\n", stmfp_base.name); | |
e6f80e87 MS |
345 | |
346 | /* | |
347 | * EtherNAT ethernet / USB interrupt handlers | |
348 | */ | |
349 | ||
350 | m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq, | |
351 | 139, 2); | |
1da177e4 LT |
352 | } |
353 | ||
354 | ||
1da177e4 LT |
355 | /* |
356 | * atari_register_vme_int() returns the number of a free interrupt vector for | |
357 | * hardware with a programmable int vector (probably a VME board). | |
358 | */ | |
359 | ||
44883eb0 | 360 | unsigned int atari_register_vme_int(void) |
1da177e4 LT |
361 | { |
362 | int i; | |
363 | ||
73408565 RZ |
364 | for (i = 0; i < 32; i++) |
365 | if ((free_vme_vec_bitmap & (1 << i)) == 0) | |
1da177e4 LT |
366 | break; |
367 | ||
73408565 | 368 | if (i == 16) |
1da177e4 LT |
369 | return 0; |
370 | ||
371 | free_vme_vec_bitmap |= 1 << i; | |
73408565 | 372 | return VME_SOURCE_BASE + i; |
1da177e4 | 373 | } |
a3b2004a | 374 | EXPORT_SYMBOL(atari_register_vme_int); |
1da177e4 LT |
375 | |
376 | ||
44883eb0 | 377 | void atari_unregister_vme_int(unsigned int irq) |
1da177e4 | 378 | { |
73408565 | 379 | if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { |
1da177e4 LT |
380 | irq -= VME_SOURCE_BASE; |
381 | free_vme_vec_bitmap &= ~(1 << irq); | |
382 | } | |
383 | } | |
a3b2004a | 384 | EXPORT_SYMBOL(atari_unregister_vme_int); |
1da177e4 LT |
385 | |
386 |