diff options
Diffstat (limited to 'arch/mips/mips-boards/atlas/atlas_int.c')
-rw-r--r-- | arch/mips/mips-boards/atlas/atlas_int.c | 272 |
1 files changed, 0 insertions, 272 deletions
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c deleted file mode 100644 index 6fb29c3ff62d..000000000000 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ /dev/null | |||
@@ -1,272 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1999, 2000, 2006 MIPS Technologies, Inc. | ||
3 | * All rights reserved. | ||
4 | * Authors: Carsten Langgaard <carstenl@mips.com> | ||
5 | * Maciej W. Rozycki <macro@mips.com> | ||
6 | * | ||
7 | * ######################################################################## | ||
8 | * | ||
9 | * This program is free software; you can distribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License (Version 2) as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
16 | * for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
21 | * | ||
22 | * ######################################################################## | ||
23 | * | ||
24 | * Routines for generic manipulation of the interrupts found on the MIPS | ||
25 | * Atlas board. | ||
26 | * | ||
27 | */ | ||
28 | #include <linux/compiler.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/irq.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/kernel_stat.h> | ||
35 | #include <linux/kernel.h> | ||
36 | |||
37 | #include <asm/gdb-stub.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <asm/irq_cpu.h> | ||
40 | #include <asm/msc01_ic.h> | ||
41 | |||
42 | #include <asm/mips-boards/atlas.h> | ||
43 | #include <asm/mips-boards/atlasint.h> | ||
44 | #include <asm/mips-boards/generic.h> | ||
45 | |||
46 | static struct atlas_ictrl_regs *atlas_hw0_icregs; | ||
47 | |||
48 | #if 0 | ||
49 | #define DEBUG_INT(x...) printk(x) | ||
50 | #else | ||
51 | #define DEBUG_INT(x...) | ||
52 | #endif | ||
53 | |||
54 | void disable_atlas_irq(unsigned int irq_nr) | ||
55 | { | ||
56 | atlas_hw0_icregs->intrsten = 1 << (irq_nr - ATLAS_INT_BASE); | ||
57 | iob(); | ||
58 | } | ||
59 | |||
60 | void enable_atlas_irq(unsigned int irq_nr) | ||
61 | { | ||
62 | atlas_hw0_icregs->intseten = 1 << (irq_nr - ATLAS_INT_BASE); | ||
63 | iob(); | ||
64 | } | ||
65 | |||
66 | static void end_atlas_irq(unsigned int irq) | ||
67 | { | ||
68 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
69 | enable_atlas_irq(irq); | ||
70 | } | ||
71 | |||
72 | static struct irq_chip atlas_irq_type = { | ||
73 | .name = "Atlas", | ||
74 | .ack = disable_atlas_irq, | ||
75 | .mask = disable_atlas_irq, | ||
76 | .mask_ack = disable_atlas_irq, | ||
77 | .unmask = enable_atlas_irq, | ||
78 | .eoi = enable_atlas_irq, | ||
79 | .end = end_atlas_irq, | ||
80 | }; | ||
81 | |||
82 | static inline int ls1bit32(unsigned int x) | ||
83 | { | ||
84 | int b = 31, s; | ||
85 | |||
86 | s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; | ||
87 | s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; | ||
88 | s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; | ||
89 | s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; | ||
90 | s = 1; if (x << 1 == 0) s = 0; b -= s; | ||
91 | |||
92 | return b; | ||
93 | } | ||
94 | |||
95 | static inline void atlas_hw0_irqdispatch(void) | ||
96 | { | ||
97 | unsigned long int_status; | ||
98 | int irq; | ||
99 | |||
100 | int_status = atlas_hw0_icregs->intstatus; | ||
101 | |||
102 | /* if int_status == 0, then the interrupt has already been cleared */ | ||
103 | if (unlikely(int_status == 0)) | ||
104 | return; | ||
105 | |||
106 | irq = ATLAS_INT_BASE + ls1bit32(int_status); | ||
107 | |||
108 | DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); | ||
109 | |||
110 | do_IRQ(irq); | ||
111 | } | ||
112 | |||
113 | static inline int clz(unsigned long x) | ||
114 | { | ||
115 | __asm__( | ||
116 | " .set push \n" | ||
117 | " .set mips32 \n" | ||
118 | " clz %0, %1 \n" | ||
119 | " .set pop \n" | ||
120 | : "=r" (x) | ||
121 | : "r" (x)); | ||
122 | |||
123 | return x; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Version of ffs that only looks at bits 12..15. | ||
128 | */ | ||
129 | static inline unsigned int irq_ffs(unsigned int pending) | ||
130 | { | ||
131 | #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) | ||
132 | return -clz(pending) + 31 - CAUSEB_IP; | ||
133 | #else | ||
134 | unsigned int a0 = 7; | ||
135 | unsigned int t0; | ||
136 | |||
137 | t0 = s0 & 0xf000; | ||
138 | t0 = t0 < 1; | ||
139 | t0 = t0 << 2; | ||
140 | a0 = a0 - t0; | ||
141 | s0 = s0 << t0; | ||
142 | |||
143 | t0 = s0 & 0xc000; | ||
144 | t0 = t0 < 1; | ||
145 | t0 = t0 << 1; | ||
146 | a0 = a0 - t0; | ||
147 | s0 = s0 << t0; | ||
148 | |||
149 | t0 = s0 & 0x8000; | ||
150 | t0 = t0 < 1; | ||
151 | //t0 = t0 << 2; | ||
152 | a0 = a0 - t0; | ||
153 | //s0 = s0 << t0; | ||
154 | |||
155 | return a0; | ||
156 | #endif | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * IRQs on the Atlas board look basically like (all external interrupt | ||
161 | * sources are combined together on hardware interrupt 0 (MIPS IRQ 2)): | ||
162 | * | ||
163 | * MIPS IRQ Source | ||
164 | * -------- ------ | ||
165 | * 0 Software 0 (reschedule IPI on MT) | ||
166 | * 1 Software 1 (remote call IPI on MT) | ||
167 | * 2 Combined Atlas hardware interrupt (hw0) | ||
168 | * 3 Hardware (ignored) | ||
169 | * 4 Hardware (ignored) | ||
170 | * 5 Hardware (ignored) | ||
171 | * 6 Hardware (ignored) | ||
172 | * 7 R4k timer (what we use) | ||
173 | * | ||
174 | * We handle the IRQ according to _our_ priority which is: | ||
175 | * | ||
176 | * Highest ---- R4k Timer | ||
177 | * Lowest ---- Software 0 | ||
178 | * | ||
179 | * then we just return, if multiple IRQs are pending then we will just take | ||
180 | * another exception, big deal. | ||
181 | */ | ||
182 | asmlinkage void plat_irq_dispatch(void) | ||
183 | { | ||
184 | unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; | ||
185 | int irq; | ||
186 | |||
187 | irq = irq_ffs(pending); | ||
188 | |||
189 | if (irq == MIPSCPU_INT_ATLAS) | ||
190 | atlas_hw0_irqdispatch(); | ||
191 | else if (irq >= 0) | ||
192 | do_IRQ(MIPS_CPU_IRQ_BASE + irq); | ||
193 | else | ||
194 | spurious_interrupt(); | ||
195 | } | ||
196 | |||
197 | static inline void init_atlas_irqs(int base) | ||
198 | { | ||
199 | int i; | ||
200 | |||
201 | atlas_hw0_icregs = (struct atlas_ictrl_regs *) | ||
202 | ioremap(ATLAS_ICTRL_REGS_BASE, | ||
203 | sizeof(struct atlas_ictrl_regs *)); | ||
204 | |||
205 | /* | ||
206 | * Mask out all interrupt by writing "1" to all bit position in | ||
207 | * the interrupt reset reg. | ||
208 | */ | ||
209 | atlas_hw0_icregs->intrsten = 0xffffffff; | ||
210 | |||
211 | for (i = ATLAS_INT_BASE; i <= ATLAS_INT_END; i++) | ||
212 | set_irq_chip_and_handler(i, &atlas_irq_type, handle_level_irq); | ||
213 | } | ||
214 | |||
215 | static struct irqaction atlasirq = { | ||
216 | .handler = no_action, | ||
217 | .name = "Atlas cascade" | ||
218 | }; | ||
219 | |||
220 | msc_irqmap_t __initdata msc_irqmap[] = { | ||
221 | {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, | ||
222 | {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, | ||
223 | }; | ||
224 | int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); | ||
225 | |||
226 | msc_irqmap_t __initdata msc_eicirqmap[] = { | ||
227 | {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, | ||
228 | {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, | ||
229 | {MSC01E_INT_ATLAS, MSC01_IRQ_LEVEL, 0}, | ||
230 | {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, | ||
231 | {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, | ||
232 | {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, | ||
233 | {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} | ||
234 | }; | ||
235 | int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); | ||
236 | |||
237 | void __init arch_init_irq(void) | ||
238 | { | ||
239 | init_atlas_irqs(ATLAS_INT_BASE); | ||
240 | |||
241 | if (!cpu_has_veic) | ||
242 | mips_cpu_irq_init(); | ||
243 | |||
244 | switch(mips_revision_corid) { | ||
245 | case MIPS_REVISION_CORID_CORE_MSC: | ||
246 | case MIPS_REVISION_CORID_CORE_FPGA2: | ||
247 | case MIPS_REVISION_CORID_CORE_FPGA3: | ||
248 | case MIPS_REVISION_CORID_CORE_FPGA4: | ||
249 | case MIPS_REVISION_CORID_CORE_24K: | ||
250 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | ||
251 | if (cpu_has_veic) | ||
252 | init_msc_irqs(MSC01E_INT_BASE, MSC01E_INT_BASE, | ||
253 | msc_eicirqmap, msc_nr_eicirqs); | ||
254 | else | ||
255 | init_msc_irqs(MSC01E_INT_BASE, MSC01C_INT_BASE, | ||
256 | msc_irqmap, msc_nr_irqs); | ||
257 | } | ||
258 | |||
259 | if (cpu_has_veic) { | ||
260 | set_vi_handler(MSC01E_INT_ATLAS, atlas_hw0_irqdispatch); | ||
261 | setup_irq(MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq); | ||
262 | } else if (cpu_has_vint) { | ||
263 | set_vi_handler(MIPSCPU_INT_ATLAS, atlas_hw0_irqdispatch); | ||
264 | #ifdef CONFIG_MIPS_MT_SMTC | ||
265 | setup_irq_smtc(MIPS_CPU_IRQ_BASE + MIPSCPU_INT_ATLAS, | ||
266 | &atlasirq, (0x100 << MIPSCPU_INT_ATLAS)); | ||
267 | #else /* Not SMTC */ | ||
268 | setup_irq(MIPS_CPU_IRQ_BASE + MIPSCPU_INT_ATLAS, &atlasirq); | ||
269 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
270 | } else | ||
271 | setup_irq(MIPS_CPU_IRQ_BASE + MIPSCPU_INT_ATLAS, &atlasirq); | ||
272 | } | ||