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