]>
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> | |
6a01f230 YL |
18 | #ifdef CONFIG_IPIPE |
19 | #include <linux/ipipe.h> | |
20 | #endif | |
1394f032 BW |
21 | #ifdef CONFIG_KGDB |
22 | #include <linux/kgdb.h> | |
23 | #endif | |
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> |
7eb87fd3 MF |
29 | #include <asm/bfin5xx_spi.h> |
30 | #include <asm/bfin_sport.h> | |
15435a2a | 31 | #include <asm/bfin_can.h> |
1394f032 | 32 | |
7beb7439 MF |
33 | #define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1)) |
34 | ||
1394f032 BW |
35 | #ifdef BF537_FAMILY |
36 | # define BF537_GENERIC_ERROR_INT_DEMUX | |
7eb87fd3 MF |
37 | # define SPI_ERR_MASK (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE) /* SPI_STAT */ |
38 | # define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF) /* SPORT_STAT */ | |
39 | # define PPI_ERR_MASK (0xFFFF & ~FLD) /* PPI_STATUS */ | |
40 | # define EMAC_ERR_MASK (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE) /* EMAC_SYSTAT */ | |
41 | # define UART_ERR_MASK (0x6) /* UART_IIR */ | |
42 | # define CAN_ERR_MASK (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF) /* CAN_GIF */ | |
1394f032 BW |
43 | #else |
44 | # undef BF537_GENERIC_ERROR_INT_DEMUX | |
45 | #endif | |
46 | ||
47 | /* | |
48 | * NOTES: | |
49 | * - we have separated the physical Hardware interrupt from the | |
50 | * levels that the LINUX kernel sees (see the description in irq.h) | |
51 | * - | |
52 | */ | |
53 | ||
6b3087c6 | 54 | #ifndef CONFIG_SMP |
a99bbccd MF |
55 | /* Initialize this to an actual value to force it into the .data |
56 | * section so that we know it is properly initialized at entry into | |
57 | * the kernel but before bss is initialized to zero (which is where | |
58 | * it would live otherwise). The 0x1f magic represents the IRQs we | |
59 | * cannot actually mask out in hardware. | |
60 | */ | |
40059784 MF |
61 | unsigned long bfin_irq_flags = 0x1f; |
62 | EXPORT_SYMBOL(bfin_irq_flags); | |
6b3087c6 | 63 | #endif |
1394f032 BW |
64 | |
65 | /* The number of spurious interrupts */ | |
66 | atomic_t num_spurious; | |
67 | ||
cfefe3c6 MH |
68 | #ifdef CONFIG_PM |
69 | unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */ | |
4a88d0ce | 70 | unsigned vr_wakeup; |
cfefe3c6 MH |
71 | #endif |
72 | ||
1394f032 | 73 | struct ivgx { |
464abc5d | 74 | /* irq number for request_irq, available in mach-bf5xx/irq.h */ |
24a07a12 | 75 | unsigned int irqno; |
1394f032 | 76 | /* corresponding bit in the SIC_ISR register */ |
24a07a12 | 77 | unsigned int isrflag; |
1394f032 BW |
78 | } ivg_table[NR_PERI_INTS]; |
79 | ||
80 | struct ivg_slice { | |
81 | /* position of first irq in ivg_table for given ivg */ | |
82 | struct ivgx *ifirst; | |
83 | struct ivgx *istop; | |
84 | } ivg7_13[IVG13 - IVG7 + 1]; | |
85 | ||
1394f032 BW |
86 | |
87 | /* | |
88 | * Search SIC_IAR and fill tables with the irqvalues | |
89 | * and their positions in the SIC_ISR register. | |
90 | */ | |
91 | static void __init search_IAR(void) | |
92 | { | |
93 | unsigned ivg, irq_pos = 0; | |
94 | for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) { | |
80fcdb95 | 95 | int irqN; |
1394f032 | 96 | |
34e0fc89 | 97 | ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos]; |
1394f032 | 98 | |
80fcdb95 MF |
99 | for (irqN = 0; irqN < NR_PERI_INTS; irqN += 4) { |
100 | int irqn; | |
101 | u32 iar = bfin_read32((unsigned long *)SIC_IAR0 + | |
102 | #if defined(CONFIG_BF51x) || defined(CONFIG_BF52x) || \ | |
103 | defined(CONFIG_BF538) || defined(CONFIG_BF539) | |
104 | ((irqN % 32) >> 3) + ((irqN / 32) * ((SIC_IAR4 - SIC_IAR0) / 4)) | |
59003145 | 105 | #else |
80fcdb95 | 106 | (irqN >> 3) |
59003145 | 107 | #endif |
80fcdb95 MF |
108 | ); |
109 | ||
110 | for (irqn = irqN; irqn < irqN + 4; ++irqn) { | |
111 | int iar_shift = (irqn & 7) * 4; | |
112 | if (ivg == (0xf & (iar >> iar_shift))) { | |
113 | ivg_table[irq_pos].irqno = IVG7 + irqn; | |
114 | ivg_table[irq_pos].isrflag = 1 << (irqn % 32); | |
115 | ivg7_13[ivg].istop++; | |
116 | irq_pos++; | |
117 | } | |
1394f032 BW |
118 | } |
119 | } | |
120 | } | |
121 | } | |
122 | ||
123 | /* | |
464abc5d | 124 | * This is for core internal IRQs |
1394f032 BW |
125 | */ |
126 | ||
464abc5d | 127 | static void bfin_ack_noop(unsigned int irq) |
1394f032 BW |
128 | { |
129 | /* Dummy function. */ | |
130 | } | |
131 | ||
132 | static void bfin_core_mask_irq(unsigned int irq) | |
133 | { | |
40059784 | 134 | bfin_irq_flags &= ~(1 << irq); |
6a01f230 YL |
135 | if (!irqs_disabled_hw()) |
136 | local_irq_enable_hw(); | |
1394f032 BW |
137 | } |
138 | ||
139 | static void bfin_core_unmask_irq(unsigned int irq) | |
140 | { | |
40059784 | 141 | bfin_irq_flags |= 1 << irq; |
1394f032 BW |
142 | /* |
143 | * If interrupts are enabled, IMASK must contain the same value | |
40059784 | 144 | * as bfin_irq_flags. Make sure that invariant holds. If interrupts |
1394f032 BW |
145 | * are currently disabled we need not do anything; one of the |
146 | * callers will take care of setting IMASK to the proper value | |
147 | * when reenabling interrupts. | |
40059784 | 148 | * local_irq_enable just does "STI bfin_irq_flags", so it's exactly |
1394f032 BW |
149 | * what we need. |
150 | */ | |
6a01f230 YL |
151 | if (!irqs_disabled_hw()) |
152 | local_irq_enable_hw(); | |
1394f032 BW |
153 | return; |
154 | } | |
155 | ||
156 | static void bfin_internal_mask_irq(unsigned int irq) | |
157 | { | |
9bd50df6 PG |
158 | unsigned long flags; |
159 | ||
59003145 | 160 | #ifdef CONFIG_BF53x |
9bd50df6 | 161 | local_irq_save_hw(flags); |
1394f032 | 162 | bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & |
464abc5d | 163 | ~(1 << SIC_SYSIRQ(irq))); |
24a07a12 RH |
164 | #else |
165 | unsigned mask_bank, mask_bit; | |
9bd50df6 | 166 | local_irq_save_hw(flags); |
464abc5d MH |
167 | mask_bank = SIC_SYSIRQ(irq) / 32; |
168 | mask_bit = SIC_SYSIRQ(irq) % 32; | |
c04d66bb BW |
169 | bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & |
170 | ~(1 << mask_bit)); | |
6b3087c6 GY |
171 | #ifdef CONFIG_SMP |
172 | bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) & | |
173 | ~(1 << mask_bit)); | |
174 | #endif | |
24a07a12 | 175 | #endif |
9bd50df6 | 176 | local_irq_restore_hw(flags); |
1394f032 BW |
177 | } |
178 | ||
0325f25a SZ |
179 | #ifdef CONFIG_SMP |
180 | static void bfin_internal_unmask_irq_affinity(unsigned int irq, | |
181 | const struct cpumask *affinity) | |
182 | #else | |
1394f032 | 183 | static void bfin_internal_unmask_irq(unsigned int irq) |
0325f25a | 184 | #endif |
1394f032 | 185 | { |
9bd50df6 PG |
186 | unsigned long flags; |
187 | ||
59003145 | 188 | #ifdef CONFIG_BF53x |
9bd50df6 | 189 | local_irq_save_hw(flags); |
1394f032 | 190 | bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | |
464abc5d | 191 | (1 << SIC_SYSIRQ(irq))); |
24a07a12 RH |
192 | #else |
193 | unsigned mask_bank, mask_bit; | |
9bd50df6 | 194 | local_irq_save_hw(flags); |
464abc5d MH |
195 | mask_bank = SIC_SYSIRQ(irq) / 32; |
196 | mask_bit = SIC_SYSIRQ(irq) % 32; | |
6b3087c6 | 197 | #ifdef CONFIG_SMP |
0325f25a SZ |
198 | if (cpumask_test_cpu(0, affinity)) |
199 | #endif | |
200 | bfin_write_SIC_IMASK(mask_bank, | |
201 | bfin_read_SIC_IMASK(mask_bank) | | |
202 | (1 << mask_bit)); | |
203 | #ifdef CONFIG_SMP | |
204 | if (cpumask_test_cpu(1, affinity)) | |
205 | bfin_write_SICB_IMASK(mask_bank, | |
206 | bfin_read_SICB_IMASK(mask_bank) | | |
207 | (1 << mask_bit)); | |
6b3087c6 | 208 | #endif |
24a07a12 | 209 | #endif |
9bd50df6 | 210 | local_irq_restore_hw(flags); |
1394f032 BW |
211 | } |
212 | ||
0325f25a SZ |
213 | #ifdef CONFIG_SMP |
214 | static void bfin_internal_unmask_irq(unsigned int irq) | |
215 | { | |
216 | struct irq_desc *desc = irq_to_desc(irq); | |
217 | bfin_internal_unmask_irq_affinity(irq, desc->affinity); | |
218 | } | |
219 | ||
220 | static int bfin_internal_set_affinity(unsigned int irq, const struct cpumask *mask) | |
221 | { | |
222 | bfin_internal_mask_irq(irq); | |
223 | bfin_internal_unmask_irq_affinity(irq, mask); | |
224 | ||
225 | return 0; | |
226 | } | |
227 | #endif | |
228 | ||
cfefe3c6 MH |
229 | #ifdef CONFIG_PM |
230 | int bfin_internal_set_wake(unsigned int irq, unsigned int state) | |
231 | { | |
8d022374 | 232 | u32 bank, bit, wakeup = 0; |
cfefe3c6 | 233 | unsigned long flags; |
464abc5d MH |
234 | bank = SIC_SYSIRQ(irq) / 32; |
235 | bit = SIC_SYSIRQ(irq) % 32; | |
cfefe3c6 | 236 | |
4a88d0ce MH |
237 | switch (irq) { |
238 | #ifdef IRQ_RTC | |
239 | case IRQ_RTC: | |
240 | wakeup |= WAKE; | |
241 | break; | |
242 | #endif | |
243 | #ifdef IRQ_CAN0_RX | |
244 | case IRQ_CAN0_RX: | |
245 | wakeup |= CANWE; | |
246 | break; | |
247 | #endif | |
248 | #ifdef IRQ_CAN1_RX | |
249 | case IRQ_CAN1_RX: | |
250 | wakeup |= CANWE; | |
251 | break; | |
252 | #endif | |
253 | #ifdef IRQ_USB_INT0 | |
254 | case IRQ_USB_INT0: | |
255 | wakeup |= USBWE; | |
256 | break; | |
257 | #endif | |
d310fb4b | 258 | #ifdef CONFIG_BF54x |
4a88d0ce MH |
259 | case IRQ_CNT: |
260 | wakeup |= ROTWE; | |
261 | break; | |
262 | #endif | |
263 | default: | |
264 | break; | |
265 | } | |
266 | ||
6a01f230 | 267 | local_irq_save_hw(flags); |
cfefe3c6 | 268 | |
4a88d0ce | 269 | if (state) { |
cfefe3c6 | 270 | bfin_sic_iwr[bank] |= (1 << bit); |
4a88d0ce MH |
271 | vr_wakeup |= wakeup; |
272 | ||
273 | } else { | |
cfefe3c6 | 274 | bfin_sic_iwr[bank] &= ~(1 << bit); |
4a88d0ce MH |
275 | vr_wakeup &= ~wakeup; |
276 | } | |
cfefe3c6 | 277 | |
6a01f230 | 278 | local_irq_restore_hw(flags); |
cfefe3c6 MH |
279 | |
280 | return 0; | |
281 | } | |
282 | #endif | |
283 | ||
1394f032 | 284 | static struct irq_chip bfin_core_irqchip = { |
763e63c6 | 285 | .name = "CORE", |
464abc5d | 286 | .ack = bfin_ack_noop, |
1394f032 BW |
287 | .mask = bfin_core_mask_irq, |
288 | .unmask = bfin_core_unmask_irq, | |
289 | }; | |
290 | ||
291 | static struct irq_chip bfin_internal_irqchip = { | |
763e63c6 | 292 | .name = "INTN", |
464abc5d | 293 | .ack = bfin_ack_noop, |
1394f032 BW |
294 | .mask = bfin_internal_mask_irq, |
295 | .unmask = bfin_internal_unmask_irq, | |
ce3b7bb6 MH |
296 | .mask_ack = bfin_internal_mask_irq, |
297 | .disable = bfin_internal_mask_irq, | |
298 | .enable = bfin_internal_unmask_irq, | |
0325f25a SZ |
299 | #ifdef CONFIG_SMP |
300 | .set_affinity = bfin_internal_set_affinity, | |
301 | #endif | |
cfefe3c6 MH |
302 | #ifdef CONFIG_PM |
303 | .set_wake = bfin_internal_set_wake, | |
304 | #endif | |
1394f032 BW |
305 | }; |
306 | ||
6a01f230 YL |
307 | static void bfin_handle_irq(unsigned irq) |
308 | { | |
309 | #ifdef CONFIG_IPIPE | |
310 | struct pt_regs regs; /* Contents not used. */ | |
311 | ipipe_trace_irq_entry(irq); | |
312 | __ipipe_handle_irq(irq, ®s); | |
313 | ipipe_trace_irq_exit(irq); | |
314 | #else /* !CONFIG_IPIPE */ | |
315 | struct irq_desc *desc = irq_desc + irq; | |
316 | desc->handle_irq(irq, desc); | |
317 | #endif /* !CONFIG_IPIPE */ | |
318 | } | |
319 | ||
1394f032 BW |
320 | #ifdef BF537_GENERIC_ERROR_INT_DEMUX |
321 | static int error_int_mask; | |
322 | ||
1394f032 BW |
323 | static void bfin_generic_error_mask_irq(unsigned int irq) |
324 | { | |
325 | error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR)); | |
464abc5d MH |
326 | if (!error_int_mask) |
327 | bfin_internal_mask_irq(IRQ_GENERIC_ERROR); | |
1394f032 BW |
328 | } |
329 | ||
330 | static void bfin_generic_error_unmask_irq(unsigned int irq) | |
331 | { | |
464abc5d | 332 | bfin_internal_unmask_irq(IRQ_GENERIC_ERROR); |
1394f032 BW |
333 | error_int_mask |= 1L << (irq - IRQ_PPI_ERROR); |
334 | } | |
335 | ||
336 | static struct irq_chip bfin_generic_error_irqchip = { | |
763e63c6 | 337 | .name = "ERROR", |
464abc5d MH |
338 | .ack = bfin_ack_noop, |
339 | .mask_ack = bfin_generic_error_mask_irq, | |
1394f032 BW |
340 | .mask = bfin_generic_error_mask_irq, |
341 | .unmask = bfin_generic_error_unmask_irq, | |
342 | }; | |
343 | ||
344 | static void bfin_demux_error_irq(unsigned int int_err_irq, | |
2c4f829b | 345 | struct irq_desc *inta_desc) |
1394f032 BW |
346 | { |
347 | int irq = 0; | |
348 | ||
1394f032 BW |
349 | #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) |
350 | if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK) | |
351 | irq = IRQ_MAC_ERROR; | |
352 | else | |
353 | #endif | |
354 | if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK) | |
355 | irq = IRQ_SPORT0_ERROR; | |
356 | else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK) | |
357 | irq = IRQ_SPORT1_ERROR; | |
358 | else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK) | |
359 | irq = IRQ_PPI_ERROR; | |
360 | else if (bfin_read_CAN_GIF() & CAN_ERR_MASK) | |
361 | irq = IRQ_CAN_ERROR; | |
362 | else if (bfin_read_SPI_STAT() & SPI_ERR_MASK) | |
363 | irq = IRQ_SPI_ERROR; | |
7eb87fd3 | 364 | else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK) |
1394f032 | 365 | irq = IRQ_UART0_ERROR; |
7eb87fd3 | 366 | else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK) |
1394f032 BW |
367 | irq = IRQ_UART1_ERROR; |
368 | ||
369 | if (irq) { | |
6a01f230 YL |
370 | if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) |
371 | bfin_handle_irq(irq); | |
372 | else { | |
1394f032 BW |
373 | |
374 | switch (irq) { | |
375 | case IRQ_PPI_ERROR: | |
376 | bfin_write_PPI_STATUS(PPI_ERR_MASK); | |
377 | break; | |
378 | #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) | |
379 | case IRQ_MAC_ERROR: | |
380 | bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK); | |
381 | break; | |
382 | #endif | |
383 | case IRQ_SPORT0_ERROR: | |
384 | bfin_write_SPORT0_STAT(SPORT_ERR_MASK); | |
385 | break; | |
386 | ||
387 | case IRQ_SPORT1_ERROR: | |
388 | bfin_write_SPORT1_STAT(SPORT_ERR_MASK); | |
389 | break; | |
390 | ||
391 | case IRQ_CAN_ERROR: | |
392 | bfin_write_CAN_GIS(CAN_ERR_MASK); | |
393 | break; | |
394 | ||
395 | case IRQ_SPI_ERROR: | |
396 | bfin_write_SPI_STAT(SPI_ERR_MASK); | |
397 | break; | |
398 | ||
399 | default: | |
400 | break; | |
401 | } | |
402 | ||
403 | pr_debug("IRQ %d:" | |
34e0fc89 MH |
404 | " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n", |
405 | irq); | |
1394f032 BW |
406 | } |
407 | } else | |
408 | printk(KERN_ERR | |
409 | "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR" | |
410 | " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n", | |
b85d858b | 411 | __func__, __FILE__, __LINE__); |
1394f032 | 412 | |
1394f032 BW |
413 | } |
414 | #endif /* BF537_GENERIC_ERROR_INT_DEMUX */ | |
415 | ||
aec59c91 MH |
416 | #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) |
417 | static int mac_stat_int_mask; | |
418 | ||
419 | static void bfin_mac_status_ack_irq(unsigned int irq) | |
420 | { | |
421 | switch (irq) { | |
422 | case IRQ_MAC_MMCINT: | |
423 | bfin_write_EMAC_MMC_TIRQS( | |
424 | bfin_read_EMAC_MMC_TIRQE() & | |
425 | bfin_read_EMAC_MMC_TIRQS()); | |
426 | bfin_write_EMAC_MMC_RIRQS( | |
427 | bfin_read_EMAC_MMC_RIRQE() & | |
428 | bfin_read_EMAC_MMC_RIRQS()); | |
429 | break; | |
430 | case IRQ_MAC_RXFSINT: | |
431 | bfin_write_EMAC_RX_STKY( | |
432 | bfin_read_EMAC_RX_IRQE() & | |
433 | bfin_read_EMAC_RX_STKY()); | |
434 | break; | |
435 | case IRQ_MAC_TXFSINT: | |
436 | bfin_write_EMAC_TX_STKY( | |
437 | bfin_read_EMAC_TX_IRQE() & | |
438 | bfin_read_EMAC_TX_STKY()); | |
439 | break; | |
440 | case IRQ_MAC_WAKEDET: | |
441 | bfin_write_EMAC_WKUP_CTL( | |
442 | bfin_read_EMAC_WKUP_CTL() | MPKS | RWKS); | |
443 | break; | |
444 | default: | |
445 | /* These bits are W1C */ | |
446 | bfin_write_EMAC_SYSTAT(1L << (irq - IRQ_MAC_PHYINT)); | |
447 | break; | |
448 | } | |
449 | } | |
450 | ||
451 | static void bfin_mac_status_mask_irq(unsigned int irq) | |
452 | { | |
453 | mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT)); | |
454 | #ifdef BF537_GENERIC_ERROR_INT_DEMUX | |
455 | switch (irq) { | |
456 | case IRQ_MAC_PHYINT: | |
457 | bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE); | |
458 | break; | |
459 | default: | |
460 | break; | |
461 | } | |
462 | #else | |
463 | if (!mac_stat_int_mask) | |
464 | bfin_internal_mask_irq(IRQ_MAC_ERROR); | |
465 | #endif | |
466 | bfin_mac_status_ack_irq(irq); | |
467 | } | |
468 | ||
469 | static void bfin_mac_status_unmask_irq(unsigned int irq) | |
470 | { | |
471 | #ifdef BF537_GENERIC_ERROR_INT_DEMUX | |
472 | switch (irq) { | |
473 | case IRQ_MAC_PHYINT: | |
474 | bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE); | |
475 | break; | |
476 | default: | |
477 | break; | |
478 | } | |
479 | #else | |
480 | if (!mac_stat_int_mask) | |
481 | bfin_internal_unmask_irq(IRQ_MAC_ERROR); | |
482 | #endif | |
483 | mac_stat_int_mask |= 1L << (irq - IRQ_MAC_PHYINT); | |
484 | } | |
485 | ||
486 | #ifdef CONFIG_PM | |
487 | int bfin_mac_status_set_wake(unsigned int irq, unsigned int state) | |
488 | { | |
489 | #ifdef BF537_GENERIC_ERROR_INT_DEMUX | |
490 | return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state); | |
491 | #else | |
492 | return bfin_internal_set_wake(IRQ_MAC_ERROR, state); | |
493 | #endif | |
494 | } | |
495 | #endif | |
496 | ||
497 | static struct irq_chip bfin_mac_status_irqchip = { | |
498 | .name = "MACST", | |
499 | .ack = bfin_ack_noop, | |
500 | .mask_ack = bfin_mac_status_mask_irq, | |
501 | .mask = bfin_mac_status_mask_irq, | |
502 | .unmask = bfin_mac_status_unmask_irq, | |
503 | #ifdef CONFIG_PM | |
504 | .set_wake = bfin_mac_status_set_wake, | |
505 | #endif | |
506 | }; | |
507 | ||
508 | static void bfin_demux_mac_status_irq(unsigned int int_err_irq, | |
509 | struct irq_desc *inta_desc) | |
510 | { | |
511 | int i, irq = 0; | |
512 | u32 status = bfin_read_EMAC_SYSTAT(); | |
513 | ||
514 | for (i = 0; i < (IRQ_MAC_STMDONE - IRQ_MAC_PHYINT); i++) | |
515 | if (status & (1L << i)) { | |
516 | irq = IRQ_MAC_PHYINT + i; | |
517 | break; | |
518 | } | |
519 | ||
520 | if (irq) { | |
521 | if (mac_stat_int_mask & (1L << (irq - IRQ_MAC_PHYINT))) { | |
522 | bfin_handle_irq(irq); | |
523 | } else { | |
524 | bfin_mac_status_ack_irq(irq); | |
525 | pr_debug("IRQ %d:" | |
526 | " MASKED MAC ERROR INTERRUPT ASSERTED\n", | |
527 | irq); | |
528 | } | |
529 | } else | |
530 | printk(KERN_ERR | |
531 | "%s : %s : LINE %d :\nIRQ ?: MAC ERROR" | |
532 | " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n", | |
533 | __func__, __FILE__, __LINE__); | |
534 | } | |
535 | #endif | |
536 | ||
bfd15117 GY |
537 | static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle) |
538 | { | |
6a01f230 | 539 | #ifdef CONFIG_IPIPE |
9bd50df6 | 540 | _set_irq_handler(irq, handle_level_irq); |
6a01f230 | 541 | #else |
bfd15117 GY |
542 | struct irq_desc *desc = irq_desc + irq; |
543 | /* May not call generic set_irq_handler() due to spinlock | |
544 | recursion. */ | |
545 | desc->handle_irq = handle; | |
6a01f230 | 546 | #endif |
bfd15117 GY |
547 | } |
548 | ||
8d022374 | 549 | static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS); |
affee2b2 | 550 | extern void bfin_gpio_irq_prepare(unsigned gpio); |
6fce6a8d | 551 | |
8d022374 MH |
552 | #if !defined(CONFIG_BF54x) |
553 | ||
1394f032 BW |
554 | static void bfin_gpio_ack_irq(unsigned int irq) |
555 | { | |
8d022374 MH |
556 | /* AFAIK ack_irq in case mask_ack is provided |
557 | * get's only called for edge sense irqs | |
558 | */ | |
559 | set_gpio_data(irq_to_gpio(irq), 0); | |
1394f032 BW |
560 | } |
561 | ||
562 | static void bfin_gpio_mask_ack_irq(unsigned int irq) | |
563 | { | |
8d022374 MH |
564 | struct irq_desc *desc = irq_desc + irq; |
565 | u32 gpionr = irq_to_gpio(irq); | |
1394f032 | 566 | |
8d022374 | 567 | if (desc->handle_irq == handle_edge_irq) |
1394f032 | 568 | set_gpio_data(gpionr, 0); |
1394f032 BW |
569 | |
570 | set_gpio_maska(gpionr, 0); | |
1394f032 BW |
571 | } |
572 | ||
573 | static void bfin_gpio_mask_irq(unsigned int irq) | |
574 | { | |
8d022374 | 575 | set_gpio_maska(irq_to_gpio(irq), 0); |
1394f032 BW |
576 | } |
577 | ||
578 | static void bfin_gpio_unmask_irq(unsigned int irq) | |
579 | { | |
8d022374 | 580 | set_gpio_maska(irq_to_gpio(irq), 1); |
1394f032 BW |
581 | } |
582 | ||
583 | static unsigned int bfin_gpio_irq_startup(unsigned int irq) | |
584 | { | |
8d022374 | 585 | u32 gpionr = irq_to_gpio(irq); |
1394f032 | 586 | |
8d022374 | 587 | if (__test_and_set_bit(gpionr, gpio_enabled)) |
affee2b2 | 588 | bfin_gpio_irq_prepare(gpionr); |
1394f032 | 589 | |
1394f032 BW |
590 | bfin_gpio_unmask_irq(irq); |
591 | ||
affee2b2 | 592 | return 0; |
1394f032 BW |
593 | } |
594 | ||
595 | static void bfin_gpio_irq_shutdown(unsigned int irq) | |
596 | { | |
30af6d49 GY |
597 | u32 gpionr = irq_to_gpio(irq); |
598 | ||
1394f032 | 599 | bfin_gpio_mask_irq(irq); |
30af6d49 | 600 | __clear_bit(gpionr, gpio_enabled); |
9570ff4a | 601 | bfin_gpio_irq_free(gpionr); |
1394f032 BW |
602 | } |
603 | ||
604 | static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) | |
605 | { | |
8eb3e3bf GY |
606 | int ret; |
607 | char buf[16]; | |
8d022374 | 608 | u32 gpionr = irq_to_gpio(irq); |
1394f032 BW |
609 | |
610 | if (type == IRQ_TYPE_PROBE) { | |
611 | /* only probe unenabled GPIO interrupt lines */ | |
c3695341 | 612 | if (test_bit(gpionr, gpio_enabled)) |
1394f032 BW |
613 | return 0; |
614 | type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | |
615 | } | |
616 | ||
617 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | | |
34e0fc89 | 618 | IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { |
8d022374 | 619 | |
9570ff4a GY |
620 | snprintf(buf, 16, "gpio-irq%d", irq); |
621 | ret = bfin_gpio_irq_request(gpionr, buf); | |
622 | if (ret) | |
623 | return ret; | |
624 | ||
8d022374 | 625 | if (__test_and_set_bit(gpionr, gpio_enabled)) |
affee2b2 | 626 | bfin_gpio_irq_prepare(gpionr); |
1394f032 | 627 | |
1394f032 | 628 | } else { |
8d022374 | 629 | __clear_bit(gpionr, gpio_enabled); |
1394f032 BW |
630 | return 0; |
631 | } | |
632 | ||
f1bceb47 | 633 | set_gpio_inen(gpionr, 0); |
1394f032 | 634 | set_gpio_dir(gpionr, 0); |
1394f032 BW |
635 | |
636 | if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | |
637 | == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | |
638 | set_gpio_both(gpionr, 1); | |
639 | else | |
640 | set_gpio_both(gpionr, 0); | |
641 | ||
642 | if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) | |
643 | set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */ | |
644 | else | |
645 | set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */ | |
646 | ||
f1bceb47 MH |
647 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { |
648 | set_gpio_edge(gpionr, 1); | |
649 | set_gpio_inen(gpionr, 1); | |
f1bceb47 MH |
650 | set_gpio_data(gpionr, 0); |
651 | ||
652 | } else { | |
653 | set_gpio_edge(gpionr, 0); | |
f1bceb47 MH |
654 | set_gpio_inen(gpionr, 1); |
655 | } | |
656 | ||
1394f032 | 657 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) |
bfd15117 | 658 | bfin_set_irq_handler(irq, handle_edge_irq); |
1394f032 | 659 | else |
bfd15117 | 660 | bfin_set_irq_handler(irq, handle_level_irq); |
1394f032 BW |
661 | |
662 | return 0; | |
663 | } | |
664 | ||
cfefe3c6 MH |
665 | #ifdef CONFIG_PM |
666 | int bfin_gpio_set_wake(unsigned int irq, unsigned int state) | |
667 | { | |
bb84dbf6 | 668 | return gpio_pm_wakeup_ctrl(irq_to_gpio(irq), state); |
cfefe3c6 MH |
669 | } |
670 | #endif | |
671 | ||
2c4f829b MH |
672 | static void bfin_demux_gpio_irq(unsigned int inta_irq, |
673 | struct irq_desc *desc) | |
1394f032 | 674 | { |
2c4f829b MH |
675 | unsigned int i, gpio, mask, irq, search = 0; |
676 | ||
677 | switch (inta_irq) { | |
678 | #if defined(CONFIG_BF53x) | |
679 | case IRQ_PROG_INTA: | |
680 | irq = IRQ_PF0; | |
681 | search = 1; | |
682 | break; | |
683 | # if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)) | |
684 | case IRQ_MAC_RX: | |
685 | irq = IRQ_PH0; | |
686 | break; | |
687 | # endif | |
dc26aec2 MH |
688 | #elif defined(CONFIG_BF538) || defined(CONFIG_BF539) |
689 | case IRQ_PORTF_INTA: | |
690 | irq = IRQ_PF0; | |
691 | break; | |
2f6f4bcd | 692 | #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) |
2c4f829b MH |
693 | case IRQ_PORTF_INTA: |
694 | irq = IRQ_PF0; | |
695 | break; | |
696 | case IRQ_PORTG_INTA: | |
697 | irq = IRQ_PG0; | |
698 | break; | |
699 | case IRQ_PORTH_INTA: | |
700 | irq = IRQ_PH0; | |
701 | break; | |
702 | #elif defined(CONFIG_BF561) | |
703 | case IRQ_PROG0_INTA: | |
704 | irq = IRQ_PF0; | |
705 | break; | |
706 | case IRQ_PROG1_INTA: | |
707 | irq = IRQ_PF16; | |
708 | break; | |
709 | case IRQ_PROG2_INTA: | |
710 | irq = IRQ_PF32; | |
711 | break; | |
712 | #endif | |
713 | default: | |
714 | BUG(); | |
715 | return; | |
716 | } | |
717 | ||
718 | if (search) { | |
cfefe3c6 | 719 | for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { |
2c4f829b MH |
720 | irq += i; |
721 | ||
8d022374 | 722 | mask = get_gpiop_data(i) & get_gpiop_maska(i); |
2c4f829b MH |
723 | |
724 | while (mask) { | |
6a01f230 YL |
725 | if (mask & 1) |
726 | bfin_handle_irq(irq); | |
2c4f829b MH |
727 | irq++; |
728 | mask >>= 1; | |
1394f032 | 729 | } |
1394f032 | 730 | } |
2c4f829b MH |
731 | } else { |
732 | gpio = irq_to_gpio(irq); | |
8d022374 | 733 | mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio); |
2c4f829b MH |
734 | |
735 | do { | |
6a01f230 YL |
736 | if (mask & 1) |
737 | bfin_handle_irq(irq); | |
2c4f829b MH |
738 | irq++; |
739 | mask >>= 1; | |
740 | } while (mask); | |
1394f032 | 741 | } |
2c4f829b | 742 | |
1394f032 BW |
743 | } |
744 | ||
a055b2b4 | 745 | #else /* CONFIG_BF54x */ |
34e0fc89 MH |
746 | |
747 | #define NR_PINT_SYS_IRQS 4 | |
748 | #define NR_PINT_BITS 32 | |
749 | #define NR_PINTS 160 | |
750 | #define IRQ_NOT_AVAIL 0xFF | |
751 | ||
752 | #define PINT_2_BANK(x) ((x) >> 5) | |
753 | #define PINT_2_BIT(x) ((x) & 0x1F) | |
754 | #define PINT_BIT(x) (1 << (PINT_2_BIT(x))) | |
755 | ||
756 | static unsigned char irq2pint_lut[NR_PINTS]; | |
e3f23000 | 757 | static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS]; |
34e0fc89 MH |
758 | |
759 | struct pin_int_t { | |
760 | unsigned int mask_set; | |
761 | unsigned int mask_clear; | |
762 | unsigned int request; | |
763 | unsigned int assign; | |
764 | unsigned int edge_set; | |
765 | unsigned int edge_clear; | |
766 | unsigned int invert_set; | |
767 | unsigned int invert_clear; | |
768 | unsigned int pinstate; | |
769 | unsigned int latch; | |
770 | }; | |
771 | ||
772 | static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = { | |
773 | (struct pin_int_t *)PINT0_MASK_SET, | |
774 | (struct pin_int_t *)PINT1_MASK_SET, | |
775 | (struct pin_int_t *)PINT2_MASK_SET, | |
776 | (struct pin_int_t *)PINT3_MASK_SET, | |
777 | }; | |
778 | ||
8d022374 | 779 | inline unsigned int get_irq_base(u32 bank, u8 bmap) |
34e0fc89 | 780 | { |
8d022374 | 781 | unsigned int irq_base; |
34e0fc89 MH |
782 | |
783 | if (bank < 2) { /*PA-PB */ | |
784 | irq_base = IRQ_PA0 + bmap * 16; | |
785 | } else { /*PC-PJ */ | |
786 | irq_base = IRQ_PC0 + bmap * 16; | |
787 | } | |
788 | ||
789 | return irq_base; | |
34e0fc89 MH |
790 | } |
791 | ||
792 | /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */ | |
793 | void init_pint_lut(void) | |
794 | { | |
795 | u16 bank, bit, irq_base, bit_pos; | |
796 | u32 pint_assign; | |
797 | u8 bmap; | |
798 | ||
799 | memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut)); | |
800 | ||
801 | for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) { | |
802 | ||
803 | pint_assign = pint[bank]->assign; | |
804 | ||
805 | for (bit = 0; bit < NR_PINT_BITS; bit++) { | |
806 | ||
807 | bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF; | |
808 | ||
809 | irq_base = get_irq_base(bank, bmap); | |
810 | ||
811 | irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0); | |
812 | bit_pos = bit + bank * NR_PINT_BITS; | |
813 | ||
e3f23000 | 814 | pint2irq_lut[bit_pos] = irq_base - SYS_IRQS; |
34e0fc89 | 815 | irq2pint_lut[irq_base - SYS_IRQS] = bit_pos; |
34e0fc89 | 816 | } |
34e0fc89 | 817 | } |
34e0fc89 MH |
818 | } |
819 | ||
34e0fc89 MH |
820 | static void bfin_gpio_ack_irq(unsigned int irq) |
821 | { | |
8d022374 MH |
822 | struct irq_desc *desc = irq_desc + irq; |
823 | u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; | |
8baf560b | 824 | u32 pintbit = PINT_BIT(pint_val); |
8d022374 | 825 | u32 bank = PINT_2_BANK(pint_val); |
8baf560b | 826 | |
8d022374 | 827 | if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { |
8baf560b MH |
828 | if (pint[bank]->invert_set & pintbit) |
829 | pint[bank]->invert_clear = pintbit; | |
830 | else | |
831 | pint[bank]->invert_set = pintbit; | |
832 | } | |
833 | pint[bank]->request = pintbit; | |
34e0fc89 | 834 | |
34e0fc89 MH |
835 | } |
836 | ||
837 | static void bfin_gpio_mask_ack_irq(unsigned int irq) | |
838 | { | |
8d022374 MH |
839 | struct irq_desc *desc = irq_desc + irq; |
840 | u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; | |
e3f23000 | 841 | u32 pintbit = PINT_BIT(pint_val); |
8d022374 | 842 | u32 bank = PINT_2_BANK(pint_val); |
34e0fc89 | 843 | |
8d022374 | 844 | if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { |
8baf560b MH |
845 | if (pint[bank]->invert_set & pintbit) |
846 | pint[bank]->invert_clear = pintbit; | |
847 | else | |
848 | pint[bank]->invert_set = pintbit; | |
849 | } | |
850 | ||
e3f23000 MH |
851 | pint[bank]->request = pintbit; |
852 | pint[bank]->mask_clear = pintbit; | |
34e0fc89 MH |
853 | } |
854 | ||
855 | static void bfin_gpio_mask_irq(unsigned int irq) | |
856 | { | |
8d022374 | 857 | u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; |
34e0fc89 MH |
858 | |
859 | pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val); | |
34e0fc89 MH |
860 | } |
861 | ||
862 | static void bfin_gpio_unmask_irq(unsigned int irq) | |
863 | { | |
8d022374 | 864 | u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; |
e3f23000 | 865 | u32 pintbit = PINT_BIT(pint_val); |
8d022374 | 866 | u32 bank = PINT_2_BANK(pint_val); |
34e0fc89 | 867 | |
e3f23000 MH |
868 | pint[bank]->request = pintbit; |
869 | pint[bank]->mask_set = pintbit; | |
34e0fc89 MH |
870 | } |
871 | ||
872 | static unsigned int bfin_gpio_irq_startup(unsigned int irq) | |
873 | { | |
8d022374 MH |
874 | u32 gpionr = irq_to_gpio(irq); |
875 | u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; | |
34e0fc89 | 876 | |
50e163ce MH |
877 | if (pint_val == IRQ_NOT_AVAIL) { |
878 | printk(KERN_ERR | |
879 | "GPIO IRQ %d :Not in PINT Assign table " | |
880 | "Reconfigure Interrupt to Port Assignemt\n", irq); | |
34e0fc89 | 881 | return -ENODEV; |
50e163ce | 882 | } |
34e0fc89 | 883 | |
8d022374 | 884 | if (__test_and_set_bit(gpionr, gpio_enabled)) |
affee2b2 | 885 | bfin_gpio_irq_prepare(gpionr); |
34e0fc89 | 886 | |
34e0fc89 MH |
887 | bfin_gpio_unmask_irq(irq); |
888 | ||
affee2b2 | 889 | return 0; |
34e0fc89 MH |
890 | } |
891 | ||
892 | static void bfin_gpio_irq_shutdown(unsigned int irq) | |
893 | { | |
8d022374 | 894 | u32 gpionr = irq_to_gpio(irq); |
8baf560b | 895 | |
34e0fc89 | 896 | bfin_gpio_mask_irq(irq); |
8d022374 | 897 | __clear_bit(gpionr, gpio_enabled); |
9570ff4a | 898 | bfin_gpio_irq_free(gpionr); |
34e0fc89 MH |
899 | } |
900 | ||
901 | static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) | |
902 | { | |
8eb3e3bf GY |
903 | int ret; |
904 | char buf[16]; | |
8d022374 MH |
905 | u32 gpionr = irq_to_gpio(irq); |
906 | u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; | |
e3f23000 | 907 | u32 pintbit = PINT_BIT(pint_val); |
8d022374 | 908 | u32 bank = PINT_2_BANK(pint_val); |
34e0fc89 MH |
909 | |
910 | if (pint_val == IRQ_NOT_AVAIL) | |
911 | return -ENODEV; | |
912 | ||
913 | if (type == IRQ_TYPE_PROBE) { | |
914 | /* only probe unenabled GPIO interrupt lines */ | |
c3695341 | 915 | if (test_bit(gpionr, gpio_enabled)) |
34e0fc89 MH |
916 | return 0; |
917 | type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | |
918 | } | |
919 | ||
920 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | | |
921 | IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { | |
9570ff4a GY |
922 | |
923 | snprintf(buf, 16, "gpio-irq%d", irq); | |
924 | ret = bfin_gpio_irq_request(gpionr, buf); | |
925 | if (ret) | |
926 | return ret; | |
927 | ||
8d022374 | 928 | if (__test_and_set_bit(gpionr, gpio_enabled)) |
affee2b2 | 929 | bfin_gpio_irq_prepare(gpionr); |
34e0fc89 | 930 | |
34e0fc89 | 931 | } else { |
8d022374 | 932 | __clear_bit(gpionr, gpio_enabled); |
34e0fc89 MH |
933 | return 0; |
934 | } | |
935 | ||
34e0fc89 | 936 | if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) |
e3f23000 | 937 | pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */ |
34e0fc89 | 938 | else |
8baf560b | 939 | pint[bank]->invert_clear = pintbit; /* high or rising edge denoted by zero */ |
34e0fc89 | 940 | |
8baf560b MH |
941 | if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) |
942 | == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | |
8baf560b MH |
943 | if (gpio_get_value(gpionr)) |
944 | pint[bank]->invert_set = pintbit; | |
945 | else | |
946 | pint[bank]->invert_clear = pintbit; | |
8baf560b MH |
947 | } |
948 | ||
949 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | |
950 | pint[bank]->edge_set = pintbit; | |
bfd15117 | 951 | bfin_set_irq_handler(irq, handle_edge_irq); |
8baf560b MH |
952 | } else { |
953 | pint[bank]->edge_clear = pintbit; | |
bfd15117 | 954 | bfin_set_irq_handler(irq, handle_level_irq); |
8baf560b MH |
955 | } |
956 | ||
34e0fc89 MH |
957 | return 0; |
958 | } | |
959 | ||
cfefe3c6 MH |
960 | #ifdef CONFIG_PM |
961 | u32 pint_saved_masks[NR_PINT_SYS_IRQS]; | |
962 | u32 pint_wakeup_masks[NR_PINT_SYS_IRQS]; | |
963 | ||
964 | int bfin_gpio_set_wake(unsigned int irq, unsigned int state) | |
965 | { | |
966 | u32 pint_irq; | |
8d022374 | 967 | u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; |
cfefe3c6 MH |
968 | u32 bank = PINT_2_BANK(pint_val); |
969 | u32 pintbit = PINT_BIT(pint_val); | |
970 | ||
971 | switch (bank) { | |
972 | case 0: | |
973 | pint_irq = IRQ_PINT0; | |
974 | break; | |
975 | case 2: | |
976 | pint_irq = IRQ_PINT2; | |
977 | break; | |
978 | case 3: | |
979 | pint_irq = IRQ_PINT3; | |
980 | break; | |
981 | case 1: | |
982 | pint_irq = IRQ_PINT1; | |
983 | break; | |
984 | default: | |
985 | return -EINVAL; | |
986 | } | |
987 | ||
988 | bfin_internal_set_wake(pint_irq, state); | |
989 | ||
990 | if (state) | |
991 | pint_wakeup_masks[bank] |= pintbit; | |
992 | else | |
993 | pint_wakeup_masks[bank] &= ~pintbit; | |
994 | ||
995 | return 0; | |
996 | } | |
997 | ||
998 | u32 bfin_pm_setup(void) | |
999 | { | |
1000 | u32 val, i; | |
1001 | ||
1002 | for (i = 0; i < NR_PINT_SYS_IRQS; i++) { | |
1003 | val = pint[i]->mask_clear; | |
1004 | pint_saved_masks[i] = val; | |
1005 | if (val ^ pint_wakeup_masks[i]) { | |
1006 | pint[i]->mask_clear = val; | |
1007 | pint[i]->mask_set = pint_wakeup_masks[i]; | |
1008 | } | |
1009 | } | |
1010 | ||
1011 | return 0; | |
1012 | } | |
1013 | ||
1014 | void bfin_pm_restore(void) | |
1015 | { | |
1016 | u32 i, val; | |
1017 | ||
1018 | for (i = 0; i < NR_PINT_SYS_IRQS; i++) { | |
1019 | val = pint_saved_masks[i]; | |
1020 | if (val ^ pint_wakeup_masks[i]) { | |
1021 | pint[i]->mask_clear = pint[i]->mask_clear; | |
1022 | pint[i]->mask_set = val; | |
1023 | } | |
1024 | } | |
1025 | } | |
1026 | #endif | |
1027 | ||
2c4f829b MH |
1028 | static void bfin_demux_gpio_irq(unsigned int inta_irq, |
1029 | struct irq_desc *desc) | |
34e0fc89 | 1030 | { |
8d022374 | 1031 | u32 bank, pint_val; |
34e0fc89 MH |
1032 | u32 request, irq; |
1033 | ||
2c4f829b | 1034 | switch (inta_irq) { |
34e0fc89 MH |
1035 | case IRQ_PINT0: |
1036 | bank = 0; | |
1037 | break; | |
1038 | case IRQ_PINT2: | |
1039 | bank = 2; | |
1040 | break; | |
1041 | case IRQ_PINT3: | |
1042 | bank = 3; | |
1043 | break; | |
1044 | case IRQ_PINT1: | |
1045 | bank = 1; | |
1046 | break; | |
e3f23000 MH |
1047 | default: |
1048 | return; | |
34e0fc89 MH |
1049 | } |
1050 | ||
1051 | pint_val = bank * NR_PINT_BITS; | |
1052 | ||
1053 | request = pint[bank]->request; | |
1054 | ||
1055 | while (request) { | |
1056 | if (request & 1) { | |
e3f23000 | 1057 | irq = pint2irq_lut[pint_val] + SYS_IRQS; |
6a01f230 | 1058 | bfin_handle_irq(irq); |
34e0fc89 MH |
1059 | } |
1060 | pint_val++; | |
1061 | request >>= 1; | |
1062 | } | |
1063 | ||
1064 | } | |
a055b2b4 | 1065 | #endif |
1394f032 | 1066 | |
8d022374 MH |
1067 | static struct irq_chip bfin_gpio_irqchip = { |
1068 | .name = "GPIO", | |
1069 | .ack = bfin_gpio_ack_irq, | |
1070 | .mask = bfin_gpio_mask_irq, | |
1071 | .mask_ack = bfin_gpio_mask_ack_irq, | |
1072 | .unmask = bfin_gpio_unmask_irq, | |
1073 | .disable = bfin_gpio_mask_irq, | |
1074 | .enable = bfin_gpio_unmask_irq, | |
1075 | .set_type = bfin_gpio_irq_type, | |
1076 | .startup = bfin_gpio_irq_startup, | |
1077 | .shutdown = bfin_gpio_irq_shutdown, | |
1078 | #ifdef CONFIG_PM | |
1079 | .set_wake = bfin_gpio_set_wake, | |
1080 | #endif | |
1081 | }; | |
1082 | ||
6b3087c6 | 1083 | void __cpuinit init_exception_vectors(void) |
8be80ed3 | 1084 | { |
f0b5d12f MF |
1085 | /* cannot program in software: |
1086 | * evt0 - emulation (jtag) | |
1087 | * evt1 - reset | |
1088 | */ | |
1089 | bfin_write_EVT2(evt_nmi); | |
8be80ed3 BS |
1090 | bfin_write_EVT3(trap); |
1091 | bfin_write_EVT5(evt_ivhw); | |
1092 | bfin_write_EVT6(evt_timer); | |
1093 | bfin_write_EVT7(evt_evt7); | |
1094 | bfin_write_EVT8(evt_evt8); | |
1095 | bfin_write_EVT9(evt_evt9); | |
1096 | bfin_write_EVT10(evt_evt10); | |
1097 | bfin_write_EVT11(evt_evt11); | |
1098 | bfin_write_EVT12(evt_evt12); | |
1099 | bfin_write_EVT13(evt_evt13); | |
9703a73c | 1100 | bfin_write_EVT14(evt_evt14); |
8be80ed3 BS |
1101 | bfin_write_EVT15(evt_system_call); |
1102 | CSYNC(); | |
1103 | } | |
1104 | ||
1394f032 BW |
1105 | /* |
1106 | * This function should be called during kernel startup to initialize | |
1107 | * the BFin IRQ handling routines. | |
1108 | */ | |
8d022374 | 1109 | |
1394f032 BW |
1110 | int __init init_arch_irq(void) |
1111 | { | |
1112 | int irq; | |
1113 | unsigned long ilat = 0; | |
1114 | /* Disable all the peripheral intrs - page 4-29 HW Ref manual */ | |
2f6f4bcd BW |
1115 | #if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \ |
1116 | || defined(BF538_FAMILY) || defined(CONFIG_BF51x) | |
24a07a12 RH |
1117 | bfin_write_SIC_IMASK0(SIC_UNMASK_ALL); |
1118 | bfin_write_SIC_IMASK1(SIC_UNMASK_ALL); | |
a055b2b4 | 1119 | # ifdef CONFIG_BF54x |
59003145 | 1120 | bfin_write_SIC_IMASK2(SIC_UNMASK_ALL); |
a055b2b4 | 1121 | # endif |
6b3087c6 GY |
1122 | # ifdef CONFIG_SMP |
1123 | bfin_write_SICB_IMASK0(SIC_UNMASK_ALL); | |
1124 | bfin_write_SICB_IMASK1(SIC_UNMASK_ALL); | |
1125 | # endif | |
24a07a12 | 1126 | #else |
1394f032 | 1127 | bfin_write_SIC_IMASK(SIC_UNMASK_ALL); |
24a07a12 | 1128 | #endif |
1394f032 BW |
1129 | |
1130 | local_irq_disable(); | |
1131 | ||
d70536ec | 1132 | #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) |
95a86b5e MF |
1133 | /* Clear EMAC Interrupt Status bits so we can demux it later */ |
1134 | bfin_write_EMAC_SYSTAT(-1); | |
1135 | #endif | |
1136 | ||
a055b2b4 MF |
1137 | #ifdef CONFIG_BF54x |
1138 | # ifdef CONFIG_PINTx_REASSIGN | |
34e0fc89 MH |
1139 | pint[0]->assign = CONFIG_PINT0_ASSIGN; |
1140 | pint[1]->assign = CONFIG_PINT1_ASSIGN; | |
1141 | pint[2]->assign = CONFIG_PINT2_ASSIGN; | |
1142 | pint[3]->assign = CONFIG_PINT3_ASSIGN; | |
a055b2b4 | 1143 | # endif |
34e0fc89 MH |
1144 | /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */ |
1145 | init_pint_lut(); | |
1146 | #endif | |
1147 | ||
1148 | for (irq = 0; irq <= SYS_IRQS; irq++) { | |
1394f032 BW |
1149 | if (irq <= IRQ_CORETMR) |
1150 | set_irq_chip(irq, &bfin_core_irqchip); | |
1151 | else | |
1152 | set_irq_chip(irq, &bfin_internal_irqchip); | |
1394f032 | 1153 | |
464abc5d | 1154 | switch (irq) { |
59003145 | 1155 | #if defined(CONFIG_BF53x) |
464abc5d | 1156 | case IRQ_PROG_INTA: |
a055b2b4 | 1157 | # if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)) |
464abc5d | 1158 | case IRQ_MAC_RX: |
a055b2b4 | 1159 | # endif |
59003145 | 1160 | #elif defined(CONFIG_BF54x) |
464abc5d MH |
1161 | case IRQ_PINT0: |
1162 | case IRQ_PINT1: | |
1163 | case IRQ_PINT2: | |
1164 | case IRQ_PINT3: | |
2f6f4bcd | 1165 | #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) |
464abc5d MH |
1166 | case IRQ_PORTF_INTA: |
1167 | case IRQ_PORTG_INTA: | |
1168 | case IRQ_PORTH_INTA: | |
2c4f829b | 1169 | #elif defined(CONFIG_BF561) |
464abc5d MH |
1170 | case IRQ_PROG0_INTA: |
1171 | case IRQ_PROG1_INTA: | |
1172 | case IRQ_PROG2_INTA: | |
dc26aec2 MH |
1173 | #elif defined(CONFIG_BF538) || defined(CONFIG_BF539) |
1174 | case IRQ_PORTF_INTA: | |
1394f032 | 1175 | #endif |
464abc5d MH |
1176 | set_irq_chained_handler(irq, |
1177 | bfin_demux_gpio_irq); | |
1178 | break; | |
1394f032 | 1179 | #ifdef BF537_GENERIC_ERROR_INT_DEMUX |
464abc5d | 1180 | case IRQ_GENERIC_ERROR: |
6a01f230 | 1181 | set_irq_chained_handler(irq, bfin_demux_error_irq); |
464abc5d | 1182 | break; |
1394f032 | 1183 | #endif |
aec59c91 MH |
1184 | #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) |
1185 | case IRQ_MAC_ERROR: | |
1186 | set_irq_chained_handler(irq, bfin_demux_mac_status_irq); | |
1187 | break; | |
1188 | #endif | |
6b3087c6 GY |
1189 | #ifdef CONFIG_SMP |
1190 | case IRQ_SUPPLE_0: | |
1191 | case IRQ_SUPPLE_1: | |
1192 | set_irq_handler(irq, handle_percpu_irq); | |
1193 | break; | |
1194 | #endif | |
17941314 | 1195 | |
cb191718 YL |
1196 | #ifdef CONFIG_TICKSOURCE_CORETMR |
1197 | case IRQ_CORETMR: | |
1198 | # ifdef CONFIG_SMP | |
1199 | set_irq_handler(irq, handle_percpu_irq); | |
1200 | break; | |
1201 | # else | |
a40494a6 PG |
1202 | set_irq_handler(irq, handle_simple_irq); |
1203 | break; | |
cb191718 | 1204 | # endif |
17941314 | 1205 | #endif |
cb191718 YL |
1206 | |
1207 | #ifdef CONFIG_TICKSOURCE_GPTMR0 | |
1208 | case IRQ_TIMER0: | |
a40494a6 PG |
1209 | set_irq_handler(irq, handle_simple_irq); |
1210 | break; | |
cb191718 YL |
1211 | #endif |
1212 | ||
1213 | #ifdef CONFIG_IPIPE | |
a40494a6 PG |
1214 | default: |
1215 | set_irq_handler(irq, handle_level_irq); | |
1216 | break; | |
6a01f230 | 1217 | #else /* !CONFIG_IPIPE */ |
a40494a6 | 1218 | default: |
464abc5d MH |
1219 | set_irq_handler(irq, handle_simple_irq); |
1220 | break; | |
17941314 | 1221 | #endif /* !CONFIG_IPIPE */ |
464abc5d | 1222 | } |
1394f032 | 1223 | } |
464abc5d | 1224 | |
1394f032 | 1225 | #ifdef BF537_GENERIC_ERROR_INT_DEMUX |
464abc5d MH |
1226 | for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++) |
1227 | set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip, | |
1228 | handle_level_irq); | |
aec59c91 MH |
1229 | #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) |
1230 | set_irq_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq); | |
1231 | #endif | |
1394f032 BW |
1232 | #endif |
1233 | ||
aec59c91 MH |
1234 | #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) |
1235 | for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++) | |
1236 | set_irq_chip_and_handler(irq, &bfin_mac_status_irqchip, | |
1237 | handle_level_irq); | |
1238 | #endif | |
464abc5d | 1239 | /* if configured as edge, then will be changed to do_edge_IRQ */ |
aec59c91 MH |
1240 | for (irq = GPIO_IRQ_BASE; |
1241 | irq < (GPIO_IRQ_BASE + MAX_BLACKFIN_GPIOS); irq++) | |
464abc5d MH |
1242 | set_irq_chip_and_handler(irq, &bfin_gpio_irqchip, |
1243 | handle_level_irq); | |
2c4f829b | 1244 | |
1394f032 BW |
1245 | bfin_write_IMASK(0); |
1246 | CSYNC(); | |
1247 | ilat = bfin_read_ILAT(); | |
1248 | CSYNC(); | |
1249 | bfin_write_ILAT(ilat); | |
1250 | CSYNC(); | |
1251 | ||
34e0fc89 | 1252 | printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n"); |
40059784 | 1253 | /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx, |
1394f032 BW |
1254 | * local_irq_enable() |
1255 | */ | |
1256 | program_IAR(); | |
1257 | /* Therefore it's better to setup IARs before interrupts enabled */ | |
1258 | search_IAR(); | |
1259 | ||
1260 | /* Enable interrupts IVG7-15 */ | |
40059784 | 1261 | bfin_irq_flags |= IMASK_IVG15 | |
1394f032 | 1262 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | |
34e0fc89 | 1263 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; |
1394f032 | 1264 | |
349ebbcc MH |
1265 | /* This implicitly covers ANOMALY_05000171 |
1266 | * Boot-ROM code modifies SICA_IWRx wakeup registers | |
1267 | */ | |
be1d8543 | 1268 | #ifdef SIC_IWR0 |
56f5f590 | 1269 | bfin_write_SIC_IWR0(IWR_DISABLE_ALL); |
be1d8543 | 1270 | # ifdef SIC_IWR1 |
2f6f4bcd | 1271 | /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which |
55546ac4 MH |
1272 | * will screw up the bootrom as it relies on MDMA0/1 waking it |
1273 | * up from IDLE instructions. See this report for more info: | |
1274 | * http://blackfin.uclinux.org/gf/tracker/4323 | |
1275 | */ | |
b7e11293 MF |
1276 | if (ANOMALY_05000435) |
1277 | bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11)); | |
1278 | else | |
1279 | bfin_write_SIC_IWR1(IWR_DISABLE_ALL); | |
be1d8543 MF |
1280 | # endif |
1281 | # ifdef SIC_IWR2 | |
56f5f590 | 1282 | bfin_write_SIC_IWR2(IWR_DISABLE_ALL); |
fe9ec9b9 MH |
1283 | # endif |
1284 | #else | |
56f5f590 | 1285 | bfin_write_SIC_IWR(IWR_DISABLE_ALL); |
fe9ec9b9 MH |
1286 | #endif |
1287 | ||
1394f032 BW |
1288 | return 0; |
1289 | } | |
1290 | ||
1291 | #ifdef CONFIG_DO_IRQ_L1 | |
a055b2b4 | 1292 | __attribute__((l1_text)) |
1394f032 | 1293 | #endif |
1394f032 BW |
1294 | void do_irq(int vec, struct pt_regs *fp) |
1295 | { | |
1296 | if (vec == EVT_IVTMR_P) { | |
1297 | vec = IRQ_CORETMR; | |
1298 | } else { | |
1299 | struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst; | |
1300 | struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop; | |
780172bf | 1301 | #if defined(SIC_ISR0) || defined(SICA_ISR0) |
24a07a12 | 1302 | unsigned long sic_status[3]; |
1394f032 | 1303 | |
6b3087c6 | 1304 | if (smp_processor_id()) { |
780172bf | 1305 | # ifdef SICB_ISR0 |
6b3087c6 GY |
1306 | /* This will be optimized out in UP mode. */ |
1307 | sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0(); | |
1308 | sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1(); | |
780172bf | 1309 | # endif |
6b3087c6 GY |
1310 | } else { |
1311 | sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); | |
1312 | sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); | |
1313 | } | |
780172bf | 1314 | # ifdef SIC_ISR2 |
4fb45241 | 1315 | sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); |
780172bf | 1316 | # endif |
1f83b8f1 | 1317 | for (;; ivg++) { |
24a07a12 RH |
1318 | if (ivg >= ivg_stop) { |
1319 | atomic_inc(&num_spurious); | |
1320 | return; | |
1321 | } | |
34e0fc89 | 1322 | if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag) |
24a07a12 RH |
1323 | break; |
1324 | } | |
1325 | #else | |
1326 | unsigned long sic_status; | |
464abc5d | 1327 | |
1394f032 BW |
1328 | sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR(); |
1329 | ||
1330 | for (;; ivg++) { | |
1331 | if (ivg >= ivg_stop) { | |
1332 | atomic_inc(&num_spurious); | |
1333 | return; | |
1334 | } else if (sic_status & ivg->isrflag) | |
1335 | break; | |
1336 | } | |
24a07a12 | 1337 | #endif |
1394f032 BW |
1338 | vec = ivg->irqno; |
1339 | } | |
1340 | asm_do_IRQ(vec, fp); | |
1394f032 | 1341 | } |
6a01f230 YL |
1342 | |
1343 | #ifdef CONFIG_IPIPE | |
1344 | ||
1345 | int __ipipe_get_irq_priority(unsigned irq) | |
1346 | { | |
1347 | int ient, prio; | |
1348 | ||
1349 | if (irq <= IRQ_CORETMR) | |
1350 | return irq; | |
1351 | ||
1352 | for (ient = 0; ient < NR_PERI_INTS; ient++) { | |
1353 | struct ivgx *ivg = ivg_table + ient; | |
1354 | if (ivg->irqno == irq) { | |
1355 | for (prio = 0; prio <= IVG13-IVG7; prio++) { | |
1356 | if (ivg7_13[prio].ifirst <= ivg && | |
1357 | ivg7_13[prio].istop > ivg) | |
1358 | return IVG7 + prio; | |
1359 | } | |
1360 | } | |
1361 | } | |
1362 | ||
1363 | return IVG15; | |
1364 | } | |
1365 | ||
6a01f230 YL |
1366 | /* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */ |
1367 | #ifdef CONFIG_DO_IRQ_L1 | |
1368 | __attribute__((l1_text)) | |
1369 | #endif | |
1370 | asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs) | |
1371 | { | |
9bd50df6 | 1372 | struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr(); |
a40494a6 | 1373 | struct ipipe_domain *this_domain = __ipipe_current_domain; |
6a01f230 YL |
1374 | struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop; |
1375 | struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst; | |
9bd50df6 | 1376 | int irq, s; |
6a01f230 | 1377 | |
a40494a6 | 1378 | if (likely(vec == EVT_IVTMR_P)) |
6a01f230 | 1379 | irq = IRQ_CORETMR; |
a40494a6 | 1380 | else { |
780172bf | 1381 | #if defined(SIC_ISR0) || defined(SICA_ISR0) |
6a01f230 YL |
1382 | unsigned long sic_status[3]; |
1383 | ||
1384 | sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); | |
1385 | sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); | |
780172bf | 1386 | # ifdef SIC_ISR2 |
6a01f230 | 1387 | sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); |
780172bf | 1388 | # endif |
6a01f230 YL |
1389 | for (;; ivg++) { |
1390 | if (ivg >= ivg_stop) { | |
1391 | atomic_inc(&num_spurious); | |
1392 | return 0; | |
1393 | } | |
1394 | if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag) | |
1395 | break; | |
1396 | } | |
6a01f230 | 1397 | #else |
6a01f230 YL |
1398 | unsigned long sic_status; |
1399 | ||
1400 | sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR(); | |
1401 | ||
1402 | for (;; ivg++) { | |
1403 | if (ivg >= ivg_stop) { | |
1404 | atomic_inc(&num_spurious); | |
1405 | return 0; | |
1406 | } else if (sic_status & ivg->isrflag) | |
1407 | break; | |
1408 | } | |
6a01f230 | 1409 | #endif |
1fa9be72 GY |
1410 | irq = ivg->irqno; |
1411 | } | |
6a01f230 YL |
1412 | |
1413 | if (irq == IRQ_SYSTMR) { | |
a40494a6 | 1414 | #if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0) |
6a01f230 | 1415 | bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */ |
9bd50df6 | 1416 | #endif |
6a01f230 YL |
1417 | /* This is basically what we need from the register frame. */ |
1418 | __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend; | |
1419 | __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc; | |
9bd50df6 | 1420 | if (this_domain != ipipe_root_domain) |
6a01f230 | 1421 | __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10; |
9bd50df6 PG |
1422 | else |
1423 | __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10; | |
6a01f230 YL |
1424 | } |
1425 | ||
9bd50df6 PG |
1426 | if (this_domain == ipipe_root_domain) { |
1427 | s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status); | |
1428 | barrier(); | |
1429 | } | |
6a01f230 YL |
1430 | |
1431 | ipipe_trace_irq_entry(irq); | |
1432 | __ipipe_handle_irq(irq, regs); | |
9bd50df6 | 1433 | ipipe_trace_irq_exit(irq); |
6a01f230 | 1434 | |
9bd50df6 PG |
1435 | if (this_domain == ipipe_root_domain) { |
1436 | set_thread_flag(TIF_IRQ_SYNC); | |
1437 | if (!s) { | |
1438 | __clear_bit(IPIPE_SYNCDEFER_FLAG, &p->status); | |
1439 | return !test_bit(IPIPE_STALL_FLAG, &p->status); | |
1440 | } | |
1441 | } | |
6a01f230 | 1442 | |
1fa9be72 | 1443 | return 0; |
6a01f230 YL |
1444 | } |
1445 | ||
1446 | #endif /* CONFIG_IPIPE */ |