]>
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 LT |
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(). | |
1da177e4 | 64 | */ |
73408565 RZ |
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; | |
1da177e4 LT |
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 | ||
73408565 | 84 | extern void atari_microwire_cmd(int cmd); |
1da177e4 | 85 | |
e8abf5e7 | 86 | static unsigned int atari_irq_startup(struct irq_data *data) |
73408565 | 87 | { |
e8abf5e7 GU |
88 | unsigned int irq = data->irq; |
89 | ||
90 | m68k_irq_startup(data); | |
73408565 RZ |
91 | atari_turnon_irq(irq); |
92 | atari_enable_irq(irq); | |
93 | return 0; | |
94 | } | |
95 | ||
e8abf5e7 | 96 | static void atari_irq_shutdown(struct irq_data *data) |
73408565 | 97 | { |
e8abf5e7 GU |
98 | unsigned int irq = data->irq; |
99 | ||
73408565 RZ |
100 | atari_disable_irq(irq); |
101 | atari_turnoff_irq(irq); | |
e8abf5e7 | 102 | m68k_irq_shutdown(data); |
69961c37 GU |
103 | |
104 | if (irq == IRQ_AUTO_4) | |
105 | vectors[VEC_INT4] = falcon_hblhandler; | |
73408565 RZ |
106 | } |
107 | ||
e8abf5e7 GU |
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 | ||
c288bf25 | 118 | static struct irq_chip atari_irq_chip = { |
73408565 | 119 | .name = "atari", |
e8abf5e7 GU |
120 | .irq_startup = atari_irq_startup, |
121 | .irq_shutdown = atari_irq_shutdown, | |
122 | .irq_enable = atari_irq_enable, | |
123 | .irq_disable = atari_irq_disable, | |
73408565 RZ |
124 | }; |
125 | ||
b1ae432c MS |
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 | ||
1efdd4bd | 145 | static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id) |
b1ae432c MS |
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 | ||
e6f80e87 MS |
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 | ||
1da177e4 LT |
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 | { | |
f30a6484 | 269 | m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER); |
edb34725 GU |
270 | m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1, |
271 | NUM_ATARI_SOURCES - 1); | |
1da177e4 LT |
272 | |
273 | /* Initialize the MFP(s) */ | |
274 | ||
275 | #ifdef ATARI_USE_SOFTWARE_EOI | |
3d92e8f3 | 276 | st_mfp.vec_adr = 0x48; /* Software EOI-Mode */ |
1da177e4 | 277 | #else |
3d92e8f3 | 278 | st_mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ |
1da177e4 | 279 | #endif |
3d92e8f3 GU |
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; | |
1da177e4 LT |
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) { | |
de339e4b | 298 | atari_scc.cha_a_ctrl = 9; |
1da177e4 | 299 | MFPDELAY(); |
de339e4b | 300 | atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ |
1da177e4 LT |
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 */ | |
73408565 | 311 | } else { |
1da177e4 LT |
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 | ||
29c8a246 AB |
317 | vectors[VEC_INT2] = falcon_hblhandler; |
318 | vectors[VEC_INT4] = falcon_hblhandler; | |
1da177e4 LT |
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; | |
b1ae432c MS |
333 | |
334 | m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq, | |
335 | IRQ_MFP_TIMER1, 8); | |
336 | ||
a0b7b242 MS |
337 | irq_set_status_flags(IRQ_MFP_TIMER1, IRQ_IS_POLLED); |
338 | irq_set_status_flags(IRQ_MFP_TIMER2, IRQ_IS_POLLED); | |
339 | ||
b1ae432c MS |
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 */ | |
1efdd4bd | 347 | if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED, |
b1ae432c MS |
348 | stmfp_base.name, &stmfp_base)) |
349 | pr_err("Couldn't register %s interrupt\n", stmfp_base.name); | |
e6f80e87 MS |
350 | |
351 | /* | |
352 | * EtherNAT ethernet / USB interrupt handlers | |
353 | */ | |
354 | ||
355 | m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq, | |
356 | 139, 2); | |
1da177e4 LT |
357 | } |
358 | ||
359 | ||
1da177e4 LT |
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 | ||
44883eb0 | 365 | unsigned int atari_register_vme_int(void) |
1da177e4 LT |
366 | { |
367 | int i; | |
368 | ||
73408565 RZ |
369 | for (i = 0; i < 32; i++) |
370 | if ((free_vme_vec_bitmap & (1 << i)) == 0) | |
1da177e4 LT |
371 | break; |
372 | ||
73408565 | 373 | if (i == 16) |
1da177e4 LT |
374 | return 0; |
375 | ||
376 | free_vme_vec_bitmap |= 1 << i; | |
73408565 | 377 | return VME_SOURCE_BASE + i; |
1da177e4 | 378 | } |
a3b2004a | 379 | EXPORT_SYMBOL(atari_register_vme_int); |
1da177e4 LT |
380 | |
381 | ||
44883eb0 | 382 | void atari_unregister_vme_int(unsigned int irq) |
1da177e4 | 383 | { |
73408565 | 384 | if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { |
1da177e4 LT |
385 | irq -= VME_SOURCE_BASE; |
386 | free_vme_vec_bitmap &= ~(1 << irq); | |
387 | } | |
388 | } | |
a3b2004a | 389 | EXPORT_SYMBOL(atari_unregister_vme_int); |
1da177e4 LT |
390 | |
391 |