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 #include "atari.h" 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(). 65 */ 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; 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 85 static unsigned int atari_irq_startup(struct irq_data *data) 86 { 87 unsigned int irq = data->irq; 88 89 m68k_irq_startup(data); 90 atari_turnon_irq(irq); 91 atari_enable_irq(irq); 92 return 0; 93 } 94 95 static void atari_irq_shutdown(struct irq_data *data) 96 { 97 unsigned int irq = data->irq; 98 99 atari_disable_irq(irq); 100 atari_turnoff_irq(irq); 101 m68k_irq_shutdown(data); 102 103 if (irq == IRQ_AUTO_4) 104 vectors[VEC_INT4] = falcon_hblhandler; 105 } 106 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 117 static struct irq_chip atari_irq_chip = { 118 .name = "atari", 119 .irq_startup = atari_irq_startup, 120 .irq_shutdown = atari_irq_shutdown, 121 .irq_enable = atari_irq_enable, 122 .irq_disable = atari_irq_disable, 123 }; 124 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 144 static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id) 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 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 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 { 268 m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER); 269 m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1, 270 NUM_ATARI_SOURCES - 1); 271 272 /* Initialize the MFP(s) */ 273 274 #ifdef ATARI_USE_SOFTWARE_EOI 275 st_mfp.vec_adr = 0x48; /* Software EOI-Mode */ 276 #else 277 st_mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ 278 #endif 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; 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) { 297 atari_scc.cha_a_ctrl = 9; 298 MFPDELAY(); 299 atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ 300 } 301 302 if (ATARIHW_PRESENT(SCU)) { 303 /* init the SCU if present */ 304 tt_scu.sys_mask = 0x0; /* disable all interrupts */ 305 tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ 306 } else { 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 312 vectors[VEC_INT2] = falcon_hblhandler; 313 vectors[VEC_INT4] = falcon_hblhandler; 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; 328 329 m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq, 330 IRQ_MFP_TIMER1, 8); 331 332 irq_set_status_flags(IRQ_MFP_TIMER1, IRQ_IS_POLLED); 333 irq_set_status_flags(IRQ_MFP_TIMER2, IRQ_IS_POLLED); 334 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 */ 342 if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED, 343 stmfp_base.name, &stmfp_base)) 344 pr_err("Couldn't register %s interrupt\n", stmfp_base.name); 345 346 /* 347 * EtherNAT ethernet / USB interrupt handlers 348 */ 349 350 m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq, 351 139, 2); 352 } 353 354 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 360 unsigned int atari_register_vme_int(void) 361 { 362 int i; 363 364 for (i = 0; i < 32; i++) 365 if ((free_vme_vec_bitmap & (1 << i)) == 0) 366 break; 367 368 if (i == 16) 369 return 0; 370 371 free_vme_vec_bitmap |= 1 << i; 372 return VME_SOURCE_BASE + i; 373 } 374 EXPORT_SYMBOL(atari_register_vme_int); 375 376 377 void atari_unregister_vme_int(unsigned int irq) 378 { 379 if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { 380 irq -= VME_SOURCE_BASE; 381 free_vme_vec_bitmap &= ~(1 << irq); 382 } 383 } 384 EXPORT_SYMBOL(atari_unregister_vme_int); 385 386 387
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.