xref: /openbmc/linux/arch/m68k/q40/q40ints.c (revision 0c79cf6a)
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 
8266a3f820SAl Viro void __init 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 : */
1870c79cf6aSSimon Arlott static int ccleirq=60;    /* ISA dev IRQs*/
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
2370c79cf6aSSimon Arlott  * not just go away but they occasionally 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