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 mfp_timer_d_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, mfp_timer_d_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