]>
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> |
b17b0153 | 19 | #include <linux/sched/debug.h> |
4f6b600f | 20 | #include <linux/syscore_ops.h> |
288e6eaa | 21 | #include <linux/gpio.h> |
4f6b600f | 22 | #include <asm/delay.h> |
6a01f230 YL |
23 | #ifdef CONFIG_IPIPE |
24 | #include <linux/ipipe.h> | |
25 | #endif | |
1394f032 BW |
26 | #include <asm/traps.h> |
27 | #include <asm/blackfin.h> | |
1394f032 | 28 | #include <asm/irq_handler.h> |
761ec44a | 29 | #include <asm/dpmc.h> |
06051fde | 30 | #include <asm/traps.h> |
1394f032 | 31 | |
1394f032 BW |
32 | /* |
33 | * NOTES: | |
34 | * - we have separated the physical Hardware interrupt from the | |
35 | * levels that the LINUX kernel sees (see the description in irq.h) | |
36 | * - | |
37 | */ | |
38 | ||
6b3087c6 | 39 | #ifndef CONFIG_SMP |
a99bbccd MF |
40 | /* Initialize this to an actual value to force it into the .data |
41 | * section so that we know it is properly initialized at entry into | |
42 | * the kernel but before bss is initialized to zero (which is where | |
43 | * it would live otherwise). The 0x1f magic represents the IRQs we | |
44 | * cannot actually mask out in hardware. | |
45 | */ | |
40059784 MF |
46 | unsigned long bfin_irq_flags = 0x1f; |
47 | EXPORT_SYMBOL(bfin_irq_flags); | |
6b3087c6 | 48 | #endif |
1394f032 | 49 | |
cfefe3c6 MH |
50 | #ifdef CONFIG_PM |
51 | unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */ | |
4a88d0ce | 52 | unsigned vr_wakeup; |
cfefe3c6 MH |
53 | #endif |
54 | ||
11b27cb5 | 55 | #ifndef SEC_GCTL |
e9e334c3 | 56 | static struct ivgx { |
464abc5d | 57 | /* irq number for request_irq, available in mach-bf5xx/irq.h */ |
24a07a12 | 58 | unsigned int irqno; |
1394f032 | 59 | /* corresponding bit in the SIC_ISR register */ |
24a07a12 | 60 | unsigned int isrflag; |
1394f032 BW |
61 | } ivg_table[NR_PERI_INTS]; |
62 | ||
e9e334c3 | 63 | static struct ivg_slice { |
1394f032 BW |
64 | /* position of first irq in ivg_table for given ivg */ |
65 | struct ivgx *ifirst; | |
66 | struct ivgx *istop; | |
67 | } ivg7_13[IVG13 - IVG7 + 1]; | |
68 | ||
1394f032 BW |
69 | |
70 | /* | |
71 | * Search SIC_IAR and fill tables with the irqvalues | |
72 | * and their positions in the SIC_ISR register. | |
73 | */ | |
74 | static void __init search_IAR(void) | |
75 | { | |
76 | unsigned ivg, irq_pos = 0; | |
77 | for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) { | |
80fcdb95 | 78 | int irqN; |
1394f032 | 79 | |
34e0fc89 | 80 | ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos]; |
1394f032 | 81 | |
80fcdb95 MF |
82 | for (irqN = 0; irqN < NR_PERI_INTS; irqN += 4) { |
83 | int irqn; | |
4f6b600f SM |
84 | u32 iar = |
85 | bfin_read32((unsigned long *)SIC_IAR0 + | |
80fcdb95 MF |
86 | #if defined(CONFIG_BF51x) || defined(CONFIG_BF52x) || \ |
87 | defined(CONFIG_BF538) || defined(CONFIG_BF539) | |
88 | ((irqN % 32) >> 3) + ((irqN / 32) * ((SIC_IAR4 - SIC_IAR0) / 4)) | |
59003145 | 89 | #else |
80fcdb95 | 90 | (irqN >> 3) |
59003145 | 91 | #endif |
80fcdb95 | 92 | ); |
80fcdb95 MF |
93 | for (irqn = irqN; irqn < irqN + 4; ++irqn) { |
94 | int iar_shift = (irqn & 7) * 4; | |
95 | if (ivg == (0xf & (iar >> iar_shift))) { | |
96 | ivg_table[irq_pos].irqno = IVG7 + irqn; | |
97 | ivg_table[irq_pos].isrflag = 1 << (irqn % 32); | |
98 | ivg7_13[ivg].istop++; | |
99 | irq_pos++; | |
100 | } | |
1394f032 BW |
101 | } |
102 | } | |
103 | } | |
104 | } | |
4f6b600f | 105 | #endif |
1394f032 BW |
106 | |
107 | /* | |
464abc5d | 108 | * This is for core internal IRQs |
1394f032 | 109 | */ |
f58c3276 | 110 | void bfin_ack_noop(struct irq_data *d) |
1394f032 BW |
111 | { |
112 | /* Dummy function. */ | |
113 | } | |
114 | ||
4f19ea49 | 115 | static void bfin_core_mask_irq(struct irq_data *d) |
1394f032 | 116 | { |
4f19ea49 | 117 | bfin_irq_flags &= ~(1 << d->irq); |
3b139cdb DH |
118 | if (!hard_irqs_disabled()) |
119 | hard_local_irq_enable(); | |
1394f032 BW |
120 | } |
121 | ||
4f19ea49 | 122 | static void bfin_core_unmask_irq(struct irq_data *d) |
1394f032 | 123 | { |
4f19ea49 | 124 | bfin_irq_flags |= 1 << d->irq; |
1394f032 BW |
125 | /* |
126 | * If interrupts are enabled, IMASK must contain the same value | |
40059784 | 127 | * as bfin_irq_flags. Make sure that invariant holds. If interrupts |
1394f032 BW |
128 | * are currently disabled we need not do anything; one of the |
129 | * callers will take care of setting IMASK to the proper value | |
130 | * when reenabling interrupts. | |
40059784 | 131 | * local_irq_enable just does "STI bfin_irq_flags", so it's exactly |
1394f032 BW |
132 | * what we need. |
133 | */ | |
3b139cdb DH |
134 | if (!hard_irqs_disabled()) |
135 | hard_local_irq_enable(); | |
1394f032 BW |
136 | return; |
137 | } | |
138 | ||
86794b43 | 139 | #ifndef SEC_GCTL |
f58c3276 | 140 | void bfin_internal_mask_irq(unsigned int irq) |
1394f032 | 141 | { |
fc6bd7b8 | 142 | unsigned long flags = hard_local_irq_save(); |
fc6bd7b8 | 143 | #ifdef SIC_IMASK0 |
86794b43 SZ |
144 | unsigned mask_bank = BFIN_SYSIRQ(irq) / 32; |
145 | unsigned mask_bit = BFIN_SYSIRQ(irq) % 32; | |
c04d66bb | 146 | bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & |
4f6b600f SM |
147 | ~(1 << mask_bit)); |
148 | # if defined(CONFIG_SMP) || defined(CONFIG_ICC) | |
6b3087c6 | 149 | bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) & |
4f6b600f | 150 | ~(1 << mask_bit)); |
fc6bd7b8 MF |
151 | # endif |
152 | #else | |
153 | bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & | |
86794b43 | 154 | ~(1 << BFIN_SYSIRQ(irq))); |
4f6b600f | 155 | #endif /* end of SIC_IMASK0 */ |
3b139cdb | 156 | hard_local_irq_restore(flags); |
1394f032 BW |
157 | } |
158 | ||
ff43a67f TG |
159 | static void bfin_internal_mask_irq_chip(struct irq_data *d) |
160 | { | |
161 | bfin_internal_mask_irq(d->irq); | |
162 | } | |
163 | ||
0325f25a | 164 | #ifdef CONFIG_SMP |
4f6b600f | 165 | void bfin_internal_unmask_irq_affinity(unsigned int irq, |
0325f25a SZ |
166 | const struct cpumask *affinity) |
167 | #else | |
f58c3276 | 168 | void bfin_internal_unmask_irq(unsigned int irq) |
0325f25a | 169 | #endif |
1394f032 | 170 | { |
fc6bd7b8 | 171 | unsigned long flags = hard_local_irq_save(); |
9bd50df6 | 172 | |
fc6bd7b8 | 173 | #ifdef SIC_IMASK0 |
86794b43 SZ |
174 | unsigned mask_bank = BFIN_SYSIRQ(irq) / 32; |
175 | unsigned mask_bit = BFIN_SYSIRQ(irq) % 32; | |
fc6bd7b8 | 176 | # ifdef CONFIG_SMP |
0325f25a | 177 | if (cpumask_test_cpu(0, affinity)) |
fc6bd7b8 | 178 | # endif |
0325f25a | 179 | bfin_write_SIC_IMASK(mask_bank, |
4f6b600f SM |
180 | bfin_read_SIC_IMASK(mask_bank) | |
181 | (1 << mask_bit)); | |
fc6bd7b8 | 182 | # ifdef CONFIG_SMP |
0325f25a SZ |
183 | if (cpumask_test_cpu(1, affinity)) |
184 | bfin_write_SICB_IMASK(mask_bank, | |
4f6b600f SM |
185 | bfin_read_SICB_IMASK(mask_bank) | |
186 | (1 << mask_bit)); | |
fc6bd7b8 MF |
187 | # endif |
188 | #else | |
189 | bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | | |
86794b43 SZ |
190 | (1 << BFIN_SYSIRQ(irq))); |
191 | #endif | |
192 | hard_local_irq_restore(flags); | |
193 | } | |
194 | ||
195 | #ifdef CONFIG_SMP | |
196 | static void bfin_internal_unmask_irq_chip(struct irq_data *d) | |
197 | { | |
247bd4f1 JL |
198 | bfin_internal_unmask_irq_affinity(d->irq, |
199 | irq_data_get_affinity_mask(d)); | |
86794b43 SZ |
200 | } |
201 | ||
202 | static int bfin_internal_set_affinity(struct irq_data *d, | |
203 | const struct cpumask *mask, bool force) | |
204 | { | |
205 | bfin_internal_mask_irq(d->irq); | |
206 | bfin_internal_unmask_irq_affinity(d->irq, mask); | |
207 | ||
208 | return 0; | |
209 | } | |
210 | #else | |
211 | static void bfin_internal_unmask_irq_chip(struct irq_data *d) | |
212 | { | |
213 | bfin_internal_unmask_irq(d->irq); | |
214 | } | |
4f6b600f | 215 | #endif |
86794b43 SZ |
216 | |
217 | #if defined(CONFIG_PM) | |
218 | int bfin_internal_set_wake(unsigned int irq, unsigned int state) | |
219 | { | |
220 | u32 bank, bit, wakeup = 0; | |
221 | unsigned long flags; | |
222 | bank = BFIN_SYSIRQ(irq) / 32; | |
223 | bit = BFIN_SYSIRQ(irq) % 32; | |
224 | ||
225 | switch (irq) { | |
226 | #ifdef IRQ_RTC | |
227 | case IRQ_RTC: | |
228 | wakeup |= WAKE; | |
229 | break; | |
230 | #endif | |
231 | #ifdef IRQ_CAN0_RX | |
232 | case IRQ_CAN0_RX: | |
233 | wakeup |= CANWE; | |
234 | break; | |
6b3087c6 | 235 | #endif |
86794b43 SZ |
236 | #ifdef IRQ_CAN1_RX |
237 | case IRQ_CAN1_RX: | |
238 | wakeup |= CANWE; | |
239 | break; | |
240 | #endif | |
241 | #ifdef IRQ_USB_INT0 | |
242 | case IRQ_USB_INT0: | |
243 | wakeup |= USBWE; | |
244 | break; | |
245 | #endif | |
246 | #ifdef CONFIG_BF54x | |
247 | case IRQ_CNT: | |
248 | wakeup |= ROTWE; | |
249 | break; | |
250 | #endif | |
251 | default: | |
252 | break; | |
253 | } | |
254 | ||
255 | flags = hard_local_irq_save(); | |
256 | ||
257 | if (state) { | |
258 | bfin_sic_iwr[bank] |= (1 << bit); | |
259 | vr_wakeup |= wakeup; | |
260 | ||
261 | } else { | |
262 | bfin_sic_iwr[bank] &= ~(1 << bit); | |
263 | vr_wakeup &= ~wakeup; | |
264 | } | |
265 | ||
4f6b600f | 266 | hard_local_irq_restore(flags); |
86794b43 SZ |
267 | |
268 | return 0; | |
4f6b600f SM |
269 | } |
270 | ||
86794b43 SZ |
271 | static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state) |
272 | { | |
273 | return bfin_internal_set_wake(d->irq, state); | |
274 | } | |
275 | #else | |
276 | inline int bfin_internal_set_wake(unsigned int irq, unsigned int state) | |
277 | { | |
278 | return 0; | |
279 | } | |
280 | # define bfin_internal_set_wake_chip NULL | |
281 | #endif | |
282 | ||
283 | #else /* SEC_GCTL */ | |
4f6b600f SM |
284 | static void bfin_sec_preflow_handler(struct irq_data *d) |
285 | { | |
286 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 287 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
288 | |
289 | bfin_write_SEC_SCI(0, SEC_CSID, sid); | |
290 | ||
291 | hard_local_irq_restore(flags); | |
292 | } | |
293 | ||
294 | static void bfin_sec_mask_ack_irq(struct irq_data *d) | |
295 | { | |
296 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 297 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
298 | |
299 | bfin_write_SEC_SCI(0, SEC_CSID, sid); | |
300 | ||
301 | hard_local_irq_restore(flags); | |
302 | } | |
303 | ||
304 | static void bfin_sec_unmask_irq(struct irq_data *d) | |
305 | { | |
306 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 307 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
308 | |
309 | bfin_write32(SEC_END, sid); | |
310 | ||
311 | hard_local_irq_restore(flags); | |
312 | } | |
313 | ||
314 | static void bfin_sec_enable_ssi(unsigned int sid) | |
315 | { | |
316 | unsigned long flags = hard_local_irq_save(); | |
317 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
318 | ||
319 | reg_sctl |= SEC_SCTL_SRC_EN; | |
320 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
321 | ||
322 | hard_local_irq_restore(flags); | |
323 | } | |
324 | ||
325 | static void bfin_sec_disable_ssi(unsigned int sid) | |
326 | { | |
327 | unsigned long flags = hard_local_irq_save(); | |
328 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
329 | ||
330 | reg_sctl &= ((uint32_t)~SEC_SCTL_SRC_EN); | |
331 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
332 | ||
333 | hard_local_irq_restore(flags); | |
334 | } | |
335 | ||
336 | static void bfin_sec_set_ssi_coreid(unsigned int sid, unsigned int coreid) | |
337 | { | |
338 | unsigned long flags = hard_local_irq_save(); | |
339 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
340 | ||
341 | reg_sctl &= ((uint32_t)~SEC_SCTL_CTG); | |
342 | bfin_write_SEC_SCTL(sid, reg_sctl | ((coreid << 20) & SEC_SCTL_CTG)); | |
343 | ||
344 | hard_local_irq_restore(flags); | |
345 | } | |
346 | ||
347 | static void bfin_sec_enable_sci(unsigned int sid) | |
348 | { | |
349 | unsigned long flags = hard_local_irq_save(); | |
350 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
351 | ||
86794b43 | 352 | if (sid == BFIN_SYSIRQ(IRQ_WATCH0)) |
4f6b600f SM |
353 | reg_sctl |= SEC_SCTL_FAULT_EN; |
354 | else | |
355 | reg_sctl |= SEC_SCTL_INT_EN; | |
356 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
357 | ||
358 | hard_local_irq_restore(flags); | |
359 | } | |
360 | ||
361 | static void bfin_sec_disable_sci(unsigned int sid) | |
362 | { | |
363 | unsigned long flags = hard_local_irq_save(); | |
364 | uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); | |
365 | ||
366 | reg_sctl &= ((uint32_t)~SEC_SCTL_INT_EN); | |
367 | bfin_write_SEC_SCTL(sid, reg_sctl); | |
368 | ||
369 | hard_local_irq_restore(flags); | |
370 | } | |
371 | ||
372 | static void bfin_sec_enable(struct irq_data *d) | |
373 | { | |
374 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 375 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
376 | |
377 | bfin_sec_enable_sci(sid); | |
378 | bfin_sec_enable_ssi(sid); | |
fc6bd7b8 | 379 | |
3b139cdb | 380 | hard_local_irq_restore(flags); |
1394f032 BW |
381 | } |
382 | ||
4f6b600f SM |
383 | static void bfin_sec_disable(struct irq_data *d) |
384 | { | |
385 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 386 | unsigned int sid = BFIN_SYSIRQ(d->irq); |
4f6b600f SM |
387 | |
388 | bfin_sec_disable_sci(sid); | |
389 | bfin_sec_disable_ssi(sid); | |
390 | ||
391 | hard_local_irq_restore(flags); | |
392 | } | |
393 | ||
e0a59310 SZ |
394 | static void bfin_sec_set_priority(unsigned int sec_int_levels, u8 *sec_int_priority) |
395 | { | |
396 | unsigned long flags = hard_local_irq_save(); | |
397 | uint32_t reg_sctl; | |
398 | int i; | |
399 | ||
400 | bfin_write_SEC_SCI(0, SEC_CPLVL, sec_int_levels); | |
401 | ||
402 | for (i = 0; i < SYS_IRQS - BFIN_IRQ(0); i++) { | |
403 | reg_sctl = bfin_read_SEC_SCTL(i) & ~SEC_SCTL_PRIO; | |
404 | reg_sctl |= sec_int_priority[i] << SEC_SCTL_PRIO_OFFSET; | |
405 | bfin_write_SEC_SCTL(i, reg_sctl); | |
406 | } | |
407 | ||
408 | hard_local_irq_restore(flags); | |
409 | } | |
410 | ||
86794b43 | 411 | void bfin_sec_raise_irq(unsigned int irq) |
4f6b600f SM |
412 | { |
413 | unsigned long flags = hard_local_irq_save(); | |
86794b43 | 414 | unsigned int sid = BFIN_SYSIRQ(irq); |
4f6b600f SM |
415 | |
416 | bfin_write32(SEC_RAISE, sid); | |
417 | ||
418 | hard_local_irq_restore(flags); | |
419 | } | |
420 | ||
421 | static void init_software_driven_irq(void) | |
422 | { | |
423 | bfin_sec_set_ssi_coreid(34, 0); | |
424 | bfin_sec_set_ssi_coreid(35, 1); | |
86794b43 SZ |
425 | |
426 | bfin_sec_enable_sci(35); | |
427 | bfin_sec_enable_ssi(35); | |
4f6b600f SM |
428 | bfin_sec_set_ssi_coreid(36, 0); |
429 | bfin_sec_set_ssi_coreid(37, 1); | |
86794b43 SZ |
430 | bfin_sec_enable_sci(37); |
431 | bfin_sec_enable_ssi(37); | |
4f6b600f SM |
432 | } |
433 | ||
4f6b600f SM |
434 | void handle_sec_sfi_fault(uint32_t gstat) |
435 | { | |
436 | ||
437 | } | |
438 | ||
439 | void handle_sec_sci_fault(uint32_t gstat) | |
440 | { | |
441 | uint32_t core_id; | |
442 | uint32_t cstat; | |
443 | ||
444 | core_id = gstat & SEC_GSTAT_SCI; | |
445 | cstat = bfin_read_SEC_SCI(core_id, SEC_CSTAT); | |
446 | if (cstat & SEC_CSTAT_ERR) { | |
447 | switch (cstat & SEC_CSTAT_ERRC) { | |
448 | case SEC_CSTAT_ACKERR: | |
449 | printk(KERN_DEBUG "sec ack err\n"); | |
450 | break; | |
451 | default: | |
9b13494c | 452 | printk(KERN_DEBUG "sec sci unknown err\n"); |
4f6b600f SM |
453 | } |
454 | } | |
455 | ||
456 | } | |
457 | ||
458 | void handle_sec_ssi_fault(uint32_t gstat) | |
459 | { | |
460 | uint32_t sid; | |
461 | uint32_t sstat; | |
462 | ||
463 | sid = gstat & SEC_GSTAT_SID; | |
464 | sstat = bfin_read_SEC_SSTAT(sid); | |
465 | ||
466 | } | |
467 | ||
1b601239 | 468 | void handle_sec_fault(uint32_t sec_gstat) |
4f6b600f | 469 | { |
4f6b600f SM |
470 | if (sec_gstat & SEC_GSTAT_ERR) { |
471 | ||
472 | switch (sec_gstat & SEC_GSTAT_ERRC) { | |
473 | case 0: | |
474 | handle_sec_sfi_fault(sec_gstat); | |
475 | break; | |
476 | case SEC_GSTAT_SCIERR: | |
477 | handle_sec_sci_fault(sec_gstat); | |
478 | break; | |
479 | case SEC_GSTAT_SSIERR: | |
480 | handle_sec_ssi_fault(sec_gstat); | |
481 | break; | |
482 | } | |
483 | ||
484 | ||
485 | } | |
4f6b600f SM |
486 | } |
487 | ||
1b601239 SZ |
488 | static struct irqaction bfin_fault_irq = { |
489 | .name = "Blackfin fault", | |
490 | }; | |
491 | ||
492 | static irqreturn_t bfin_fault_routine(int irq, void *data) | |
06051fde SZ |
493 | { |
494 | struct pt_regs *fp = get_irq_regs(); | |
495 | ||
06051fde SZ |
496 | switch (irq) { |
497 | case IRQ_C0_DBL_FAULT: | |
498 | double_fault_c(fp); | |
499 | break; | |
500 | case IRQ_C0_HW_ERR: | |
501 | dump_bfin_process(fp); | |
502 | dump_bfin_mem(fp); | |
503 | show_regs(fp); | |
504 | printk(KERN_NOTICE "Kernel Stack\n"); | |
505 | show_stack(current, NULL); | |
506 | print_modules(); | |
86794b43 | 507 | panic("Core 0 hardware error"); |
06051fde SZ |
508 | break; |
509 | case IRQ_C0_NMI_L1_PARITY_ERR: | |
86794b43 | 510 | panic("Core 0 NMI L1 parity error"); |
06051fde | 511 | break; |
1b601239 SZ |
512 | case IRQ_SEC_ERR: |
513 | pr_err("SEC error\n"); | |
514 | handle_sec_fault(bfin_read32(SEC_GSTAT)); | |
515 | break; | |
06051fde | 516 | default: |
1b601239 | 517 | panic("Unknown fault %d", irq); |
06051fde SZ |
518 | } |
519 | ||
1b601239 | 520 | return IRQ_HANDLED; |
06051fde | 521 | } |
86794b43 | 522 | #endif /* SEC_GCTL */ |
cfefe3c6 | 523 | |
1394f032 | 524 | static struct irq_chip bfin_core_irqchip = { |
763e63c6 | 525 | .name = "CORE", |
4f19ea49 TG |
526 | .irq_mask = bfin_core_mask_irq, |
527 | .irq_unmask = bfin_core_unmask_irq, | |
1394f032 BW |
528 | }; |
529 | ||
86794b43 | 530 | #ifndef SEC_GCTL |
1394f032 | 531 | static struct irq_chip bfin_internal_irqchip = { |
763e63c6 | 532 | .name = "INTN", |
ff43a67f TG |
533 | .irq_mask = bfin_internal_mask_irq_chip, |
534 | .irq_unmask = bfin_internal_unmask_irq_chip, | |
ff43a67f TG |
535 | .irq_disable = bfin_internal_mask_irq_chip, |
536 | .irq_enable = bfin_internal_unmask_irq_chip, | |
0325f25a | 537 | #ifdef CONFIG_SMP |
ff43a67f | 538 | .irq_set_affinity = bfin_internal_set_affinity, |
0325f25a | 539 | #endif |
ff43a67f | 540 | .irq_set_wake = bfin_internal_set_wake_chip, |
1394f032 | 541 | }; |
86794b43 | 542 | #else |
4f6b600f SM |
543 | static struct irq_chip bfin_sec_irqchip = { |
544 | .name = "SEC", | |
545 | .irq_mask_ack = bfin_sec_mask_ack_irq, | |
546 | .irq_mask = bfin_sec_mask_ack_irq, | |
547 | .irq_unmask = bfin_sec_unmask_irq, | |
548 | .irq_eoi = bfin_sec_unmask_irq, | |
549 | .irq_disable = bfin_sec_disable, | |
550 | .irq_enable = bfin_sec_enable, | |
551 | }; | |
552 | #endif | |
553 | ||
f58c3276 | 554 | void bfin_handle_irq(unsigned irq) |
6a01f230 YL |
555 | { |
556 | #ifdef CONFIG_IPIPE | |
557 | struct pt_regs regs; /* Contents not used. */ | |
558 | ipipe_trace_irq_entry(irq); | |
559 | __ipipe_handle_irq(irq, ®s); | |
560 | ipipe_trace_irq_exit(irq); | |
561 | #else /* !CONFIG_IPIPE */ | |
b10bbbbc | 562 | generic_handle_irq(irq); |
6a01f230 YL |
563 | #endif /* !CONFIG_IPIPE */ |
564 | } | |
565 | ||
aec59c91 MH |
566 | #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) |
567 | static int mac_stat_int_mask; | |
568 | ||
569 | static void bfin_mac_status_ack_irq(unsigned int irq) | |
570 | { | |
571 | switch (irq) { | |
572 | case IRQ_MAC_MMCINT: | |
573 | bfin_write_EMAC_MMC_TIRQS( | |
574 | bfin_read_EMAC_MMC_TIRQE() & | |
575 | bfin_read_EMAC_MMC_TIRQS()); | |
576 | bfin_write_EMAC_MMC_RIRQS( | |
577 | bfin_read_EMAC_MMC_RIRQE() & | |
578 | bfin_read_EMAC_MMC_RIRQS()); | |
579 | break; | |
580 | case IRQ_MAC_RXFSINT: | |
581 | bfin_write_EMAC_RX_STKY( | |
582 | bfin_read_EMAC_RX_IRQE() & | |
583 | bfin_read_EMAC_RX_STKY()); | |
584 | break; | |
585 | case IRQ_MAC_TXFSINT: | |
586 | bfin_write_EMAC_TX_STKY( | |
587 | bfin_read_EMAC_TX_IRQE() & | |
588 | bfin_read_EMAC_TX_STKY()); | |
589 | break; | |
590 | case IRQ_MAC_WAKEDET: | |
591 | bfin_write_EMAC_WKUP_CTL( | |
592 | bfin_read_EMAC_WKUP_CTL() | MPKS | RWKS); | |
593 | break; | |
594 | default: | |
595 | /* These bits are W1C */ | |
596 | bfin_write_EMAC_SYSTAT(1L << (irq - IRQ_MAC_PHYINT)); | |
597 | break; | |
598 | } | |
599 | } | |
600 | ||
172d2d1d | 601 | static void bfin_mac_status_mask_irq(struct irq_data *d) |
aec59c91 | 602 | { |
172d2d1d TG |
603 | unsigned int irq = d->irq; |
604 | ||
aec59c91 | 605 | mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT)); |
f58c3276 | 606 | #ifdef BF537_FAMILY |
aec59c91 MH |
607 | switch (irq) { |
608 | case IRQ_MAC_PHYINT: | |
609 | bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE); | |
610 | break; | |
611 | default: | |
612 | break; | |
613 | } | |
614 | #else | |
615 | if (!mac_stat_int_mask) | |
616 | bfin_internal_mask_irq(IRQ_MAC_ERROR); | |
617 | #endif | |
618 | bfin_mac_status_ack_irq(irq); | |
619 | } | |
620 | ||
172d2d1d | 621 | static void bfin_mac_status_unmask_irq(struct irq_data *d) |
aec59c91 | 622 | { |
172d2d1d TG |
623 | unsigned int irq = d->irq; |
624 | ||
f58c3276 | 625 | #ifdef BF537_FAMILY |
aec59c91 MH |
626 | switch (irq) { |
627 | case IRQ_MAC_PHYINT: | |
628 | bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE); | |
629 | break; | |
630 | default: | |
631 | break; | |
632 | } | |
633 | #else | |
634 | if (!mac_stat_int_mask) | |
635 | bfin_internal_unmask_irq(IRQ_MAC_ERROR); | |
636 | #endif | |
637 | mac_stat_int_mask |= 1L << (irq - IRQ_MAC_PHYINT); | |
638 | } | |
639 | ||
640 | #ifdef CONFIG_PM | |
172d2d1d | 641 | int bfin_mac_status_set_wake(struct irq_data *d, unsigned int state) |
aec59c91 | 642 | { |
f58c3276 | 643 | #ifdef BF537_FAMILY |
aec59c91 MH |
644 | return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state); |
645 | #else | |
646 | return bfin_internal_set_wake(IRQ_MAC_ERROR, state); | |
647 | #endif | |
648 | } | |
fc6bd7b8 MF |
649 | #else |
650 | # define bfin_mac_status_set_wake NULL | |
aec59c91 MH |
651 | #endif |
652 | ||
653 | static struct irq_chip bfin_mac_status_irqchip = { | |
654 | .name = "MACST", | |
172d2d1d TG |
655 | .irq_mask = bfin_mac_status_mask_irq, |
656 | .irq_unmask = bfin_mac_status_unmask_irq, | |
172d2d1d | 657 | .irq_set_wake = bfin_mac_status_set_wake, |
aec59c91 MH |
658 | }; |
659 | ||
bd0b9ac4 | 660 | void bfin_demux_mac_status_irq(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 | ||
28438444 | 689 | static inline void bfin_set_irq_handler(struct irq_data *d, irq_flow_handler_t handle) |
bfd15117 | 690 | { |
6a01f230 | 691 | #ifdef CONFIG_IPIPE |
5b5da4c4 | 692 | handle = handle_level_irq; |
6a01f230 | 693 | #endif |
28438444 | 694 | irq_set_handler_locked(d, 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)) |
28438444 | 806 | bfin_set_irq_handler(d, handle_edge_irq); |
1394f032 | 807 | else |
28438444 | 808 | bfin_set_irq_handler(d, 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 | ||
bd0b9ac4 | 828 | void bfin_demux_gpio_irq(struct irq_desc *desc) |
1394f032 | 829 | { |
2b501769 | 830 | unsigned int inta_irq = irq_desc_get_irq(desc); |
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 */ |