11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * arch/m68k/q40/q40ints.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1999,2001 Richard Zidlicky 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 71da177e4SLinus Torvalds * License. See the file COPYING in the main directory of this archive 81da177e4SLinus Torvalds * for more details. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * .. used to be loosely based on bvme6000ints.c 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/types.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/errno.h> 171da177e4SLinus Torvalds #include <linux/interrupt.h> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include <asm/ptrace.h> 201da177e4SLinus Torvalds #include <asm/system.h> 211da177e4SLinus Torvalds #include <asm/irq.h> 221da177e4SLinus Torvalds #include <asm/traps.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include <asm/q40_master.h> 251da177e4SLinus Torvalds #include <asm/q40ints.h> 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* 281da177e4SLinus Torvalds * Q40 IRQs are defined as follows: 291da177e4SLinus Torvalds * 3,4,5,6,7,10,11,14,15 : ISA dev IRQs 301da177e4SLinus Torvalds * 16-31: reserved 311da177e4SLinus Torvalds * 32 : keyboard int 321da177e4SLinus Torvalds * 33 : frame int (50/200 Hz periodic timer) 331da177e4SLinus Torvalds * 34 : sample int (10/20 KHz periodic timer) 341da177e4SLinus Torvalds * 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds 3777dda339SRoman Zippel static void q40_irq_handler(unsigned int, struct pt_regs *fp); 3877dda339SRoman Zippel static void q40_enable_irq(unsigned int); 3977dda339SRoman Zippel static void q40_disable_irq(unsigned int); 401da177e4SLinus Torvalds 4177dda339SRoman Zippel unsigned short q40_ablecount[35]; 4277dda339SRoman Zippel unsigned short q40_state[35]; 431da177e4SLinus Torvalds 4477dda339SRoman Zippel static int q40_irq_startup(unsigned int irq) 4577dda339SRoman Zippel { 4677dda339SRoman Zippel /* test for ISA ints not implemented by HW */ 4777dda339SRoman Zippel switch (irq) { 4877dda339SRoman Zippel case 1: case 2: case 8: case 9: 4977dda339SRoman Zippel case 11: case 12: case 13: 5077dda339SRoman Zippel printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq); 5177dda339SRoman Zippel return -ENXIO; 5277dda339SRoman Zippel } 5377dda339SRoman Zippel return 0; 5477dda339SRoman Zippel } 551da177e4SLinus Torvalds 5677dda339SRoman Zippel static void q40_irq_shutdown(unsigned int irq) 5777dda339SRoman Zippel { 5877dda339SRoman Zippel } 591da177e4SLinus Torvalds 6077dda339SRoman Zippel static struct irq_controller q40_irq_controller = { 6177dda339SRoman Zippel .name = "q40", 62241258d1SMilind Arun Choudhary .lock = __SPIN_LOCK_UNLOCKED(q40_irq_controller.lock), 6377dda339SRoman Zippel .startup = q40_irq_startup, 6477dda339SRoman Zippel .shutdown = q40_irq_shutdown, 6577dda339SRoman Zippel .enable = q40_enable_irq, 6677dda339SRoman Zippel .disable = q40_disable_irq, 6777dda339SRoman Zippel }; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /* 701da177e4SLinus Torvalds * void q40_init_IRQ (void) 711da177e4SLinus Torvalds * 721da177e4SLinus Torvalds * Parameters: None 731da177e4SLinus Torvalds * 741da177e4SLinus Torvalds * Returns: Nothing 751da177e4SLinus Torvalds * 761da177e4SLinus Torvalds * This function is called during kernel startup to initialize 771da177e4SLinus Torvalds * the q40 IRQ handling routines. 781da177e4SLinus Torvalds */ 791da177e4SLinus Torvalds 8077dda339SRoman Zippel static int disabled; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds void q40_init_IRQ(void) 831da177e4SLinus Torvalds { 8477dda339SRoman Zippel m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX); 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* setup handler for ISA ints */ 8777dda339SRoman Zippel m68k_setup_auto_interrupt(q40_irq_handler); 8877dda339SRoman Zippel 8977dda339SRoman Zippel m68k_irq_startup(IRQ_AUTO_2); 9077dda339SRoman Zippel m68k_irq_startup(IRQ_AUTO_4); 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds /* now enable some ints.. */ 931da177e4SLinus Torvalds master_outb(1, EXT_ENABLE_REG); /* ISA IRQ 5-15 */ 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* make sure keyboard IRQ is disabled */ 961da177e4SLinus Torvalds master_outb(0, KEY_IRQ_ENABLE_REG); 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds /* 1011da177e4SLinus Torvalds * this stuff doesn't really belong here.. 1021da177e4SLinus Torvalds */ 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds int ql_ticks; /* 200Hz ticks since last jiffie */ 1051da177e4SLinus Torvalds static int sound_ticks; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds #define SVOL 45 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds void q40_mksound(unsigned int hz, unsigned int ticks) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds /* for now ignore hz, except that hz==0 switches off sound */ 1121da177e4SLinus Torvalds /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */ 11377dda339SRoman Zippel if (hz == 0) { 1141da177e4SLinus Torvalds if (sound_ticks) 1151da177e4SLinus Torvalds sound_ticks = 1; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds *DAC_LEFT = 128; 1181da177e4SLinus Torvalds *DAC_RIGHT = 128; 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds return; 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds /* sound itself is done in q40_timer_int */ 12377dda339SRoman Zippel if (sound_ticks == 0) 12477dda339SRoman Zippel sound_ticks = 1000; /* pretty long beep */ 1251da177e4SLinus Torvalds sound_ticks = ticks << 1; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 12840220c1aSDavid Howells static irq_handler_t q40_timer_routine; 1291da177e4SLinus Torvalds 1302850bc27SAl Viro static irqreturn_t q40_timer_int (int irq, void * dev) 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds ql_ticks = ql_ticks ? 0 : 1; 13377dda339SRoman Zippel if (sound_ticks) { 1341da177e4SLinus Torvalds unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; 1351da177e4SLinus Torvalds sound_ticks--; 1361da177e4SLinus Torvalds *DAC_LEFT=sval; 1371da177e4SLinus Torvalds *DAC_RIGHT=sval; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds if (!ql_ticks) 1412850bc27SAl Viro q40_timer_routine(irq, dev); 1421da177e4SLinus Torvalds return IRQ_HANDLED; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 14540220c1aSDavid Howells void q40_sched_init (irq_handler_t timer_routine) 1461da177e4SLinus Torvalds { 1471da177e4SLinus Torvalds int timer_irq; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds q40_timer_routine = timer_routine; 1501da177e4SLinus Torvalds timer_irq = Q40_IRQ_FRAME; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds if (request_irq(timer_irq, q40_timer_int, 0, 1531da177e4SLinus Torvalds "timer", q40_timer_int)) 1541da177e4SLinus Torvalds panic("Couldn't register timer int"); 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds master_outb(-1, FRAME_CLEAR_REG); 1571da177e4SLinus Torvalds master_outb( 1, FRAME_RATE_REG); 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 1621da177e4SLinus Torvalds * tables to translate bits into IRQ numbers 1631da177e4SLinus Torvalds * it is a good idea to order the entries by priority 1641da177e4SLinus Torvalds * 1651da177e4SLinus Torvalds */ 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds struct IRQ_TABLE{ unsigned mask; int irq ;}; 1681da177e4SLinus Torvalds #if 0 1691da177e4SLinus Torvalds static struct IRQ_TABLE iirqs[]={ 1701da177e4SLinus Torvalds {Q40_IRQ_FRAME_MASK,Q40_IRQ_FRAME}, 1711da177e4SLinus Torvalds {Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD}, 1721da177e4SLinus Torvalds {0,0}}; 1731da177e4SLinus Torvalds #endif 1741da177e4SLinus Torvalds static struct IRQ_TABLE eirqs[] = { 1751da177e4SLinus Torvalds { .mask = Q40_IRQ3_MASK, .irq = 3 }, /* ser 1 */ 1761da177e4SLinus Torvalds { .mask = Q40_IRQ4_MASK, .irq = 4 }, /* ser 2 */ 1771da177e4SLinus Torvalds { .mask = Q40_IRQ14_MASK, .irq = 14 }, /* IDE 1 */ 1781da177e4SLinus Torvalds { .mask = Q40_IRQ15_MASK, .irq = 15 }, /* IDE 2 */ 1791da177e4SLinus Torvalds { .mask = Q40_IRQ6_MASK, .irq = 6 }, /* floppy, handled elsewhere */ 1801da177e4SLinus Torvalds { .mask = Q40_IRQ7_MASK, .irq = 7 }, /* par */ 1811da177e4SLinus Torvalds { .mask = Q40_IRQ5_MASK, .irq = 5 }, 1821da177e4SLinus Torvalds { .mask = Q40_IRQ10_MASK, .irq = 10 }, 1831da177e4SLinus Torvalds {0,0} 1841da177e4SLinus Torvalds }; 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds /* complain only this many times about spurious ints : */ 1871da177e4SLinus Torvalds static int ccleirq=60; /* ISA dev IRQ's*/ 1881da177e4SLinus Torvalds /*static int cclirq=60;*/ /* internal */ 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds /* FIXME: add shared ints,mask,unmask,probing.... */ 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds #define IRQ_INPROGRESS 1 1931da177e4SLinus Torvalds /*static unsigned short saved_mask;*/ 1941da177e4SLinus Torvalds //static int do_tint=0; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds #define DEBUG_Q40INT 1971da177e4SLinus Torvalds /*#define IP_USE_DISABLE *//* would be nice, but crashes ???? */ 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds static int mext_disabled=0; /* ext irq disabled by master chip? */ 2001da177e4SLinus Torvalds static int aliased_irq=0; /* how many times inside handler ?*/ 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds 20377dda339SRoman Zippel /* got interrupt, dispatch to ISA or keyboard/timer IRQs */ 20477dda339SRoman Zippel static void q40_irq_handler(unsigned int irq, struct pt_regs *fp) 2051da177e4SLinus Torvalds { 2061da177e4SLinus Torvalds unsigned mir, mer; 20777dda339SRoman Zippel int i; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds //repeat: 2101da177e4SLinus Torvalds mir = master_inb(IIRQ_REG); 21177dda339SRoman Zippel #ifdef CONFIG_BLK_DEV_FD 21277dda339SRoman Zippel if ((mir & Q40_IRQ_EXT_MASK) && 21377dda339SRoman Zippel (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) { 21477dda339SRoman Zippel floppy_hardint(); 21577dda339SRoman Zippel return; 21677dda339SRoman Zippel } 21777dda339SRoman Zippel #endif 21877dda339SRoman Zippel switch (irq) { 21977dda339SRoman Zippel case 4: 22077dda339SRoman Zippel case 6: 2212850bc27SAl Viro __m68k_handle_int(Q40_IRQ_SAMPLE, fp); 22277dda339SRoman Zippel return; 22377dda339SRoman Zippel } 2241da177e4SLinus Torvalds if (mir & Q40_IRQ_FRAME_MASK) { 2252850bc27SAl Viro __m68k_handle_int(Q40_IRQ_FRAME, fp); 2261da177e4SLinus Torvalds master_outb(-1, FRAME_CLEAR_REG); 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) { 2291da177e4SLinus Torvalds mer = master_inb(EIRQ_REG); 2301da177e4SLinus Torvalds for (i = 0; eirqs[i].mask; i++) { 23177dda339SRoman Zippel if (mer & eirqs[i].mask) { 2321da177e4SLinus Torvalds irq = eirqs[i].irq; 2331da177e4SLinus Torvalds /* 2341da177e4SLinus Torvalds * There is a little mess wrt which IRQ really caused this irq request. The 2351da177e4SLinus Torvalds * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they 2361da177e4SLinus Torvalds * are read - which is long after the request came in. In theory IRQs should 2371da177e4SLinus Torvalds * not just go away but they occassionally do 2381da177e4SLinus Torvalds */ 2391da177e4SLinus Torvalds if (irq > 4 && irq <= 15 && mext_disabled) { 2401da177e4SLinus Torvalds /*aliased_irq++;*/ 2411da177e4SLinus Torvalds goto iirq; 2421da177e4SLinus Torvalds } 24377dda339SRoman Zippel if (q40_state[irq] & IRQ_INPROGRESS) { 2441da177e4SLinus Torvalds /* some handlers do local_irq_enable() for irq latency reasons, */ 2451da177e4SLinus Torvalds /* however reentering an active irq handler is not permitted */ 2461da177e4SLinus Torvalds #ifdef IP_USE_DISABLE 2471da177e4SLinus Torvalds /* in theory this is the better way to do it because it still */ 2481da177e4SLinus Torvalds /* lets through eg the serial irqs, unfortunately it crashes */ 2491da177e4SLinus Torvalds disable_irq(irq); 2501da177e4SLinus Torvalds disabled = 1; 2511da177e4SLinus Torvalds #else 25277dda339SRoman Zippel /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n", 25377dda339SRoman Zippel irq, disabled ? "already" : "not yet"); */ 2541da177e4SLinus Torvalds fp->sr = (((fp->sr) & (~0x700))+0x200); 2551da177e4SLinus Torvalds disabled = 1; 2561da177e4SLinus Torvalds #endif 2571da177e4SLinus Torvalds goto iirq; 2581da177e4SLinus Torvalds } 25977dda339SRoman Zippel q40_state[irq] |= IRQ_INPROGRESS; 2602850bc27SAl Viro __m68k_handle_int(irq, fp); 26177dda339SRoman Zippel q40_state[irq] &= ~IRQ_INPROGRESS; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds /* naively enable everything, if that fails than */ 2641da177e4SLinus Torvalds /* this function will be reentered immediately thus */ 2651da177e4SLinus Torvalds /* getting another chance to disable the IRQ */ 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds if (disabled) { 2681da177e4SLinus Torvalds #ifdef IP_USE_DISABLE 2691da177e4SLinus Torvalds if (irq > 4) { 2701da177e4SLinus Torvalds disabled = 0; 27177dda339SRoman Zippel enable_irq(irq); 27277dda339SRoman Zippel } 2731da177e4SLinus Torvalds #else 2741da177e4SLinus Torvalds disabled = 0; 2751da177e4SLinus Torvalds /*printk("reenabling irq %d\n", irq); */ 2761da177e4SLinus Torvalds #endif 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds // used to do 'goto repeat;' here, this delayed bh processing too long 27977dda339SRoman Zippel return; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds } 28277dda339SRoman Zippel if (mer && ccleirq > 0 && !aliased_irq) { 28377dda339SRoman Zippel printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer); 28477dda339SRoman Zippel ccleirq--; 28577dda339SRoman Zippel } 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds iirq: 2881da177e4SLinus Torvalds mir = master_inb(IIRQ_REG); 2891da177e4SLinus Torvalds /* should test whether keyboard irq is really enabled, doing it in defhand */ 29077dda339SRoman Zippel if (mir & Q40_IRQ_KEYB_MASK) 2912850bc27SAl Viro __m68k_handle_int(Q40_IRQ_KEYBOARD, fp); 2921da177e4SLinus Torvalds 29377dda339SRoman Zippel return; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds void q40_enable_irq(unsigned int irq) 2971da177e4SLinus Torvalds { 29877dda339SRoman Zippel if (irq >= 5 && irq <= 15) { 2991da177e4SLinus Torvalds mext_disabled--; 3001da177e4SLinus Torvalds if (mext_disabled > 0) 3011da177e4SLinus Torvalds printk("q40_enable_irq : nested disable/enable\n"); 3021da177e4SLinus Torvalds if (mext_disabled == 0) 3031da177e4SLinus Torvalds master_outb(1, EXT_ENABLE_REG); 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds void q40_disable_irq(unsigned int irq) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds /* disable ISA iqs : only do something if the driver has been 3111da177e4SLinus Torvalds * verified to be Q40 "compatible" - right now IDE, NE2K 3121da177e4SLinus Torvalds * Any driver should not attempt to sleep across disable_irq !! 3131da177e4SLinus Torvalds */ 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds if (irq >= 5 && irq <= 15) { 3161da177e4SLinus Torvalds master_outb(0, EXT_ENABLE_REG); 3171da177e4SLinus Torvalds mext_disabled++; 31877dda339SRoman Zippel if (mext_disabled > 1) 31977dda339SRoman Zippel printk("disable_irq nesting count %d\n",mext_disabled); 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds unsigned long q40_probe_irq_on(void) 3241da177e4SLinus Torvalds { 3251da177e4SLinus Torvalds printk("irq probing not working - reconfigure the driver to avoid this\n"); 3261da177e4SLinus Torvalds return -1; 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds int q40_probe_irq_off(unsigned long irqs) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds return -1; 3311da177e4SLinus Torvalds } 332