1 /*
2  * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
3  *
4  * May be copied or modified under the terms of the GNU General Public
5  * License.  See linux/COPYING for more information.
6  *
7  * Looks after interrupts on the HARP board.
8  *
9  * Bases on the IPR irq system
10  */
11 
12 #include <linux/config.h>
13 #include <linux/init.h>
14 #include <linux/irq.h>
15 
16 #include <asm/system.h>
17 #include <asm/io.h>
18 
19 #include "harp.h"
20 
21 
22 #define NUM_EXTERNAL_IRQS 16
23 
24 // Early versions of the STB1 Overdrive required this nasty frig
25 //#define INVERT_INTMASK_WRITES
26 
27 static void enable_harp_irq(unsigned int irq);
28 static void disable_harp_irq(unsigned int irq);
29 
30 /* shutdown is same as "disable" */
31 #define shutdown_harp_irq disable_harp_irq
32 
33 static void mask_and_ack_harp(unsigned int);
34 static void end_harp_irq(unsigned int irq);
35 
startup_harp_irq(unsigned int irq)36 static unsigned int startup_harp_irq(unsigned int irq)
37 {
38 	enable_harp_irq(irq);
39 	return 0;		/* never anything pending */
40 }
41 
42 static struct hw_interrupt_type harp_irq_type = {
43 	"Harp-IRQ",
44 	startup_harp_irq,
45 	shutdown_harp_irq,
46 	enable_harp_irq,
47 	disable_harp_irq,
48 	mask_and_ack_harp,
49 	end_harp_irq
50 };
51 
disable_harp_irq(unsigned int irq)52 static void disable_harp_irq(unsigned int irq)
53 {
54 	unsigned val, flags;
55 	unsigned maskReg;
56 	unsigned mask;
57 	int pri;
58 
59 	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
60 		return;
61 
62 	pri = 15 - irq;
63 
64 	if (pri < 8) {
65 		maskReg = EPLD_INTMASK0;
66 	} else {
67 		maskReg = EPLD_INTMASK1;
68 		pri -= 8;
69 	}
70 
71 	save_and_cli(flags);
72 	mask = ctrl_inl(maskReg);
73 	mask &= (~(1 << pri));
74 #if defined(INVERT_INTMASK_WRITES)
75 	mask ^= 0xff;
76 #endif
77 	ctrl_outl(mask, maskReg);
78 	restore_flags(flags);
79 }
80 
enable_harp_irq(unsigned int irq)81 static void enable_harp_irq(unsigned int irq)
82 {
83 	unsigned flags;
84 	unsigned maskReg;
85 	unsigned mask;
86 	int pri;
87 
88 	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
89 		return;
90 
91 	pri = 15 - irq;
92 
93 	if (pri < 8) {
94 		maskReg = EPLD_INTMASK0;
95 	} else {
96 		maskReg = EPLD_INTMASK1;
97 		pri -= 8;
98 	}
99 
100 	save_and_cli(flags);
101 	mask = ctrl_inl(maskReg);
102 
103 
104 	mask |= (1 << pri);
105 
106 #if defined(INVERT_INTMASK_WRITES)
107 	mask ^= 0xff;
108 #endif
109 	ctrl_outl(mask, maskReg);
110 
111 	restore_flags(flags);
112 }
113 
114 /* This functions sets the desired irq handler to be an overdrive type */
make_harp_irq(unsigned int irq)115 static void __init make_harp_irq(unsigned int irq)
116 {
117 	disable_irq_nosync(irq);
118 	irq_desc[irq].handler = &harp_irq_type;
119 	disable_harp_irq(irq);
120 }
121 
mask_and_ack_harp(unsigned int irq)122 static void mask_and_ack_harp(unsigned int irq)
123 {
124 	disable_harp_irq(irq);
125 }
126 
end_harp_irq(unsigned int irq)127 static void end_harp_irq(unsigned int irq)
128 {
129 	enable_harp_irq(irq);
130 }
131 
init_harp_irq(void)132 void __init init_harp_irq(void)
133 {
134 	int i;
135 
136 #if !defined(INVERT_INTMASK_WRITES)
137 	// On the harp these are set to enable an interrupt
138 	ctrl_outl(0x00, EPLD_INTMASK0);
139 	ctrl_outl(0x00, EPLD_INTMASK1);
140 #else
141 	// On the Overdrive the data is inverted before being stored in the reg
142 	ctrl_outl(0xff, EPLD_INTMASK0);
143 	ctrl_outl(0xff, EPLD_INTMASK1);
144 #endif
145 
146 	for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
147 		make_harp_irq(i);
148 	}
149 }
150