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