]>
Commit | Line | Data |
---|---|---|
1394f032 | 1 | /* |
96f1050d | 2 | * Set up the interrupt priorities |
1394f032 | 3 | * |
96f1050d RG |
4 | * Copyright 2004-2009 Analog Devices Inc. |
5 | * 2003 Bas Vermeulen <bas@buyways.nl> | |
6 | * 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> | |
7 | * 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> | |
8 | * 1999 D. Jeff Dionne <jeff@uclinux.org> | |
9 | * 1996 Roman Zippel | |
1394f032 | 10 | * |
96f1050d | 11 | * Licensed under the GPL-2 |
1394f032 BW |
12 | */ |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/kernel_stat.h> | |
16 | #include <linux/seq_file.h> | |
17 | #include <linux/irq.h> | |
5b5da4c4 | 18 | #include <linux/sched.h> |
4f6b600f SM |
19 | #include <linux/syscore_ops.h> |
20 | #include <asm/delay.h> | |
6a01f230 YL |
21 | #ifdef CONFIG_IPIPE |
22 | #include <linux/ipipe.h> | |
23 | #endif | |
1394f032 BW |
24 | #include <asm/traps.h> |
25 | #include <asm/blackfin.h> | |
26 | #include <asm/gpio.h> | |
27 | #include <asm/irq_handler.h> | |
761ec44a | 28 | #include <asm/dpmc.h> |
06051fde | 29 | #include <asm/traps.h> |
1394f032 | 30 | |
1394f032 BW |
31 | /* |
32 | * NOTES: | |
33 | * - we have separated the physical Hardware interrupt from the | |
34 | * levels that the LINUX kernel sees (see the description in irq.h) | |
35 | * - | |
36 | */ | |
37 | ||
6b3087c6 | 38 | #ifndef CONFIG_SMP |
a99bbccd MF |
39 | /* Initialize this to an actual value to force it into the .data |
40 | * section so that we know it is properly initialized at entry into | |
41 | * the kernel but before bss is initialized to zero (which is where | |
42 | * it would live otherwise). The 0x1f magic represents the IRQs we | |
43 | * cannot actually mask out in hardware. | |
44 | */ | |
40059784 MF |
45 | unsigned long bfin_irq_flags = 0x1f; |
46 | EXPORT_SYMBOL(bfin_irq_flags); | |
6b3087c6 | 47 | #endif |
1394f032 | 48 | |
cfefe3c6 MH |
49 | #ifdef CONFIG_PM |
50 | unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */ | |
4a88d0ce | 51 | unsigned vr_wakeup; |
cfefe3c6 MH |
52 | #endif |
53 | ||
11b27cb5 | 54 | #ifndef SEC_GCTL |
e9e334c3 | 55 | static struct ivgx { |
464abc5d | 56 | /* irq number for request_irq, available in mach-bf5xx/irq.h */ |
24a07a12 | 57 | unsigned int irqno; |
1394f032 | 58 | /* corresponding bit in the SIC_ISR register */ |
24a07a12 | 59 | unsigned int isrflag; |
1394f032 BW |
60 | } ivg_table[NR_PERI_INTS]; |
61 | ||
e9e334c3 | 62 | static struct ivg_slice { |
1394f032 BW |
63 | /* position of first irq in ivg_table for given ivg */ |
64 | struct ivgx *ifirst; | |
65 | struct ivgx *istop; | |
66 | } ivg7_13[IVG13 - IVG7 + 1]; | |
67 | ||
1394f032 BW |
68 | |
69 | /* | |
70 | * Search SIC_IAR and fill tables with the irqvalues | |
71 | * and their positions in the SIC_ISR register. | |
72 | */ | |
73 | static void __init search_IAR(void) | |
74 | { | |
75 | unsigned ivg, irq_pos = 0; | |
76 | for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) { | |
80fcdb95 | 77 | int irqN; |
1394f032 | 78 | |
34e0fc89 | 79 | ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos]; |
1394f032 | 80 | |
80fcdb95 MF |
81 | for (irqN = 0; irqN < NR_PERI_INTS; irqN += 4) { |
82 | int irqn; | |
4f6b600f SM |
83 | u32 iar = |
84 | bfin_read32((unsigned long *)SIC_IAR0 + | |
80fcdb95 MF |
85 | #if defined(CONFIG_BF51x) || defined(CONFIG_BF52x) || \ |
86 | defined(CONFIG_BF538) || defined(CONFIG_BF539) | |
87 | ((irqN % 32) >> 3) + ((irqN / 32) * ((SIC_IAR4 - SIC_IAR0) / 4)) | |
59003145 | 88 | #else |
80fcdb95 | 89 | (irqN >> 3) |
59003145 | 90 | #endif |
80fcdb95 | 91 | ); |
80fcdb95 MF |
92 | for (irqn = irqN; irqn < irqN + 4; ++irqn) { |
93 | int iar_shift = (irqn & 7) * 4; | |
94 | if (ivg == (0xf & (iar >> iar_shift))) { | |
95 | ivg_table[irq_pos].irqno = IVG7 + irqn; | |
96 | ivg_table[irq_pos].isrflag = 1 << (irqn % 32); | |
97 | ivg7_13[ivg].istop++; | |
98 | irq_pos++; | |
99 | } | |
1394f032 BW |
100 | } |
101 | } | |
102 | } | |
103 | } | |
4f6b600f | 104 | #endif |
1394f032 BW |
105 | |
106 | /* | |
464abc5d | 107 | * This is for core internal IRQs |
1394f032 | 108 | */ |
f58c3276 | 109 | void bfin_ack_noop(struct irq_data *d) |
1394f032 BW |
110 | { |
111 | /* Dummy function. */ | |
112 | } | |
113 | ||
4f19ea49 | 114 | static void bfin_core_mask_irq(struct irq_data *d) |
1394f032 | 115 | { |
4f19ea49 | 116 | bfin_irq_flags &= ~(1 << d->irq); |
3b139cdb DH |
117 | if (!hard_irqs_disabled()) |
118 | hard_local_irq_enable(); | |
1394f032 BW |
119 | } |
120 | ||
4f19ea49 | 121 | static void bfin_core_unmask_irq(struct irq_data *d) |
1394f032 | 122 | { |
4f19ea49 | 123 | bfin_irq_flags |= 1 << d->irq; |
1394f032 BW |
124 | /* |
125 | * If interrupts are enabled, IMASK must contain the same value | |
40059784 | 126 | * as bfin_irq_flags. Make sure that invariant holds. If interrupts |
1394f032 BW |
127 | * are currently disabled we need not do anything; one of the |
128 | * callers will take care of setting IMASK to the proper value | |
129 | * when reenabling interrupts. | |
40059784 | 130 | * local_irq_enable just does "STI bfin_irq_flags", so it's exactly |
1394f032 BW |
131 | * what we need. |
132 | */ | |
3b139cdb DH |
133 | if (!hard_irqs_disabled()) |
134 | hard_local_irq_enable(); | |
1394f032 BW |
135 | return; |
136 | } | |
137 | ||
86794b43 | 138 | #ifndef SEC_GCTL |
f58c3276 | 139 | void bfin_internal_mask_irq(unsigned int irq) |
1394f032 | 140 | { |
fc6bd7b8 | 141 | unsigned long flags = hard_local_irq_save(); |
fc6bd7b8 | 142 | #ifdef SIC_IMASK0 |
86794b43 SZ |
143 | unsigned mask_bank = BFIN_SYSIRQ(irq) / 32; |
144 | unsigned mask_bit = BFIN_SYSIRQ(irq) % 32; | |
c04d66bb | 145 | bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & |
4f6b600f SM |
146 | ~(1 << mask_bit)); |
147 | # if defined(CONFIG_SMP) || defined(CONFIG_ICC) | |
6b3087c6 | 148 | bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) & |
4f6b600f | 149 | ~(1 << mask_bit)); |
fc6bd7b8 MF |
150 | # endif |
151 | #else | |
152 | bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & | |
86794b43 | 153 | ~(1 << BFIN_SYSIRQ(irq))); |
4f6b600f | 154 | #endif /* end of SIC_IMASK0 */ |
3b139cdb | 155 | hard_local_irq_restore(flags); |
1394f032 BW |
156 | } |
157 | ||
ff43a67f TG |
158 | static void bfin_internal_mask_irq_chip(struct irq_data *d) |
159 | { | |
160 | bfin_internal_mask_irq(d->irq); | |
161 | } | |
162 | ||
0325f25a | 163 | #ifdef CONFIG_SMP |
4f6b600f | 164 | void bfin_internal_unmask_irq_affinity(unsigned int irq, |
0325f25a SZ |
165 | const struct cpumask *affinity) |
166 | #else | |
f58c3276 | 167 | void bfin_internal_unmask_irq(unsigned int irq) |
0325f25a | 168 | #endif |
1394f032 | 169 | { |
fc6bd7b8 | 170 | unsigned long flags = hard_local_irq_save(); |
9bd50df6 | 171 | |
fc6bd7b8 | 172 | #ifdef SIC_IMASK0 |
86794b43 SZ |
173 | unsigned mask_bank = BFIN_SYSIRQ(irq) / 32; |
174 | unsigned mask_bit = BFIN_SYSIRQ(irq) % 32; | |
fc6bd7b8 | 175 | # ifdef CONFIG_SMP |
0325f25a | 176 | if (cpumask_test_cpu(0, affinity)) |
fc6bd7b8 | 177 | # endif |
0325f25a | 178 | bfin_write_SIC_IMASK(mask_bank, |
4f6b600f SM |
179 | bfin_read_SIC_IMASK(mask_bank) | |
180 | (1 << mask_bit)); | |
fc6bd7b8 | 181 | # ifdef CONFIG_SMP |
0325f25a SZ |
182 | if (cpumask_test_cpu(1, affinity)) |
183 | bfin_write_SICB_IMASK(mask_bank, | |
4f6b600f SM |
184 | bfin_read_SICB_IMASK(mask_bank) | |
185 | (1 << mask_bit)); | |
fc6bd7b8 MF |
186 | # endif |
187 | #else | |
188 | bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | | |
86794b43 SZ |
189 | (1 << BFIN_SYSIRQ(irq))); |
190 | #endif | |
191 | hard_local_irq_restore(flags); | |
192 | } | |
193 | ||
194 | #ifdef CONFIG_SMP | |
195 | static void bfin_internal_unmask_irq_chip(struct irq_data *d) | |
196 | { | |
247bd4f1 JL |
197 | bfin_internal_unmask_irq_affinity(d->irq, |
198 | irq_data_get_affinity_mask(d)); | |
86794b43 SZ |
199 | } |
200 | ||
201 | static int bfin_internal_set_affinity(struct irq_data *d, | |
202 | const struct cpumask *mask, bool force) | |
203 | { | |
204 | bfin_internal_mask_irq(d->irq); | |
205 | bfin_internal_unmask_irq_affinity(d->irq, mask); | |
206 | ||
207 | return 0; | |
208 | } | |
209 | #else | |
210 | static void bfin_internal_unmask_irq_chip(struct irq_data *d) | |
211 | { | |
212 | bfin_internal_unmask_irq(d->irq); | |
213 | } | |
4f6b600f | 214 | #endif |
86794b43 SZ |
215 | |
216 | #if defined(CONFIG_PM) | |
217 | int bfin_internal_set_wake(unsigned int irq, unsigned int state) | |
218 | { | |
219 | u32 bank, bit, wakeup = 0; | |
220 | unsigned long flags; | |
221 | bank = BFIN_SYSIRQ(irq) / 32; | |
222 | bit = BFIN_SYSIRQ(irq) % 32; | |
223 | ||
224 | switch (irq) { | |
225 | #ifdef IRQ_RTC | |
226 | case IRQ_RTC: | |
227 | wakeup |= WAKE; | |
228 | break; | |
229 | #endif | |
230 | #ifdef IRQ_CAN0_RX | |
231 | case IRQ_CAN0_RX: | |
232 | wakeup |= CANWE; | |
233 | break; | |
6b3087c6 | 234 | #endif |
86794b43 SZ |
235 | #ifdef IRQ_CAN1_RX |
236 | case IRQ_CAN1_RX: | |
237 | wakeup |= CANWE; | |
238 | break; | |
239 | #endif | |
240 | #ifdef IRQ_USB_INT0 | |
241 | case IRQ_USB_INT0: | |
242 | wakeup |= USBWE; | |
243 | break; | |
244 | #endif | |
245 | #ifdef CONFIG_BF54x | |
246 | case IRQ_CNT: | |
247 | wakeup |= ROTWE; | |
248 | break; | |
249 | #endif | |
250 | default: | |
251 | break; | |
252 | } | |
253 | ||
254 | flags = hard_local_irq_save(); | |
255 | ||
256 | if (state) { | |
257 | bfin_sic_iwr[bank] |= (1 << bit); | |
258 | vr_wakeup |= wakeup; | |
259 | ||
260 | } else { | |
261 | bfin_sic_iwr[bank] &= ~(1 << bit); | |
262 | vr_wakeup &= ~wakeup; | |
263 | } | |
264 | ||
4f6b600f | 265 | hard_local_irq_restore(flags); |
86794b43 SZ |
266 | |
267 | return 0; | |
4f6b600f SM |
268 | } |
269 | ||
86794b43 SZ |
270 | static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state) |
271 | { | |
272 | return bfin_internal_set_wake(d->irq, state); | |
273 | } | |
274 | #else | |
275 | inline int bfin_internal_set_wake(unsigned int irq, unsigned int state) | |
276 | { | |
277 | return 0; | |
278 | } | |
279 | # define bfin_internal_set_wake_chip NULL | |
280 | #endif | |
281 | ||
282 | #else /* SEC_GCTL */ | |
4f6b600f SM |
283 | static void bfin_sec_preflow_handler(struct irq_data *d) |
284 | { | |
285 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 286 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
287 | |
288 | bfin_write_SEC_SCI(0, SEC_CSID, sid); | |
289 | ||
290 | hard_local_irq_restore(flags); | |
291 | } | |
292 | ||
293 | static void bfin_sec_mask_ack_irq(struct irq_data *d) | |
294 | { | |
295 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 296 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
297 | |
298 | bfin_write_SEC_SCI(0, SEC_CSID, sid); | |
299 | ||
300 | hard_local_irq_restore(flags); | |
301 | } | |
302 | ||
303 | static void bfin_sec_unmask_irq(struct irq_data *d) | |
304 | { | |
305 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 306 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
307 | |
308 | bfin_write32(SEC_END, sid); | |
309 | ||
310 | hard_local_irq_restore(flags); | |
311 | } | |
312 | ||
313 | static void bfin_sec_enable_ssi(unsigned int sid) | |
314 | { | |
315 | unsigned long flags = hard_local_irq_save(); | |
316 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
317 | ||
318 | reg_sctl |= SEC_SCTL_SRC_EN; | |
319 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
320 | ||
321 | hard_local_irq_restore(flags); | |
322 | } | |
323 | ||
324 | static void bfin_sec_disable_ssi(unsigned int sid) | |
325 | { | |
326 | unsigned long flags = hard_local_irq_save(); | |
327 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
328 | ||
329 | reg_sctl &= ((uint32_t)~SEC_SCTL_SRC_EN); | |
330 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
331 | ||
332 | hard_local_irq_restore(flags); | |
333 | } | |
334 | ||
335 | static void bfin_sec_set_ssi_coreid(unsigned int sid, unsigned int coreid) | |
336 | { | |
337 | unsigned long flags = hard_local_irq_save(); | |
338 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
339 | ||
340 | reg_sctl &= ((uint32_t)~SEC_SCTL_CTG); | |
341 | bfin_write_SEC_SCTL(sid, reg_sctl | ((coreid << 20) & SEC_SCTL_CTG)); | |
342 | ||
343 | hard_local_irq_restore(flags); | |
344 | } | |
345 | ||
346 | static void bfin_sec_enable_sci(unsigned int sid) | |
347 | { | |
348 | unsigned long flags = hard_local_irq_save(); | |
349 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
350 | ||
86794b43 | 351 | if (sid == BFIN_SYSIRQ(IRQ_WATCH0)) |
4f6b600f SM |
352 | reg_sctl |= SEC_SCTL_FAULT_EN; |
353 | else | |
354 | reg_sctl |= SEC_SCTL_INT_EN; | |
355 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
356 | ||
357 | hard_local_irq_restore(flags); | |
358 | } | |
359 | ||
360 | static void bfin_sec_disable_sci(unsigned int sid) | |
361 | { | |
362 | unsigned long flags = hard_local_irq_save(); | |
363 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
364 | ||
365 | reg_sctl &= ((uint32_t)~SEC_SCTL_INT_EN); | |
366 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
367 | ||
368 | hard_local_irq_restore(flags); | |
369 | } | |
370 | ||
371 | static void bfin_sec_enable(struct irq_data *d) | |
372 | { | |
373 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 374 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
375 | |
376 | bfin_sec_enable_sci(sid); | |
377 | bfin_sec_enable_ssi(sid); | |
fc6bd7b8 | 378 | |
3b139cdb | 379 | hard_local_irq_restore(flags); |
1394f032 BW |
380 | } |
381 | ||
4f6b600f SM |
382 | static void bfin_sec_disable(struct irq_data *d) |
383 | { | |
384 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 385 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
386 | |
387 | bfin_sec_disable_sci(sid); | |
388 | bfin_sec_disable_ssi(sid); | |
389 | ||
390 | hard_local_irq_restore(flags); | |
391 | } | |
392 | ||
e0a59310 SZ |
393 | static void bfin_sec_set_priority(unsigned int sec_int_levels, u8 *sec_int_priority) |
394 | { | |
395 | unsigned long flags = hard_local_irq_save(); | |
396 | uint32_t reg_sctl; | |
397 | int i; | |
398 | ||
399 | bfin_write_SEC_SCI(0, SEC_CPLVL, sec_int_levels); | |
400 | ||
401 | for (i = 0; i < SYS_IRQS - BFIN_IRQ(0); i++) { | |
402 | reg_sctl = bfin_read_SEC_SCTL(i) & ~SEC_SCTL_PRIO; | |
403 | reg_sctl |= sec_int_priority[i] << SEC_SCTL_PRIO_OFFSET; | |
404 | bfin_write_SEC_SCTL(i, reg_sctl); | |
405 | } | |
406 | ||
407 | hard_local_irq_restore(flags); | |
408 | } | |
409 | ||
86794b43 | 410 | void bfin_sec_raise_irq(unsigned int irq) |
4f6b600f SM |
411 | { |
412 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 413 | unsigned int sid = BFIN_SYSIRQ(irq); |
4f6b600f SM |
414 | |
415 | bfin_write32(SEC_RAISE, sid); | |
416 | ||
417 | hard_local_irq_restore(flags); | |
418 | } | |
419 | ||
420 | static void init_software_driven_irq(void) | |
421 | { | |
422 | bfin_sec_set_ssi_coreid(34, 0); | |
423 | bfin_sec_set_ssi_coreid(35, 1); | |
86794b43 SZ |
424 | |
425 | bfin_sec_enable_sci(35); | |
426 | bfin_sec_enable_ssi(35); | |
4f6b600f SM |
427 | bfin_sec_set_ssi_coreid(36, 0); |
428 | bfin_sec_set_ssi_coreid(37, 1); | |
86794b43 SZ |
429 | bfin_sec_enable_sci(37); |
430 | bfin_sec_enable_ssi(37); | |
4f6b600f SM |
431 | } |
432 | ||
4f6b600f SM |
433 | void handle_sec_sfi_fault(uint32_t gstat) |
434 | { | |
435 | ||
436 | } | |
437 | ||
438 | void handle_sec_sci_fault(uint32_t gstat) | |
439 | { | |
440 | uint32_t core_id; | |
441 | uint32_t cstat; | |
442 | ||
443 | core_id = gstat & SEC_GSTAT_SCI; | |
444 | cstat = bfin_read_SEC_SCI(core_id, SEC_CSTAT); | |
445 | if (cstat & SEC_CSTAT_ERR) { | |
446 | switch (cstat & SEC_CSTAT_ERRC) { | |
447 | case SEC_CSTAT_ACKERR: | |
448 | printk(KERN_DEBUG "sec ack err\n"); | |
449 | break; | |
450 | default: | |
9b13494c | 451 | printk(KERN_DEBUG "sec sci unknown err\n"); |
4f6b600f SM |
452 | } |
453 | } | |
454 | ||
455 | } | |
456 | ||
457 | void handle_sec_ssi_fault(uint32_t gstat) | |
458 | { | |
459 | uint32_t sid; | |
460 | uint32_t sstat; | |
461 | ||
462 | sid = gstat & SEC_GSTAT_SID; | |
463 | sstat = bfin_read_SEC_SSTAT(sid); | |
464 | ||
465 | } | |
466 | ||
1b601239 | 467 | void handle_sec_fault(uint32_t sec_gstat) |
4f6b600f | 468 | { |
4f6b600f SM |
469 | if (sec_gstat & SEC_GSTAT_ERR) { |
470 | ||
471 | switch (sec_gstat & SEC_GSTAT_ERRC) { | |
472 | case 0: | |
473 | handle_sec_sfi_fault(sec_gstat); | |
474 | break; | |
475 | case SEC_GSTAT_SCIERR: | |
476 | handle_sec_sci_fault(sec_gstat); | |
477 | break; | |
478 | case SEC_GSTAT_SSIERR: | |
479 | handle_sec_ssi_fault(sec_gstat); | |
480 | break; | |
481 | } | |
482 | ||
483 | ||
484 | } | |
4f6b600f SM |
485 | } |
486 | ||
1b601239 SZ |
487 | static struct irqaction bfin_fault_irq = { |
488 | .name = "Blackfin fault", | |
489 | }; | |
490 | ||
491 | static irqreturn_t bfin_fault_routine(int irq, void *data) | |
06051fde SZ |
492 | { |
493 | struct pt_regs *fp = get_irq_regs(); | |
494 | ||
06051fde SZ |
495 | switch (irq) { |
496 | case IRQ_C0_DBL_FAULT: | |
497 | double_fault_c(fp); | |
498 | break; | |
499 | case IRQ_C0_HW_ERR: | |
500 | dump_bfin_process(fp); | |
501 | dump_bfin_mem(fp); | |
502 | show_regs(fp); | |
503 | printk(KERN_NOTICE "Kernel Stack\n"); | |
504 | show_stack(current, NULL); | |
505 | print_modules(); | |
86794b43 | 506 | panic("Core 0 hardware error"); |
06051fde SZ |
507 | break; |
508 | case IRQ_C0_NMI_L1_PARITY_ERR: | |
86794b43 | 509 | panic("Core 0 NMI L1 parity error"); |
06051fde | 510 | break; |
1b601239 SZ |
511 | case IRQ_SEC_ERR: |
512 | pr_err("SEC error\n"); | |
513 | handle_sec_fault(bfin_read32(SEC_GSTAT)); | |
514 | break; | |
06051fde | 515 | default: |
1b601239 | 516 | panic("Unknown fault %d", irq); |
06051fde SZ |
517 | } |
518 | ||
1b601239 | 519 | return IRQ_HANDLED; |
06051fde | 520 | } |
86794b43 | 521 | #endif /* SEC_GCTL */ |
cfefe3c6 | 522 | |
1394f032 | 523 | static struct irq_chip bfin_core_irqchip = { |
763e63c6 | 524 | .name = "CORE", |
4f19ea49 TG |
525 | .irq_mask = bfin_core_mask_irq, |
526 | .irq_unmask = bfin_core_unmask_irq, | |
1394f032 BW |
527 | }; |
528 | ||
86794b43 | 529 | #ifndef SEC_GCTL |
1394f032 | 530 | static struct irq_chip bfin_internal_irqchip = { |
763e63c6 | 531 | .name = "INTN", |
ff43a67f TG |
532 | .irq_mask = bfin_internal_mask_irq_chip, |
533 | .irq_unmask = bfin_internal_unmask_irq_chip, | |
ff43a67f TG |
534 | .irq_disable = bfin_internal_mask_irq_chip, |
535 | .irq_enable = bfin_internal_unmask_irq_chip, | |
0325f25a | 536 | #ifdef CONFIG_SMP |
ff43a67f | 537 | .irq_set_affinity = bfin_internal_set_affinity, |
0325f25a | 538 | #endif |
ff43a67f | 539 | .irq_set_wake = bfin_internal_set_wake_chip, |
1394f032 | 540 | }; |
86794b43 | 541 | #else |
4f6b600f SM |
542 | static struct irq_chip bfin_sec_irqchip = { |
543 | .name = "SEC", | |
544 | .irq_mask_ack = bfin_sec_mask_ack_irq, | |
545 | .irq_mask = bfin_sec_mask_ack_irq, | |
546 | .irq_unmask = bfin_sec_unmask_irq, | |
547 | .irq_eoi = bfin_sec_unmask_irq, | |
548 | .irq_disable = bfin_sec_disable, | |
549 | .irq_enable = bfin_sec_enable, | |
550 | }; | |
551 | #endif | |
552 | ||
f58c3276 | 553 | void bfin_handle_irq(unsigned irq) |
6a01f230 YL |
554 | { |
555 | #ifdef CONFIG_IPIPE | |
556 | struct pt_regs regs; /* Contents not used. */ | |
557 | ipipe_trace_irq_entry(irq); | |
558 | __ipipe_handle_irq(irq, ®s); | |
559 | ipipe_trace_irq_exit(irq); | |
560 | #else /* !CONFIG_IPIPE */ | |
b10bbbbc | 561 | generic_handle_irq(irq); |
6a01f230 YL |
562 | #endif /* !CONFIG_IPIPE */ |
563 | } | |
564 | ||
aec59c91 MH |
565 | #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) |
566 | static int mac_stat_int_mask; | |
567 | ||
568 | static void bfin_mac_status_ack_irq(unsigned int irq) | |
569 | { | |
570 | switch (irq) { | |
571 | case IRQ_MAC_MMCINT: | |
572 | bfin_write_EMAC_MMC_TIRQS( | |
573 | bfin_read_EMAC_MMC_TIRQE() & | |
574 | bfin_read_EMAC_MMC_TIRQS()); | |
575 | bfin_write_EMAC_MMC_RIRQS( | |
576 | bfin_read_EMAC_MMC_RIRQE() & | |
577 | bfin_read_EMAC_MMC_RIRQS()); | |
578 | break; | |
579 | case IRQ_MAC_RXFSINT: | |
580 | bfin_write_EMAC_RX_STKY( | |
581 | bfin_read_EMAC_RX_IRQE() & | |
582 | bfin_read_EMAC_RX_STKY()); | |
583 | break; | |
584 | case IRQ_MAC_TXFSINT: | |
585 | bfin_write_EMAC_TX_STKY( | |
586 | bfin_read_EMAC_TX_IRQE() & | |
587 | bfin_read_EMAC_TX_STKY()); | |
588 | break; | |
589 | case IRQ_MAC_WAKEDET: | |
590 | bfin_write_EMAC_WKUP_CTL( | |
591 | bfin_read_EMAC_WKUP_CTL() | MPKS | RWKS); | |
592 | break; | |
593 | default: | |
594 | /* These bits are W1C */ | |
595 | bfin_write_EMAC_SYSTAT(1L << (irq - IRQ_MAC_PHYINT)); | |
596 | break; | |
597 | } | |
598 | } | |
599 | ||
172d2d1d | 600 | static void bfin_mac_status_mask_irq(struct irq_data *d) |
aec59c91 | 601 | { |
172d2d1d TG |
602 | unsigned int irq = d->irq; |
603 | ||
aec59c91 | 604 | mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT)); |
f58c3276 | 605 | #ifdef BF537_FAMILY |
aec59c91 MH |
606 | switch (irq) { |
607 | case IRQ_MAC_PHYINT: | |
608 | bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE); | |
609 | break; | |
610 | default: | |
611 | break; | |
612 | } | |
613 | #else | |
614 | if (!mac_stat_int_mask) | |
615 | bfin_internal_mask_irq(IRQ_MAC_ERROR); | |
616 | #endif | |
617 | bfin_mac_status_ack_irq(irq); | |
618 | } | |
619 | ||
172d2d1d | 620 | static void bfin_mac_status_unmask_irq(struct irq_data *d) |
aec59c91 | 621 | { |
172d2d1d TG |
622 | unsigned int irq = d->irq; |
623 | ||
f58c3276 | 624 | #ifdef BF537_FAMILY |
aec59c91 MH |
625 | switch (irq) { |
626 | case IRQ_MAC_PHYINT: | |
627 | bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE); | |
628 | break; | |
629 | default: | |
630 | break; | |
631 | } | |
632 | #else | |
633 | if (!mac_stat_int_mask) | |
634 | bfin_internal_unmask_irq(IRQ_MAC_ERROR); | |
635 | #endif | |
636 | mac_stat_int_mask |= 1L << (irq - IRQ_MAC_PHYINT); | |
637 | } | |
638 | ||
639 | #ifdef CONFIG_PM | |
172d2d1d | 640 | int bfin_mac_status_set_wake(struct irq_data *d, unsigned int state) |
aec59c91 | 641 | { |
f58c3276 | 642 | #ifdef BF537_FAMILY |
aec59c91 MH |
643 | return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state); |
644 | #else | |
645 | return bfin_internal_set_wake(IRQ_MAC_ERROR, state); | |
646 | #endif | |
647 | } | |
fc6bd7b8 MF |
648 | #else |
649 | # define bfin_mac_status_set_wake NULL | |
aec59c91 MH |
650 | #endif |
651 | ||
652 | static struct irq_chip bfin_mac_status_irqchip = { | |
653 | .name = "MACST", | |
172d2d1d TG |
654 | .irq_mask = bfin_mac_status_mask_irq, |
655 | .irq_unmask = bfin_mac_status_unmask_irq, | |
172d2d1d | 656 | .irq_set_wake = bfin_mac_status_set_wake, |
aec59c91 MH |
657 | }; |
658 | ||
f58c3276 MF |
659 | void bfin_demux_mac_status_irq(unsigned int int_err_irq, |
660 | struct irq_desc *inta_desc) | |
aec59c91 MH |
661 | { |
662 | int i, irq = 0; | |
663 | u32 status = bfin_read_EMAC_SYSTAT(); | |
664 | ||
bedeea6e | 665 | for (i = 0; i <= (IRQ_MAC_STMDONE - IRQ_MAC_PHYINT); i++) |
aec59c91 MH |
666 | if (status & (1L << i)) { |
667 | irq = IRQ_MAC_PHYINT + i; | |
668 | break; | |
669 | } | |
670 | ||
671 | if (irq) { | |
672 | if (mac_stat_int_mask & (1L << (irq - IRQ_MAC_PHYINT))) { | |
673 | bfin_handle_irq(irq); | |
674 | } else { | |
675 | bfin_mac_status_ack_irq(irq); | |
676 | pr_debug("IRQ %d:" | |
4f6b600f SM |
677 | " MASKED MAC ERROR INTERRUPT ASSERTED\n", |
678 | irq); | |
aec59c91 MH |
679 | } |
680 | } else | |
681 | printk(KERN_ERR | |
4f6b600f SM |
682 | "%s : %s : LINE %d :\nIRQ ?: MAC ERROR" |
683 | " INTERRUPT ASSERTED BUT NO SOURCE FOUND" | |
684 | "(EMAC_SYSTAT=0x%X)\n", | |
685 | __func__, __FILE__, __LINE__, status); | |
aec59c91 MH |
686 | } |
687 | #endif | |
688 | ||
bfd15117 GY |
689 | static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle) |
690 | { | |
6a01f230 | 691 | #ifdef CONFIG_IPIPE |
5b5da4c4 | 692 | handle = handle_level_irq; |
6a01f230 | 693 | #endif |
43f2f115 | 694 | __irq_set_handler_locked(irq, handle); |
bfd15117 GY |
695 | } |
696 | ||
54e4ff4d | 697 | #ifdef CONFIG_GPIO_ADI |
6fce6a8d | 698 | |
54e4ff4d | 699 | static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS); |
8d022374 | 700 | |
e9502850 | 701 | static void bfin_gpio_ack_irq(struct irq_data *d) |
1394f032 | 702 | { |
8d022374 MH |
703 | /* AFAIK ack_irq in case mask_ack is provided |
704 | * get's only called for edge sense irqs | |
705 | */ | |
e9502850 | 706 | set_gpio_data(irq_to_gpio(d->irq), 0); |
1394f032 BW |
707 | } |
708 | ||
e9502850 | 709 | static void bfin_gpio_mask_ack_irq(struct irq_data *d) |
1394f032 | 710 | { |
e9502850 | 711 | unsigned int irq = d->irq; |
8d022374 | 712 | u32 gpionr = irq_to_gpio(irq); |
1394f032 | 713 | |
1907d8be | 714 | if (!irqd_is_level_type(d)) |
1394f032 | 715 | set_gpio_data(gpionr, 0); |
1394f032 BW |
716 | |
717 | set_gpio_maska(gpionr, 0); | |
1394f032 BW |
718 | } |
719 | ||
e9502850 | 720 | static void bfin_gpio_mask_irq(struct irq_data *d) |
1394f032 | 721 | { |
e9502850 | 722 | set_gpio_maska(irq_to_gpio(d->irq), 0); |
1394f032 BW |
723 | } |
724 | ||
e9502850 | 725 | static void bfin_gpio_unmask_irq(struct irq_data *d) |
1394f032 | 726 | { |
e9502850 | 727 | set_gpio_maska(irq_to_gpio(d->irq), 1); |
1394f032 BW |
728 | } |
729 | ||
e9502850 | 730 | static unsigned int bfin_gpio_irq_startup(struct irq_data *d) |
1394f032 | 731 | { |
e9502850 | 732 | u32 gpionr = irq_to_gpio(d->irq); |
1394f032 | 733 | |
8d022374 | 734 | if (__test_and_set_bit(gpionr, gpio_enabled)) |
affee2b2 | 735 | bfin_gpio_irq_prepare(gpionr); |
1394f032 | 736 | |
e9502850 | 737 | bfin_gpio_unmask_irq(d); |
1394f032 | 738 | |
affee2b2 | 739 | return 0; |
1394f032 BW |
740 | } |
741 | ||
e9502850 | 742 | static void bfin_gpio_irq_shutdown(struct irq_data *d) |
1394f032 | 743 | { |
e9502850 | 744 | u32 gpionr = irq_to_gpio(d->irq); |
30af6d49 | 745 | |
e9502850 | 746 | bfin_gpio_mask_irq(d); |
30af6d49 | 747 | __clear_bit(gpionr, gpio_enabled); |
9570ff4a | 748 | bfin_gpio_irq_free(gpionr); |
1394f032 BW |
749 | } |
750 | ||
e9502850 | 751 | static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type) |
1394f032 | 752 | { |
e9502850 | 753 | unsigned int irq = d->irq; |
8eb3e3bf GY |
754 | int ret; |
755 | char buf[16]; | |
8d022374 | 756 | u32 gpionr = irq_to_gpio(irq); |
1394f032 BW |
757 | |
758 | if (type == IRQ_TYPE_PROBE) { | |
759 | /* only probe unenabled GPIO interrupt lines */ | |
c3695341 | 760 | if (test_bit(gpionr, gpio_enabled)) |
1394f032 BW |
761 | return 0; |
762 | type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | |
763 | } | |
764 | ||
765 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | | |
34e0fc89 | 766 | IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { |
8d022374 | 767 | |
9570ff4a GY |
768 | snprintf(buf, 16, "gpio-irq%d", irq); |
769 | ret = bfin_gpio_irq_request(gpionr, buf); | |
770 | if (ret) | |
771 | return ret; | |
772 | ||
8d022374 | 773 | if (__test_and_set_bit(gpionr, gpio_enabled)) |
affee2b2 | 774 | bfin_gpio_irq_prepare(gpionr); |
1394f032 | 775 | |
1394f032 | 776 | } else { |
8d022374 | 777 | __clear_bit(gpionr, gpio_enabled); |
1394f032 BW |
778 | return 0; |
779 | } | |
780 | ||
f1bceb47 | 781 | set_gpio_inen(gpionr, 0); |
1394f032 | 782 | set_gpio_dir(gpionr, 0); |
1394f032 BW |
783 | |
784 | if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | |
785 | == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | |
786 | set_gpio_both(gpionr, 1); | |
787 | else | |
788 | set_gpio_both(gpionr, 0); | |
789 | ||
790 | if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) | |
791 | set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */ | |
792 | else | |
793 | set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */ | |
794 | ||
f1bceb47 MH |
795 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { |
796 | set_gpio_edge(gpionr, 1); | |
797 | set_gpio_inen(gpionr, 1); | |
f1bceb47 MH |
798 | set_gpio_data(gpionr, 0); |
799 | ||
800 | } else { | |
801 | set_gpio_edge(gpionr, 0); | |
f1bceb47 MH |
802 | set_gpio_inen(gpionr, 1); |
803 | } | |
804 | ||
1394f032 | 805 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) |
bfd15117 | 806 | bfin_set_irq_handler(irq, handle_edge_irq); |
1394f032 | 807 | else |
bfd15117 | 808 | bfin_set_irq_handler(irq, handle_level_irq); |
1394f032 BW |
809 | |
810 | return 0; | |
811 | } | |
812 | ||
e2a8092c MF |
813 | static void bfin_demux_gpio_block(unsigned int irq) |
814 | { | |
815 | unsigned int gpio, mask; | |
816 | ||
817 | gpio = irq_to_gpio(irq); | |
818 | mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio); | |
819 | ||
820 | while (mask) { | |
821 | if (mask & 1) | |
822 | bfin_handle_irq(irq); | |
823 | irq++; | |
824 | mask >>= 1; | |
825 | } | |
826 | } | |
827 | ||
8c054103 | 828 | void bfin_demux_gpio_irq(unsigned int inta_irq, |
4f6b600f | 829 | struct irq_desc *desc) |
1394f032 | 830 | { |
e2a8092c | 831 | unsigned int irq; |
2c4f829b MH |
832 | |
833 | switch (inta_irq) { | |
e2a8092c | 834 | #if defined(BF537_FAMILY) |
8c054103 | 835 | case IRQ_PF_INTA_PG_INTA: |
e2a8092c MF |
836 | bfin_demux_gpio_block(IRQ_PF0); |
837 | irq = IRQ_PG0; | |
2c4f829b | 838 | break; |
8c054103 | 839 | case IRQ_PH_INTA_MAC_RX: |
2c4f829b MH |
840 | irq = IRQ_PH0; |
841 | break; | |
e2a8092c MF |
842 | #elif defined(BF533_FAMILY) |
843 | case IRQ_PROG_INTA: | |
844 | irq = IRQ_PF0; | |
845 | break; | |
fc6bd7b8 | 846 | #elif defined(BF538_FAMILY) |
dc26aec2 MH |
847 | case IRQ_PORTF_INTA: |
848 | irq = IRQ_PF0; | |
849 | break; | |
2f6f4bcd | 850 | #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) |
2c4f829b MH |
851 | case IRQ_PORTF_INTA: |
852 | irq = IRQ_PF0; | |
853 | break; | |
854 | case IRQ_PORTG_INTA: | |
855 | irq = IRQ_PG0; | |
856 | break; | |
857 | case IRQ_PORTH_INTA: | |
858 | irq = IRQ_PH0; | |
859 | break; | |
860 | #elif defined(CONFIG_BF561) | |
861 | case IRQ_PROG0_INTA: | |
862 | irq = IRQ_PF0; | |
863 | break; | |
864 | case IRQ_PROG1_INTA: | |
865 | irq = IRQ_PF16; | |
866 | break; | |
867 | case IRQ_PROG2_INTA: | |
868 | irq = IRQ_PF32; | |
869 | break; | |
870 | #endif | |
871 | default: | |
872 | BUG(); | |
873 | return; | |
874 | } | |
875 | ||
e2a8092c | 876 | bfin_demux_gpio_block(irq); |
1394f032 BW |
877 | } |
878 | ||
cfefe3c6 | 879 | #ifdef CONFIG_PM |
d49cdf84 | 880 | |
dd8cb37b | 881 | static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state) |
cfefe3c6 | 882 | { |
54e4ff4d SZ |
883 | return bfin_gpio_pm_wakeup_ctrl(irq_to_gpio(d->irq), state); |
884 | } | |
cfefe3c6 | 885 | |
54e4ff4d | 886 | #else |
cfefe3c6 | 887 | |
54e4ff4d | 888 | # define bfin_gpio_set_wake NULL |
d49cdf84 | 889 | |
54e4ff4d | 890 | #endif |
d49cdf84 | 891 | |
54e4ff4d SZ |
892 | static struct irq_chip bfin_gpio_irqchip = { |
893 | .name = "GPIO", | |
894 | .irq_ack = bfin_gpio_ack_irq, | |
895 | .irq_mask = bfin_gpio_mask_irq, | |
896 | .irq_mask_ack = bfin_gpio_mask_ack_irq, | |
897 | .irq_unmask = bfin_gpio_unmask_irq, | |
898 | .irq_disable = bfin_gpio_mask_irq, | |
899 | .irq_enable = bfin_gpio_unmask_irq, | |
900 | .irq_set_type = bfin_gpio_irq_type, | |
901 | .irq_startup = bfin_gpio_irq_startup, | |
902 | .irq_shutdown = bfin_gpio_irq_shutdown, | |
903 | .irq_set_wake = bfin_gpio_set_wake, | |
904 | }; | |
d49cdf84 | 905 | |
54e4ff4d | 906 | #endif |
d49cdf84 | 907 | |
54e4ff4d | 908 | #ifdef CONFIG_PM |
d49cdf84 | 909 | |
11b27cb5 | 910 | #ifdef SEC_GCTL |
54e4ff4d SZ |
911 | static u32 save_pint_sec_ctl[NR_PINT_SYS_IRQS]; |
912 | ||
d49cdf84 SM |
913 | static int sec_suspend(void) |
914 | { | |
915 | u32 bank; | |
916 | ||
917 | for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) | |
86794b43 | 918 | save_pint_sec_ctl[bank] = bfin_read_SEC_SCTL(bank + BFIN_SYSIRQ(IRQ_PINT0)); |
d49cdf84 SM |
919 | return 0; |
920 | } | |
921 | ||
922 | static void sec_resume(void) | |
923 | { | |
924 | u32 bank; | |
925 | ||
926 | bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_RESET); | |
927 | udelay(100); | |
928 | bfin_write_SEC_GCTL(SEC_GCTL_EN); | |
929 | bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_EN | SEC_CCTL_NMI_EN); | |
930 | ||
931 | for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) | |
86794b43 | 932 | bfin_write_SEC_SCTL(bank + BFIN_SYSIRQ(IRQ_PINT0), save_pint_sec_ctl[bank]); |
d49cdf84 SM |
933 | } |
934 | ||
935 | static struct syscore_ops sec_pm_syscore_ops = { | |
936 | .suspend = sec_suspend, | |
937 | .resume = sec_resume, | |
938 | }; | |
4f6b600f | 939 | #endif |
34e0fc89 | 940 | |
a055b2b4 | 941 | #endif |
1394f032 | 942 | |
13dff62d | 943 | void init_exception_vectors(void) |
8be80ed3 | 944 | { |
f0b5d12f MF |
945 | /* cannot program in software: |
946 | * evt0 - emulation (jtag) | |
947 | * evt1 - reset | |
948 | */ | |
949 | bfin_write_EVT2(evt_nmi); | |
8be80ed3 BS |
950 | bfin_write_EVT3(trap); |
951 | bfin_write_EVT5(evt_ivhw); | |
952 | bfin_write_EVT6(evt_timer); | |
953 | bfin_write_EVT7(evt_evt7); | |
954 | bfin_write_EVT8(evt_evt8); | |
955 | bfin_write_EVT9(evt_evt9); | |
956 | bfin_write_EVT10(evt_evt10); | |
957 | bfin_write_EVT11(evt_evt11); | |
958 | bfin_write_EVT12(evt_evt12); | |
959 | bfin_write_EVT13(evt_evt13); | |
9703a73c | 960 | bfin_write_EVT14(evt_evt14); |
8be80ed3 BS |
961 | bfin_write_EVT15(evt_system_call); |
962 | CSYNC(); | |
963 | } | |
964 | ||
11b27cb5 | 965 | #ifndef SEC_GCTL |
1394f032 BW |
966 | /* |
967 | * This function should be called during kernel startup to initialize | |
968 | * the BFin IRQ handling routines. | |
969 | */ | |
8d022374 | 970 | |
1394f032 BW |
971 | int __init init_arch_irq(void) |
972 | { | |
973 | int irq; | |
974 | unsigned long ilat = 0; | |
fc6bd7b8 | 975 | |
1394f032 | 976 | /* Disable all the peripheral intrs - page 4-29 HW Ref manual */ |
fc6bd7b8 | 977 | #ifdef SIC_IMASK0 |
24a07a12 RH |
978 | bfin_write_SIC_IMASK0(SIC_UNMASK_ALL); |
979 | bfin_write_SIC_IMASK1(SIC_UNMASK_ALL); | |
fc6bd7b8 | 980 | # ifdef SIC_IMASK2 |
59003145 | 981 | bfin_write_SIC_IMASK2(SIC_UNMASK_ALL); |
a055b2b4 | 982 | # endif |
4f6b600f | 983 | # if defined(CONFIG_SMP) || defined(CONFIG_ICC) |
6b3087c6 GY |
984 | bfin_write_SICB_IMASK0(SIC_UNMASK_ALL); |
985 | bfin_write_SICB_IMASK1(SIC_UNMASK_ALL); | |
986 | # endif | |
24a07a12 | 987 | #else |
1394f032 | 988 | bfin_write_SIC_IMASK(SIC_UNMASK_ALL); |
24a07a12 | 989 | #endif |
1394f032 BW |
990 | |
991 | local_irq_disable(); | |
992 | ||
34e0fc89 | 993 | for (irq = 0; irq <= SYS_IRQS; irq++) { |
1394f032 | 994 | if (irq <= IRQ_CORETMR) |
43f2f115 | 995 | irq_set_chip(irq, &bfin_core_irqchip); |
1394f032 | 996 | else |
43f2f115 | 997 | irq_set_chip(irq, &bfin_internal_irqchip); |
1394f032 | 998 | |
464abc5d | 999 | switch (irq) { |
54e4ff4d SZ |
1000 | #if !BFIN_GPIO_PINT |
1001 | #if defined(BF537_FAMILY) | |
01f8e34c MF |
1002 | case IRQ_PH_INTA_MAC_RX: |
1003 | case IRQ_PF_INTA_PG_INTA: | |
1004 | #elif defined(BF533_FAMILY) | |
1005 | case IRQ_PROG_INTA: | |
2f6f4bcd | 1006 | #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) |
464abc5d MH |
1007 | case IRQ_PORTF_INTA: |
1008 | case IRQ_PORTG_INTA: | |
1009 | case IRQ_PORTH_INTA: | |
2c4f829b | 1010 | #elif defined(CONFIG_BF561) |
464abc5d MH |
1011 | case IRQ_PROG0_INTA: |
1012 | case IRQ_PROG1_INTA: | |
1013 | case IRQ_PROG2_INTA: | |
fc6bd7b8 | 1014 | #elif defined(BF538_FAMILY) |
dc26aec2 | 1015 | case IRQ_PORTF_INTA: |
1394f032 | 1016 | #endif |
43f2f115 | 1017 | irq_set_chained_handler(irq, bfin_demux_gpio_irq); |
464abc5d | 1018 | break; |
54e4ff4d | 1019 | #endif |
aec59c91 MH |
1020 | #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) |
1021 | case IRQ_MAC_ERROR: | |
43f2f115 TG |
1022 | irq_set_chained_handler(irq, |
1023 | bfin_demux_mac_status_irq); | |
aec59c91 MH |
1024 | break; |
1025 | #endif | |
4f6b600f | 1026 | #if defined(CONFIG_SMP) || defined(CONFIG_ICC) |
6b3087c6 GY |
1027 | case IRQ_SUPPLE_0: |
1028 | case IRQ_SUPPLE_1: | |
43f2f115 | 1029 | irq_set_handler(irq, handle_percpu_irq); |
6b3087c6 GY |
1030 | break; |
1031 | #endif | |
17941314 | 1032 | |
cb191718 YL |
1033 | #ifdef CONFIG_TICKSOURCE_CORETMR |
1034 | case IRQ_CORETMR: | |
1035 | # ifdef CONFIG_SMP | |
43f2f115 | 1036 | irq_set_handler(irq, handle_percpu_irq); |
cb191718 | 1037 | # else |
43f2f115 | 1038 | irq_set_handler(irq, handle_simple_irq); |
cb191718 | 1039 | # endif |
fc6bd7b8 | 1040 | break; |
17941314 | 1041 | #endif |
cb191718 YL |
1042 | |
1043 | #ifdef CONFIG_TICKSOURCE_GPTMR0 | |
1044 | case IRQ_TIMER0: | |
43f2f115 | 1045 | irq_set_handler(irq, handle_simple_irq); |
a40494a6 | 1046 | break; |
cb191718 YL |
1047 | #endif |
1048 | ||
a40494a6 | 1049 | default: |
fc6bd7b8 | 1050 | #ifdef CONFIG_IPIPE |
43f2f115 | 1051 | irq_set_handler(irq, handle_level_irq); |
fc6bd7b8 | 1052 | #else |
43f2f115 | 1053 | irq_set_handler(irq, handle_simple_irq); |
fc6bd7b8 | 1054 | #endif |
464abc5d MH |
1055 | break; |
1056 | } | |
1394f032 | 1057 | } |
464abc5d | 1058 | |
f58c3276 | 1059 | init_mach_irq(); |
1394f032 | 1060 | |
11b27cb5 | 1061 | #if (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)) |
aec59c91 | 1062 | for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++) |
43f2f115 | 1063 | irq_set_chip_and_handler(irq, &bfin_mac_status_irqchip, |
aec59c91 MH |
1064 | handle_level_irq); |
1065 | #endif | |
464abc5d | 1066 | /* if configured as edge, then will be changed to do_edge_IRQ */ |
54e4ff4d | 1067 | #ifdef CONFIG_GPIO_ADI |
aec59c91 MH |
1068 | for (irq = GPIO_IRQ_BASE; |
1069 | irq < (GPIO_IRQ_BASE + MAX_BLACKFIN_GPIOS); irq++) | |
43f2f115 | 1070 | irq_set_chip_and_handler(irq, &bfin_gpio_irqchip, |
464abc5d | 1071 | handle_level_irq); |
54e4ff4d | 1072 | #endif |
1394f032 BW |
1073 | bfin_write_IMASK(0); |
1074 | CSYNC(); | |
1075 | ilat = bfin_read_ILAT(); | |
1076 | CSYNC(); | |
1077 | bfin_write_ILAT(ilat); | |
1078 | CSYNC(); | |
1079 | ||
34e0fc89 | 1080 | printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n"); |
40059784 | 1081 | /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx, |
1394f032 BW |
1082 | * local_irq_enable() |
1083 | */ | |
1084 | program_IAR(); | |
1085 | /* Therefore it's better to setup IARs before interrupts enabled */ | |
1086 | search_IAR(); | |
1087 | ||
1088 | /* Enable interrupts IVG7-15 */ | |
40059784 | 1089 | bfin_irq_flags |= IMASK_IVG15 | |
4f6b600f SM |
1090 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | |
1091 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; | |
1092 | ||
1394f032 | 1093 | |
349ebbcc MH |
1094 | /* This implicitly covers ANOMALY_05000171 |
1095 | * Boot-ROM code modifies SICA_IWRx wakeup registers | |
1096 | */ | |
be1d8543 | 1097 | #ifdef SIC_IWR0 |
56f5f590 | 1098 | bfin_write_SIC_IWR0(IWR_DISABLE_ALL); |
be1d8543 | 1099 | # ifdef SIC_IWR1 |
2f6f4bcd | 1100 | /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which |
55546ac4 MH |
1101 | * will screw up the bootrom as it relies on MDMA0/1 waking it |
1102 | * up from IDLE instructions. See this report for more info: | |
1103 | * http://blackfin.uclinux.org/gf/tracker/4323 | |
1104 | */ | |
b7e11293 MF |
1105 | if (ANOMALY_05000435) |
1106 | bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11)); | |
1107 | else | |
1108 | bfin_write_SIC_IWR1(IWR_DISABLE_ALL); | |
be1d8543 MF |
1109 | # endif |
1110 | # ifdef SIC_IWR2 | |
56f5f590 | 1111 | bfin_write_SIC_IWR2(IWR_DISABLE_ALL); |
fe9ec9b9 MH |
1112 | # endif |
1113 | #else | |
56f5f590 | 1114 | bfin_write_SIC_IWR(IWR_DISABLE_ALL); |
4f6b600f | 1115 | #endif |
1394f032 BW |
1116 | return 0; |
1117 | } | |
1118 | ||
1119 | #ifdef CONFIG_DO_IRQ_L1 | |
a055b2b4 | 1120 | __attribute__((l1_text)) |
1394f032 | 1121 | #endif |
6b108049 | 1122 | static int vec_to_irq(int vec) |
1394f032 | 1123 | { |
6b108049 MF |
1124 | struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst; |
1125 | struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop; | |
1126 | unsigned long sic_status[3]; | |
6b108049 MF |
1127 | if (likely(vec == EVT_IVTMR_P)) |
1128 | return IRQ_CORETMR; | |
6b108049 MF |
1129 | #ifdef SIC_ISR |
1130 | sic_status[0] = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR(); | |
1131 | #else | |
1132 | if (smp_processor_id()) { | |
780172bf | 1133 | # ifdef SICB_ISR0 |
6b108049 MF |
1134 | /* This will be optimized out in UP mode. */ |
1135 | sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0(); | |
1136 | sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1(); | |
780172bf | 1137 | # endif |
6b108049 MF |
1138 | } else { |
1139 | sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); | |
1140 | sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); | |
1141 | } | |
1142 | #endif | |
1143 | #ifdef SIC_ISR2 | |
1144 | sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); | |
1145 | #endif | |
1394f032 | 1146 | |
6b108049 MF |
1147 | for (;; ivg++) { |
1148 | if (ivg >= ivg_stop) | |
1149 | return -1; | |
1150 | #ifdef SIC_ISR | |
1151 | if (sic_status[0] & ivg->isrflag) | |
1152 | #else | |
1153 | if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag) | |
24a07a12 | 1154 | #endif |
6b108049 | 1155 | return ivg->irqno; |
1394f032 | 1156 | } |
11b27cb5 SZ |
1157 | } |
1158 | ||
1159 | #else /* SEC_GCTL */ | |
1160 | ||
1161 | /* | |
1162 | * This function should be called during kernel startup to initialize | |
1163 | * the BFin IRQ handling routines. | |
1164 | */ | |
1165 | ||
1166 | int __init init_arch_irq(void) | |
1167 | { | |
1168 | int irq; | |
1169 | unsigned long ilat = 0; | |
1170 | ||
1171 | bfin_write_SEC_GCTL(SEC_GCTL_RESET); | |
1172 | ||
1173 | local_irq_disable(); | |
1174 | ||
11b27cb5 SZ |
1175 | for (irq = 0; irq <= SYS_IRQS; irq++) { |
1176 | if (irq <= IRQ_CORETMR) { | |
86794b43 SZ |
1177 | irq_set_chip_and_handler(irq, &bfin_core_irqchip, |
1178 | handle_simple_irq); | |
1179 | #if defined(CONFIG_TICKSOURCE_CORETMR) && defined(CONFIG_SMP) | |
11b27cb5 | 1180 | if (irq == IRQ_CORETMR) |
11b27cb5 | 1181 | irq_set_handler(irq, handle_percpu_irq); |
11b27cb5 | 1182 | #endif |
11b27cb5 | 1183 | } else if (irq >= BFIN_IRQ(34) && irq <= BFIN_IRQ(37)) { |
11b27cb5 | 1184 | irq_set_chip_and_handler(irq, &bfin_sec_irqchip, |
86794b43 SZ |
1185 | handle_percpu_irq); |
1186 | } else { | |
1187 | irq_set_chip(irq, &bfin_sec_irqchip); | |
1b601239 | 1188 | irq_set_handler(irq, handle_fasteoi_irq); |
11b27cb5 SZ |
1189 | __irq_set_preflow_handler(irq, bfin_sec_preflow_handler); |
1190 | } | |
1191 | } | |
11b27cb5 SZ |
1192 | |
1193 | bfin_write_IMASK(0); | |
1194 | CSYNC(); | |
1195 | ilat = bfin_read_ILAT(); | |
1196 | CSYNC(); | |
1197 | bfin_write_ILAT(ilat); | |
1198 | CSYNC(); | |
1199 | ||
1200 | printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n"); | |
1201 | ||
e0a59310 SZ |
1202 | bfin_sec_set_priority(CONFIG_SEC_IRQ_PRIORITY_LEVELS, sec_int_priority); |
1203 | ||
11b27cb5 SZ |
1204 | /* Enable interrupts IVG7-15 */ |
1205 | bfin_irq_flags |= IMASK_IVG15 | | |
1206 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | | |
1207 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; | |
1208 | ||
1209 | ||
1210 | bfin_write_SEC_FCTL(SEC_FCTL_EN | SEC_FCTL_SYSRST_EN | SEC_FCTL_FLTIN_EN); | |
86794b43 SZ |
1211 | bfin_sec_enable_sci(BFIN_SYSIRQ(IRQ_WATCH0)); |
1212 | bfin_sec_enable_ssi(BFIN_SYSIRQ(IRQ_WATCH0)); | |
11b27cb5 SZ |
1213 | bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_RESET); |
1214 | udelay(100); | |
1215 | bfin_write_SEC_GCTL(SEC_GCTL_EN); | |
1216 | bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_EN | SEC_CCTL_NMI_EN); | |
1217 | bfin_write_SEC_SCI(1, SEC_CCTL, SEC_CCTL_EN | SEC_CCTL_NMI_EN); | |
1218 | ||
1219 | init_software_driven_irq(); | |
36c47239 SM |
1220 | |
1221 | #ifdef CONFIG_PM | |
11b27cb5 | 1222 | register_syscore_ops(&sec_pm_syscore_ops); |
36c47239 | 1223 | #endif |
11b27cb5 | 1224 | |
1b601239 SZ |
1225 | bfin_fault_irq.handler = bfin_fault_routine; |
1226 | #ifdef CONFIG_L1_PARITY_CHECK | |
1227 | setup_irq(IRQ_C0_NMI_L1_PARITY_ERR, &bfin_fault_irq); | |
1228 | #endif | |
1229 | setup_irq(IRQ_C0_DBL_FAULT, &bfin_fault_irq); | |
1230 | setup_irq(IRQ_SEC_ERR, &bfin_fault_irq); | |
1231 | ||
11b27cb5 SZ |
1232 | return 0; |
1233 | } | |
1234 | ||
1235 | #ifdef CONFIG_DO_IRQ_L1 | |
1236 | __attribute__((l1_text)) | |
1237 | #endif | |
1238 | static int vec_to_irq(int vec) | |
1239 | { | |
1240 | if (likely(vec == EVT_IVTMR_P)) | |
1241 | return IRQ_CORETMR; | |
1242 | ||
4f6b600f | 1243 | return BFIN_IRQ(bfin_read_SEC_SCI(0, SEC_CSID)); |
6b108049 | 1244 | } |
11b27cb5 | 1245 | #endif /* SEC_GCTL */ |
6b108049 MF |
1246 | |
1247 | #ifdef CONFIG_DO_IRQ_L1 | |
1248 | __attribute__((l1_text)) | |
1249 | #endif | |
1250 | void do_irq(int vec, struct pt_regs *fp) | |
1251 | { | |
1252 | int irq = vec_to_irq(vec); | |
1253 | if (irq == -1) | |
1254 | return; | |
1255 | asm_do_IRQ(irq, fp); | |
1394f032 | 1256 | } |
6a01f230 YL |
1257 | |
1258 | #ifdef CONFIG_IPIPE | |
1259 | ||
1260 | int __ipipe_get_irq_priority(unsigned irq) | |
1261 | { | |
1262 | int ient, prio; | |
1263 | ||
1264 | if (irq <= IRQ_CORETMR) | |
1265 | return irq; | |
1266 | ||
11b27cb5 SZ |
1267 | #ifdef SEC_GCTL |
1268 | if (irq >= BFIN_IRQ(0)) | |
1269 | return IVG11; | |
1270 | #else | |
6a01f230 YL |
1271 | for (ient = 0; ient < NR_PERI_INTS; ient++) { |
1272 | struct ivgx *ivg = ivg_table + ient; | |
1273 | if (ivg->irqno == irq) { | |
1274 | for (prio = 0; prio <= IVG13-IVG7; prio++) { | |
1275 | if (ivg7_13[prio].ifirst <= ivg && | |
1276 | ivg7_13[prio].istop > ivg) | |
1277 | return IVG7 + prio; | |
1278 | } | |
1279 | } | |
1280 | } | |
11b27cb5 | 1281 | #endif |
6a01f230 YL |
1282 | |
1283 | return IVG15; | |
1284 | } | |
1285 | ||
6a01f230 YL |
1286 | /* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */ |
1287 | #ifdef CONFIG_DO_IRQ_L1 | |
1288 | __attribute__((l1_text)) | |
1289 | #endif | |
1290 | asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs) | |
1291 | { | |
9bd50df6 | 1292 | struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr(); |
a40494a6 | 1293 | struct ipipe_domain *this_domain = __ipipe_current_domain; |
5b5da4c4 | 1294 | int irq, s = 0; |
6a01f230 | 1295 | |
6b108049 MF |
1296 | irq = vec_to_irq(vec); |
1297 | if (irq == -1) | |
1298 | return 0; | |
6a01f230 YL |
1299 | |
1300 | if (irq == IRQ_SYSTMR) { | |
a40494a6 | 1301 | #if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0) |
6a01f230 | 1302 | bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */ |
9bd50df6 | 1303 | #endif |
6a01f230 | 1304 | /* This is basically what we need from the register frame. */ |
7e788ab1 CL |
1305 | __this_cpu_write(__ipipe_tick_regs.ipend, regs->ipend); |
1306 | __this_cpu_write(__ipipe_tick_regs.pc, regs->pc); | |
9bd50df6 | 1307 | if (this_domain != ipipe_root_domain) |
7e788ab1 | 1308 | __this_cpu_and(__ipipe_tick_regs.ipend, ~0x10); |
9bd50df6 | 1309 | else |
7e788ab1 | 1310 | __this_cpu_or(__ipipe_tick_regs.ipend, 0x10); |
6a01f230 YL |
1311 | } |
1312 | ||
5b5da4c4 PG |
1313 | /* |
1314 | * We don't want Linux interrupt handlers to run at the | |
1315 | * current core priority level (i.e. < EVT15), since this | |
1316 | * might delay other interrupts handled by a high priority | |
1317 | * domain. Here is what we do instead: | |
1318 | * | |
1319 | * - we raise the SYNCDEFER bit to prevent | |
1320 | * __ipipe_handle_irq() to sync the pipeline for the root | |
1321 | * stage for the incoming interrupt. Upon return, that IRQ is | |
1322 | * pending in the interrupt log. | |
1323 | * | |
1324 | * - we raise the TIF_IRQ_SYNC bit for the current thread, so | |
1325 | * that _schedule_and_signal_from_int will eventually sync the | |
1326 | * pipeline from EVT15. | |
1327 | */ | |
9bd50df6 PG |
1328 | if (this_domain == ipipe_root_domain) { |
1329 | s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status); | |
1330 | barrier(); | |
1331 | } | |
6a01f230 YL |
1332 | |
1333 | ipipe_trace_irq_entry(irq); | |
1334 | __ipipe_handle_irq(irq, regs); | |
9bd50df6 | 1335 | ipipe_trace_irq_exit(irq); |
6a01f230 | 1336 | |
5b5da4c4 PG |
1337 | if (user_mode(regs) && |
1338 | !ipipe_test_foreign_stack() && | |
1339 | (current->ipipe_flags & PF_EVTRET) != 0) { | |
1340 | /* | |
1341 | * Testing for user_regs() does NOT fully eliminate | |
1342 | * foreign stack contexts, because of the forged | |
1343 | * interrupt returns we do through | |
1344 | * __ipipe_call_irqtail. In that case, we might have | |
1345 | * preempted a foreign stack context in a high | |
1346 | * priority domain, with a single interrupt level now | |
1347 | * pending after the irqtail unwinding is done. In | |
1348 | * which case user_mode() is now true, and the event | |
1349 | * gets dispatched spuriously. | |
1350 | */ | |
1351 | current->ipipe_flags &= ~PF_EVTRET; | |
1352 | __ipipe_dispatch_event(IPIPE_EVENT_RETURN, regs); | |
1353 | } | |
1354 | ||
9bd50df6 PG |
1355 | if (this_domain == ipipe_root_domain) { |
1356 | set_thread_flag(TIF_IRQ_SYNC); | |
1357 | if (!s) { | |
1358 | __clear_bit(IPIPE_SYNCDEFER_FLAG, &p->status); | |
1359 | return !test_bit(IPIPE_STALL_FLAG, &p->status); | |
1360 | } | |
1361 | } | |
6a01f230 | 1362 | |
1fa9be72 | 1363 | return 0; |
6a01f230 YL |
1364 | } |
1365 | ||
1366 | #endif /* CONFIG_IPIPE */ |