blob: f1e5288f043fb4fd394a16daeebf509afeb23b27 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/m68k/q40/q40ints.c
3 *
4 * Copyright (C) 1999,2001 Richard Zidlicky
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 *
10 * .. used to be loosely based on bvme6000ints.c
11 *
12 */
13
14#include <linux/types.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/interrupt.h>
Geert Uytterhoevena03010e2011-08-18 14:47:16 +020018#ifdef CONFIG_GENERIC_HARDIRQS
19#include <linux/irq.h>
20#else
21#include <asm/irq.h>
22#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/ptrace.h>
25#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/traps.h>
27
28#include <asm/q40_master.h>
29#include <asm/q40ints.h>
30
31/*
32 * Q40 IRQs are defined as follows:
33 * 3,4,5,6,7,10,11,14,15 : ISA dev IRQs
34 * 16-31: reserved
35 * 32 : keyboard int
36 * 33 : frame int (50/200 Hz periodic timer)
37 * 34 : sample int (10/20 KHz periodic timer)
38 *
39*/
40
Roman Zippel77dda332006-06-25 05:47:05 -070041static void q40_irq_handler(unsigned int, struct pt_regs *fp);
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +020042static void q40_irq_enable(struct irq_data *data);
43static void q40_irq_disable(struct irq_data *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Roman Zippel77dda332006-06-25 05:47:05 -070045unsigned short q40_ablecount[35];
46unsigned short q40_state[35];
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +020048static unsigned int q40_irq_startup(struct irq_data *data)
Roman Zippel77dda332006-06-25 05:47:05 -070049{
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +020050 unsigned int irq = data->irq;
51
Roman Zippel77dda332006-06-25 05:47:05 -070052 /* test for ISA ints not implemented by HW */
53 switch (irq) {
54 case 1: case 2: case 8: case 9:
55 case 11: case 12: case 13:
Harvey Harrisonf85e7cd2008-04-28 02:13:49 -070056 printk("%s: ISA IRQ %d not implemented by HW\n", __func__, irq);
Geert Uytterhoevenc288bf22011-04-13 22:31:28 +020057 /* FIXME return -ENXIO; */
Roman Zippel77dda332006-06-25 05:47:05 -070058 }
59 return 0;
60}
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +020062static void q40_irq_shutdown(struct irq_data *data)
Roman Zippel77dda332006-06-25 05:47:05 -070063{
64}
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Geert Uytterhoevenc288bf22011-04-13 22:31:28 +020066static struct irq_chip q40_irq_chip = {
Roman Zippel77dda332006-06-25 05:47:05 -070067 .name = "q40",
Geert Uytterhoevenc288bf22011-04-13 22:31:28 +020068 .irq_startup = q40_irq_startup,
69 .irq_shutdown = q40_irq_shutdown,
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +020070 .irq_enable = q40_irq_enable,
71 .irq_disable = q40_irq_disable,
Roman Zippel77dda332006-06-25 05:47:05 -070072};
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/*
75 * void q40_init_IRQ (void)
76 *
77 * Parameters: None
78 *
79 * Returns: Nothing
80 *
81 * This function is called during kernel startup to initialize
82 * the q40 IRQ handling routines.
83 */
84
Roman Zippel77dda332006-06-25 05:47:05 -070085static int disabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Al Viro66a3f822007-07-20 04:33:28 +010087void __init q40_init_IRQ(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
Geert Uytterhoevenedb34722011-06-01 11:15:21 +020089 m68k_setup_irq_controller(&q40_irq_chip, handle_simple_irq, 1,
90 Q40_IRQ_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92 /* setup handler for ISA ints */
Roman Zippel77dda332006-06-25 05:47:05 -070093 m68k_setup_auto_interrupt(q40_irq_handler);
94
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +020095 m68k_irq_startup_irq(IRQ_AUTO_2);
96 m68k_irq_startup_irq(IRQ_AUTO_4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98 /* now enable some ints.. */
Roman Zippel77dda332006-06-25 05:47:05 -070099 master_outb(1, EXT_ENABLE_REG); /* ISA IRQ 5-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101 /* make sure keyboard IRQ is disabled */
Roman Zippel77dda332006-06-25 05:47:05 -0700102 master_outb(0, KEY_IRQ_ENABLE_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106/*
107 * this stuff doesn't really belong here..
Roman Zippel77dda332006-06-25 05:47:05 -0700108 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
110int ql_ticks; /* 200Hz ticks since last jiffie */
111static int sound_ticks;
112
113#define SVOL 45
114
115void q40_mksound(unsigned int hz, unsigned int ticks)
116{
Roman Zippel77dda332006-06-25 05:47:05 -0700117 /* for now ignore hz, except that hz==0 switches off sound */
118 /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
119 if (hz == 0) {
120 if (sound_ticks)
121 sound_ticks = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Roman Zippel77dda332006-06-25 05:47:05 -0700123 *DAC_LEFT = 128;
124 *DAC_RIGHT = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Roman Zippel77dda332006-06-25 05:47:05 -0700126 return;
127 }
128 /* sound itself is done in q40_timer_int */
129 if (sound_ticks == 0)
130 sound_ticks = 1000; /* pretty long beep */
131 sound_ticks = ticks << 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
David Howells40220c12006-10-09 12:19:47 +0100134static irq_handler_t q40_timer_routine;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Al Viro2850bc22006-10-07 14:16:45 +0100136static irqreturn_t q40_timer_int (int irq, void * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Roman Zippel77dda332006-06-25 05:47:05 -0700138 ql_ticks = ql_ticks ? 0 : 1;
139 if (sound_ticks) {
140 unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
141 sound_ticks--;
142 *DAC_LEFT=sval;
143 *DAC_RIGHT=sval;
144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Roman Zippel77dda332006-06-25 05:47:05 -0700146 if (!ql_ticks)
Al Viro2850bc22006-10-07 14:16:45 +0100147 q40_timer_routine(irq, dev);
Roman Zippel77dda332006-06-25 05:47:05 -0700148 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149}
150
David Howells40220c12006-10-09 12:19:47 +0100151void q40_sched_init (irq_handler_t timer_routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
Roman Zippel77dda332006-06-25 05:47:05 -0700153 int timer_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Roman Zippel77dda332006-06-25 05:47:05 -0700155 q40_timer_routine = timer_routine;
156 timer_irq = Q40_IRQ_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Roman Zippel77dda332006-06-25 05:47:05 -0700158 if (request_irq(timer_irq, q40_timer_int, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 "timer", q40_timer_int))
Roman Zippel77dda332006-06-25 05:47:05 -0700160 panic("Couldn't register timer int");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Roman Zippel77dda332006-06-25 05:47:05 -0700162 master_outb(-1, FRAME_CLEAR_REG);
163 master_outb( 1, FRAME_RATE_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
166
167/*
168 * tables to translate bits into IRQ numbers
169 * it is a good idea to order the entries by priority
170 *
171*/
172
173struct IRQ_TABLE{ unsigned mask; int irq ;};
174#if 0
175static struct IRQ_TABLE iirqs[]={
176 {Q40_IRQ_FRAME_MASK,Q40_IRQ_FRAME},
177 {Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
178 {0,0}};
179#endif
180static struct IRQ_TABLE eirqs[] = {
181 { .mask = Q40_IRQ3_MASK, .irq = 3 }, /* ser 1 */
182 { .mask = Q40_IRQ4_MASK, .irq = 4 }, /* ser 2 */
183 { .mask = Q40_IRQ14_MASK, .irq = 14 }, /* IDE 1 */
184 { .mask = Q40_IRQ15_MASK, .irq = 15 }, /* IDE 2 */
185 { .mask = Q40_IRQ6_MASK, .irq = 6 }, /* floppy, handled elsewhere */
186 { .mask = Q40_IRQ7_MASK, .irq = 7 }, /* par */
187 { .mask = Q40_IRQ5_MASK, .irq = 5 },
188 { .mask = Q40_IRQ10_MASK, .irq = 10 },
189 {0,0}
190};
191
192/* complain only this many times about spurious ints : */
Simon Arlott0c79cf62007-10-20 01:20:32 +0200193static int ccleirq=60; /* ISA dev IRQs*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194/*static int cclirq=60;*/ /* internal */
195
196/* FIXME: add shared ints,mask,unmask,probing.... */
197
198#define IRQ_INPROGRESS 1
199/*static unsigned short saved_mask;*/
200//static int do_tint=0;
201
202#define DEBUG_Q40INT
203/*#define IP_USE_DISABLE *//* would be nice, but crashes ???? */
204
205static int mext_disabled=0; /* ext irq disabled by master chip? */
206static int aliased_irq=0; /* how many times inside handler ?*/
207
208
Roman Zippel77dda332006-06-25 05:47:05 -0700209/* got interrupt, dispatch to ISA or keyboard/timer IRQs */
210static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
Roman Zippel77dda332006-06-25 05:47:05 -0700212 unsigned mir, mer;
213 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215//repeat:
Roman Zippel77dda332006-06-25 05:47:05 -0700216 mir = master_inb(IIRQ_REG);
217#ifdef CONFIG_BLK_DEV_FD
218 if ((mir & Q40_IRQ_EXT_MASK) &&
219 (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) {
220 floppy_hardint();
221 return;
222 }
223#endif
224 switch (irq) {
225 case 4:
226 case 6:
Geert Uytterhoeven1425df82011-07-01 20:39:19 +0200227 do_IRQ(Q40_IRQ_SAMPLE, fp);
Roman Zippel77dda332006-06-25 05:47:05 -0700228 return;
229 }
230 if (mir & Q40_IRQ_FRAME_MASK) {
Geert Uytterhoeven1425df82011-07-01 20:39:19 +0200231 do_IRQ(Q40_IRQ_FRAME, fp);
Roman Zippel77dda332006-06-25 05:47:05 -0700232 master_outb(-1, FRAME_CLEAR_REG);
233 }
234 if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
235 mer = master_inb(EIRQ_REG);
236 for (i = 0; eirqs[i].mask; i++) {
237 if (mer & eirqs[i].mask) {
238 irq = eirqs[i].irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239/*
240 * There is a little mess wrt which IRQ really caused this irq request. The
241 * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
242 * are read - which is long after the request came in. In theory IRQs should
Simon Arlott0c79cf62007-10-20 01:20:32 +0200243 * not just go away but they occasionally do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 */
Roman Zippel77dda332006-06-25 05:47:05 -0700245 if (irq > 4 && irq <= 15 && mext_disabled) {
246 /*aliased_irq++;*/
247 goto iirq;
248 }
249 if (q40_state[irq] & IRQ_INPROGRESS) {
250 /* some handlers do local_irq_enable() for irq latency reasons, */
251 /* however reentering an active irq handler is not permitted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252#ifdef IP_USE_DISABLE
Roman Zippel77dda332006-06-25 05:47:05 -0700253 /* in theory this is the better way to do it because it still */
254 /* lets through eg the serial irqs, unfortunately it crashes */
255 disable_irq(irq);
256 disabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257#else
Roman Zippel77dda332006-06-25 05:47:05 -0700258 /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",
259 irq, disabled ? "already" : "not yet"); */
260 fp->sr = (((fp->sr) & (~0x700))+0x200);
261 disabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262#endif
Roman Zippel77dda332006-06-25 05:47:05 -0700263 goto iirq;
264 }
265 q40_state[irq] |= IRQ_INPROGRESS;
Geert Uytterhoeven1425df82011-07-01 20:39:19 +0200266 do_IRQ(irq, fp);
Roman Zippel77dda332006-06-25 05:47:05 -0700267 q40_state[irq] &= ~IRQ_INPROGRESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Roman Zippel77dda332006-06-25 05:47:05 -0700269 /* naively enable everything, if that fails than */
270 /* this function will be reentered immediately thus */
271 /* getting another chance to disable the IRQ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Roman Zippel77dda332006-06-25 05:47:05 -0700273 if (disabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274#ifdef IP_USE_DISABLE
Roman Zippel77dda332006-06-25 05:47:05 -0700275 if (irq > 4) {
276 disabled = 0;
277 enable_irq(irq);
278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279#else
Roman Zippel77dda332006-06-25 05:47:05 -0700280 disabled = 0;
281 /*printk("reenabling irq %d\n", irq); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282#endif
Roman Zippel77dda332006-06-25 05:47:05 -0700283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284// used to do 'goto repeat;' here, this delayed bh processing too long
Roman Zippel77dda332006-06-25 05:47:05 -0700285 return;
286 }
287 }
288 if (mer && ccleirq > 0 && !aliased_irq) {
289 printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer);
290 ccleirq--;
291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 }
Roman Zippel77dda332006-06-25 05:47:05 -0700293 iirq:
294 mir = master_inb(IIRQ_REG);
295 /* should test whether keyboard irq is really enabled, doing it in defhand */
296 if (mir & Q40_IRQ_KEYB_MASK)
Geert Uytterhoeven1425df82011-07-01 20:39:19 +0200297 do_IRQ(Q40_IRQ_KEYBOARD, fp);
Roman Zippel77dda332006-06-25 05:47:05 -0700298
299 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +0200302void q40_irq_enable(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +0200304 unsigned int irq = data->irq;
305
Roman Zippel77dda332006-06-25 05:47:05 -0700306 if (irq >= 5 && irq <= 15) {
307 mext_disabled--;
308 if (mext_disabled > 0)
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +0200309 printk("q40_irq_enable : nested disable/enable\n");
Roman Zippel77dda332006-06-25 05:47:05 -0700310 if (mext_disabled == 0)
311 master_outb(1, EXT_ENABLE_REG);
312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +0200316void q40_irq_disable(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Geert Uytterhoevene8abf5e2011-04-17 22:53:04 +0200318 unsigned int irq = data->irq;
319
Roman Zippel77dda332006-06-25 05:47:05 -0700320 /* disable ISA iqs : only do something if the driver has been
321 * verified to be Q40 "compatible" - right now IDE, NE2K
322 * Any driver should not attempt to sleep across disable_irq !!
323 */
324
325 if (irq >= 5 && irq <= 15) {
326 master_outb(0, EXT_ENABLE_REG);
327 mext_disabled++;
328 if (mext_disabled > 1)
329 printk("disable_irq nesting count %d\n",mext_disabled);
330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Geert Uytterhoevena03010e2011-08-18 14:47:16 +0200333#ifndef CONFIG_GENERIC_HARDIRQS
Roman Zippel77dda332006-06-25 05:47:05 -0700334unsigned long q40_probe_irq_on(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Roman Zippel77dda332006-06-25 05:47:05 -0700336 printk("irq probing not working - reconfigure the driver to avoid this\n");
337 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338}
Roman Zippel77dda332006-06-25 05:47:05 -0700339int q40_probe_irq_off(unsigned long irqs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Roman Zippel77dda332006-06-25 05:47:05 -0700341 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342}
Geert Uytterhoevena03010e2011-08-18 14:47:16 +0200343#endif