blob: 5202a607669514194b60cf61031522816ea81695 [file] [log] [blame]
Bryan Wu1394f032007-05-06 14:50:22 -07001/*
Robin Getz96f10502009-09-24 14:11:24 +00002 * Set up the interrupt priorities
Bryan Wu1394f032007-05-06 14:50:22 -07003 *
Robin Getz96f10502009-09-24 14:11:24 +00004 * 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
Bryan Wu1394f032007-05-06 14:50:22 -070010 *
Robin Getz96f10502009-09-24 14:11:24 +000011 * Licensed under the GPL-2
Bryan Wu1394f032007-05-06 14:50:22 -070012 */
13
14#include <linux/module.h>
15#include <linux/kernel_stat.h>
16#include <linux/seq_file.h>
17#include <linux/irq.h>
Yi Li6a01f232009-01-07 23:14:39 +080018#ifdef CONFIG_IPIPE
19#include <linux/ipipe.h>
20#endif
Bryan Wu1394f032007-05-06 14:50:22 -070021#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>
Mike Frysinger761ec442009-10-15 17:12:05 +000028#include <asm/dpmc.h>
Mike Frysinger7eb87fd2009-11-03 09:29:50 +000029#include <asm/bfin5xx_spi.h>
30#include <asm/bfin_sport.h>
Michael Hennerich15435a22009-12-16 08:39:58 +000031#include <asm/bfin_can.h>
Bryan Wu1394f032007-05-06 14:50:22 -070032
Mike Frysinger7beb7432008-11-18 17:48:22 +080033#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
34
Bryan Wu1394f032007-05-06 14:50:22 -070035#ifdef BF537_FAMILY
36# define BF537_GENERIC_ERROR_INT_DEMUX
Mike Frysinger7eb87fd2009-11-03 09:29:50 +000037# 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 */
Bryan Wu1394f032007-05-06 14:50:22 -070043#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
Graf Yang6b3087c2009-01-07 23:14:39 +080054#ifndef CONFIG_SMP
Mike Frysingera99bbcc2007-10-22 00:19:31 +080055/* 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 */
Mike Frysinger40059782008-11-18 17:48:22 +080061unsigned long bfin_irq_flags = 0x1f;
62EXPORT_SYMBOL(bfin_irq_flags);
Graf Yang6b3087c2009-01-07 23:14:39 +080063#endif
Bryan Wu1394f032007-05-06 14:50:22 -070064
65/* The number of spurious interrupts */
66atomic_t num_spurious;
67
Michael Hennerichcfefe3c2008-02-09 04:12:37 +080068#ifdef CONFIG_PM
69unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */
Michael Hennerich4a88d0c2008-08-05 17:38:41 +080070unsigned vr_wakeup;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +080071#endif
72
Bryan Wu1394f032007-05-06 14:50:22 -070073struct ivgx {
Michael Hennerich464abc52008-02-25 13:50:20 +080074 /* irq number for request_irq, available in mach-bf5xx/irq.h */
Roy Huang24a07a12007-07-12 22:41:45 +080075 unsigned int irqno;
Bryan Wu1394f032007-05-06 14:50:22 -070076 /* corresponding bit in the SIC_ISR register */
Roy Huang24a07a12007-07-12 22:41:45 +080077 unsigned int isrflag;
Bryan Wu1394f032007-05-06 14:50:22 -070078} ivg_table[NR_PERI_INTS];
79
80struct 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
Bryan Wu1394f032007-05-06 14:50:22 -070086
87/*
88 * Search SIC_IAR and fill tables with the irqvalues
89 * and their positions in the SIC_ISR register.
90 */
91static void __init search_IAR(void)
92{
93 unsigned ivg, irq_pos = 0;
94 for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
95 int irqn;
96
Michael Hennerich34e0fc82007-07-12 16:17:18 +080097 ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
Bryan Wu1394f032007-05-06 14:50:22 -070098
99 for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
100 int iar_shift = (irqn & 7) * 4;
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800101 if (ivg == (0xf &
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800102#if defined(CONFIG_BF52x) || defined(CONFIG_BF538) \
103 || defined(CONFIG_BF539) || defined(CONFIG_BF51x)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800104 bfin_read32((unsigned long *)SIC_IAR0 +
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800105 ((irqn % 32) >> 3) + ((irqn / 32) *
106 ((SIC_IAR4 - SIC_IAR0) / 4))) >> iar_shift)) {
Michael Hennerich59003142007-10-21 16:54:27 +0800107#else
108 bfin_read32((unsigned long *)SIC_IAR0 +
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800109 (irqn >> 3)) >> iar_shift)) {
Michael Hennerich59003142007-10-21 16:54:27 +0800110#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700111 ivg_table[irq_pos].irqno = IVG7 + irqn;
Roy Huang24a07a12007-07-12 22:41:45 +0800112 ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
Bryan Wu1394f032007-05-06 14:50:22 -0700113 ivg7_13[ivg].istop++;
114 irq_pos++;
115 }
116 }
117 }
118}
119
120/*
Michael Hennerich464abc52008-02-25 13:50:20 +0800121 * This is for core internal IRQs
Bryan Wu1394f032007-05-06 14:50:22 -0700122 */
123
Michael Hennerich464abc52008-02-25 13:50:20 +0800124static void bfin_ack_noop(unsigned int irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700125{
126 /* Dummy function. */
127}
128
129static void bfin_core_mask_irq(unsigned int irq)
130{
Mike Frysinger40059782008-11-18 17:48:22 +0800131 bfin_irq_flags &= ~(1 << irq);
Yi Li6a01f232009-01-07 23:14:39 +0800132 if (!irqs_disabled_hw())
133 local_irq_enable_hw();
Bryan Wu1394f032007-05-06 14:50:22 -0700134}
135
136static void bfin_core_unmask_irq(unsigned int irq)
137{
Mike Frysinger40059782008-11-18 17:48:22 +0800138 bfin_irq_flags |= 1 << irq;
Bryan Wu1394f032007-05-06 14:50:22 -0700139 /*
140 * If interrupts are enabled, IMASK must contain the same value
Mike Frysinger40059782008-11-18 17:48:22 +0800141 * as bfin_irq_flags. Make sure that invariant holds. If interrupts
Bryan Wu1394f032007-05-06 14:50:22 -0700142 * are currently disabled we need not do anything; one of the
143 * callers will take care of setting IMASK to the proper value
144 * when reenabling interrupts.
Mike Frysinger40059782008-11-18 17:48:22 +0800145 * local_irq_enable just does "STI bfin_irq_flags", so it's exactly
Bryan Wu1394f032007-05-06 14:50:22 -0700146 * what we need.
147 */
Yi Li6a01f232009-01-07 23:14:39 +0800148 if (!irqs_disabled_hw())
149 local_irq_enable_hw();
Bryan Wu1394f032007-05-06 14:50:22 -0700150 return;
151}
152
153static void bfin_internal_mask_irq(unsigned int irq)
154{
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800155 unsigned long flags;
156
Michael Hennerich59003142007-10-21 16:54:27 +0800157#ifdef CONFIG_BF53x
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800158 local_irq_save_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700159 bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
Michael Hennerich464abc52008-02-25 13:50:20 +0800160 ~(1 << SIC_SYSIRQ(irq)));
Roy Huang24a07a12007-07-12 22:41:45 +0800161#else
162 unsigned mask_bank, mask_bit;
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800163 local_irq_save_hw(flags);
Michael Hennerich464abc52008-02-25 13:50:20 +0800164 mask_bank = SIC_SYSIRQ(irq) / 32;
165 mask_bit = SIC_SYSIRQ(irq) % 32;
Bryan Wuc04d66b2007-07-12 17:26:31 +0800166 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
167 ~(1 << mask_bit));
Graf Yang6b3087c2009-01-07 23:14:39 +0800168#ifdef CONFIG_SMP
169 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
170 ~(1 << mask_bit));
171#endif
Roy Huang24a07a12007-07-12 22:41:45 +0800172#endif
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800173 local_irq_restore_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700174}
175
176static void bfin_internal_unmask_irq(unsigned int irq)
177{
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800178 unsigned long flags;
179
Michael Hennerich59003142007-10-21 16:54:27 +0800180#ifdef CONFIG_BF53x
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800181 local_irq_save_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700182 bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
Michael Hennerich464abc52008-02-25 13:50:20 +0800183 (1 << SIC_SYSIRQ(irq)));
Roy Huang24a07a12007-07-12 22:41:45 +0800184#else
185 unsigned mask_bank, mask_bit;
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800186 local_irq_save_hw(flags);
Michael Hennerich464abc52008-02-25 13:50:20 +0800187 mask_bank = SIC_SYSIRQ(irq) / 32;
188 mask_bit = SIC_SYSIRQ(irq) % 32;
Bryan Wuc04d66b2007-07-12 17:26:31 +0800189 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
190 (1 << mask_bit));
Graf Yang6b3087c2009-01-07 23:14:39 +0800191#ifdef CONFIG_SMP
192 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) |
193 (1 << mask_bit));
194#endif
Roy Huang24a07a12007-07-12 22:41:45 +0800195#endif
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800196 local_irq_restore_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700197}
198
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800199#ifdef CONFIG_PM
200int bfin_internal_set_wake(unsigned int irq, unsigned int state)
201{
Michael Hennerich8d022372008-11-18 17:48:22 +0800202 u32 bank, bit, wakeup = 0;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800203 unsigned long flags;
Michael Hennerich464abc52008-02-25 13:50:20 +0800204 bank = SIC_SYSIRQ(irq) / 32;
205 bit = SIC_SYSIRQ(irq) % 32;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800206
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800207 switch (irq) {
208#ifdef IRQ_RTC
209 case IRQ_RTC:
210 wakeup |= WAKE;
211 break;
212#endif
213#ifdef IRQ_CAN0_RX
214 case IRQ_CAN0_RX:
215 wakeup |= CANWE;
216 break;
217#endif
218#ifdef IRQ_CAN1_RX
219 case IRQ_CAN1_RX:
220 wakeup |= CANWE;
221 break;
222#endif
223#ifdef IRQ_USB_INT0
224 case IRQ_USB_INT0:
225 wakeup |= USBWE;
226 break;
227#endif
228#ifdef IRQ_KEY
229 case IRQ_KEY:
230 wakeup |= KPADWE;
231 break;
232#endif
Michael Hennerichd310fb42008-08-28 17:32:01 +0800233#ifdef CONFIG_BF54x
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800234 case IRQ_CNT:
235 wakeup |= ROTWE;
236 break;
237#endif
238 default:
239 break;
240 }
241
Yi Li6a01f232009-01-07 23:14:39 +0800242 local_irq_save_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800243
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800244 if (state) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800245 bfin_sic_iwr[bank] |= (1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800246 vr_wakeup |= wakeup;
247
248 } else {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800249 bfin_sic_iwr[bank] &= ~(1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800250 vr_wakeup &= ~wakeup;
251 }
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800252
Yi Li6a01f232009-01-07 23:14:39 +0800253 local_irq_restore_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800254
255 return 0;
256}
257#endif
258
Bryan Wu1394f032007-05-06 14:50:22 -0700259static struct irq_chip bfin_core_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800260 .name = "CORE",
Michael Hennerich464abc52008-02-25 13:50:20 +0800261 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700262 .mask = bfin_core_mask_irq,
263 .unmask = bfin_core_unmask_irq,
264};
265
266static struct irq_chip bfin_internal_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800267 .name = "INTN",
Michael Hennerich464abc52008-02-25 13:50:20 +0800268 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700269 .mask = bfin_internal_mask_irq,
270 .unmask = bfin_internal_unmask_irq,
Michael Hennerichce3b7bb2008-02-25 13:48:47 +0800271 .mask_ack = bfin_internal_mask_irq,
272 .disable = bfin_internal_mask_irq,
273 .enable = bfin_internal_unmask_irq,
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800274#ifdef CONFIG_PM
275 .set_wake = bfin_internal_set_wake,
276#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700277};
278
Yi Li6a01f232009-01-07 23:14:39 +0800279static void bfin_handle_irq(unsigned irq)
280{
281#ifdef CONFIG_IPIPE
282 struct pt_regs regs; /* Contents not used. */
283 ipipe_trace_irq_entry(irq);
284 __ipipe_handle_irq(irq, &regs);
285 ipipe_trace_irq_exit(irq);
286#else /* !CONFIG_IPIPE */
287 struct irq_desc *desc = irq_desc + irq;
288 desc->handle_irq(irq, desc);
289#endif /* !CONFIG_IPIPE */
290}
291
Bryan Wu1394f032007-05-06 14:50:22 -0700292#ifdef BF537_GENERIC_ERROR_INT_DEMUX
293static int error_int_mask;
294
Bryan Wu1394f032007-05-06 14:50:22 -0700295static void bfin_generic_error_mask_irq(unsigned int irq)
296{
297 error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
298
Michael Hennerich464abc52008-02-25 13:50:20 +0800299 if (!error_int_mask)
300 bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700301}
302
303static void bfin_generic_error_unmask_irq(unsigned int irq)
304{
Michael Hennerich464abc52008-02-25 13:50:20 +0800305 bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700306 error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
307}
308
309static struct irq_chip bfin_generic_error_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800310 .name = "ERROR",
Michael Hennerich464abc52008-02-25 13:50:20 +0800311 .ack = bfin_ack_noop,
312 .mask_ack = bfin_generic_error_mask_irq,
Bryan Wu1394f032007-05-06 14:50:22 -0700313 .mask = bfin_generic_error_mask_irq,
314 .unmask = bfin_generic_error_unmask_irq,
315};
316
317static void bfin_demux_error_irq(unsigned int int_err_irq,
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800318 struct irq_desc *inta_desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700319{
320 int irq = 0;
321
Bryan Wu1394f032007-05-06 14:50:22 -0700322#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
323 if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
324 irq = IRQ_MAC_ERROR;
325 else
326#endif
327 if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
328 irq = IRQ_SPORT0_ERROR;
329 else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
330 irq = IRQ_SPORT1_ERROR;
331 else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
332 irq = IRQ_PPI_ERROR;
333 else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
334 irq = IRQ_CAN_ERROR;
335 else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
336 irq = IRQ_SPI_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000337 else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700338 irq = IRQ_UART0_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000339 else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700340 irq = IRQ_UART1_ERROR;
341
342 if (irq) {
Yi Li6a01f232009-01-07 23:14:39 +0800343 if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
344 bfin_handle_irq(irq);
345 else {
Bryan Wu1394f032007-05-06 14:50:22 -0700346
347 switch (irq) {
348 case IRQ_PPI_ERROR:
349 bfin_write_PPI_STATUS(PPI_ERR_MASK);
350 break;
351#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
352 case IRQ_MAC_ERROR:
353 bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
354 break;
355#endif
356 case IRQ_SPORT0_ERROR:
357 bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
358 break;
359
360 case IRQ_SPORT1_ERROR:
361 bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
362 break;
363
364 case IRQ_CAN_ERROR:
365 bfin_write_CAN_GIS(CAN_ERR_MASK);
366 break;
367
368 case IRQ_SPI_ERROR:
369 bfin_write_SPI_STAT(SPI_ERR_MASK);
370 break;
371
372 default:
373 break;
374 }
375
376 pr_debug("IRQ %d:"
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800377 " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
378 irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700379 }
380 } else
381 printk(KERN_ERR
382 "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
383 " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
Harvey Harrisonb85d8582008-04-23 09:39:01 +0800384 __func__, __FILE__, __LINE__);
Bryan Wu1394f032007-05-06 14:50:22 -0700385
Bryan Wu1394f032007-05-06 14:50:22 -0700386}
387#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
388
Graf Yangbfd15112008-10-08 18:02:44 +0800389static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
390{
Yi Li6a01f232009-01-07 23:14:39 +0800391#ifdef CONFIG_IPIPE
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800392 _set_irq_handler(irq, handle_level_irq);
Yi Li6a01f232009-01-07 23:14:39 +0800393#else
Graf Yangbfd15112008-10-08 18:02:44 +0800394 struct irq_desc *desc = irq_desc + irq;
395 /* May not call generic set_irq_handler() due to spinlock
396 recursion. */
397 desc->handle_irq = handle;
Yi Li6a01f232009-01-07 23:14:39 +0800398#endif
Graf Yangbfd15112008-10-08 18:02:44 +0800399}
400
Michael Hennerich8d022372008-11-18 17:48:22 +0800401static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800402extern void bfin_gpio_irq_prepare(unsigned gpio);
Michael Hennerich6fce6a82007-12-24 16:56:12 +0800403
Michael Hennerich8d022372008-11-18 17:48:22 +0800404#if !defined(CONFIG_BF54x)
405
Bryan Wu1394f032007-05-06 14:50:22 -0700406static void bfin_gpio_ack_irq(unsigned int irq)
407{
Michael Hennerich8d022372008-11-18 17:48:22 +0800408 /* AFAIK ack_irq in case mask_ack is provided
409 * get's only called for edge sense irqs
410 */
411 set_gpio_data(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700412}
413
414static void bfin_gpio_mask_ack_irq(unsigned int irq)
415{
Michael Hennerich8d022372008-11-18 17:48:22 +0800416 struct irq_desc *desc = irq_desc + irq;
417 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700418
Michael Hennerich8d022372008-11-18 17:48:22 +0800419 if (desc->handle_irq == handle_edge_irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700420 set_gpio_data(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700421
422 set_gpio_maska(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700423}
424
425static void bfin_gpio_mask_irq(unsigned int irq)
426{
Michael Hennerich8d022372008-11-18 17:48:22 +0800427 set_gpio_maska(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700428}
429
430static void bfin_gpio_unmask_irq(unsigned int irq)
431{
Michael Hennerich8d022372008-11-18 17:48:22 +0800432 set_gpio_maska(irq_to_gpio(irq), 1);
Bryan Wu1394f032007-05-06 14:50:22 -0700433}
434
435static unsigned int bfin_gpio_irq_startup(unsigned int irq)
436{
Michael Hennerich8d022372008-11-18 17:48:22 +0800437 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700438
Michael Hennerich8d022372008-11-18 17:48:22 +0800439 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800440 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700441
Bryan Wu1394f032007-05-06 14:50:22 -0700442 bfin_gpio_unmask_irq(irq);
443
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800444 return 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700445}
446
447static void bfin_gpio_irq_shutdown(unsigned int irq)
448{
Graf Yang30af6d42008-11-18 17:48:21 +0800449 u32 gpionr = irq_to_gpio(irq);
450
Bryan Wu1394f032007-05-06 14:50:22 -0700451 bfin_gpio_mask_irq(irq);
Graf Yang30af6d42008-11-18 17:48:21 +0800452 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800453 bfin_gpio_irq_free(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700454}
455
456static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
457{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800458 int ret;
459 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800460 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700461
462 if (type == IRQ_TYPE_PROBE) {
463 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400464 if (test_bit(gpionr, gpio_enabled))
Bryan Wu1394f032007-05-06 14:50:22 -0700465 return 0;
466 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
467 }
468
469 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800470 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Michael Hennerich8d022372008-11-18 17:48:22 +0800471
Graf Yang9570ff42009-01-07 23:14:38 +0800472 snprintf(buf, 16, "gpio-irq%d", irq);
473 ret = bfin_gpio_irq_request(gpionr, buf);
474 if (ret)
475 return ret;
476
Michael Hennerich8d022372008-11-18 17:48:22 +0800477 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800478 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700479
Bryan Wu1394f032007-05-06 14:50:22 -0700480 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800481 __clear_bit(gpionr, gpio_enabled);
Bryan Wu1394f032007-05-06 14:50:22 -0700482 return 0;
483 }
484
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800485 set_gpio_inen(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700486 set_gpio_dir(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700487
488 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
489 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
490 set_gpio_both(gpionr, 1);
491 else
492 set_gpio_both(gpionr, 0);
493
494 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
495 set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
496 else
497 set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
498
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800499 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
500 set_gpio_edge(gpionr, 1);
501 set_gpio_inen(gpionr, 1);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800502 set_gpio_data(gpionr, 0);
503
504 } else {
505 set_gpio_edge(gpionr, 0);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800506 set_gpio_inen(gpionr, 1);
507 }
508
Bryan Wu1394f032007-05-06 14:50:22 -0700509 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
Graf Yangbfd15112008-10-08 18:02:44 +0800510 bfin_set_irq_handler(irq, handle_edge_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700511 else
Graf Yangbfd15112008-10-08 18:02:44 +0800512 bfin_set_irq_handler(irq, handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700513
514 return 0;
515}
516
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800517#ifdef CONFIG_PM
518int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
519{
520 unsigned gpio = irq_to_gpio(irq);
521
522 if (state)
523 gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE);
524 else
525 gpio_pm_wakeup_free(gpio);
526
527 return 0;
528}
529#endif
530
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800531static void bfin_demux_gpio_irq(unsigned int inta_irq,
532 struct irq_desc *desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700533{
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800534 unsigned int i, gpio, mask, irq, search = 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700535
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800536 switch (inta_irq) {
537#if defined(CONFIG_BF53x)
538 case IRQ_PROG_INTA:
539 irq = IRQ_PF0;
540 search = 1;
541 break;
542# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
543 case IRQ_MAC_RX:
544 irq = IRQ_PH0;
545 break;
546# endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800547#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
548 case IRQ_PORTF_INTA:
549 irq = IRQ_PF0;
550 break;
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800551#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800552 case IRQ_PORTF_INTA:
553 irq = IRQ_PF0;
554 break;
555 case IRQ_PORTG_INTA:
556 irq = IRQ_PG0;
557 break;
558 case IRQ_PORTH_INTA:
559 irq = IRQ_PH0;
560 break;
561#elif defined(CONFIG_BF561)
562 case IRQ_PROG0_INTA:
563 irq = IRQ_PF0;
564 break;
565 case IRQ_PROG1_INTA:
566 irq = IRQ_PF16;
567 break;
568 case IRQ_PROG2_INTA:
569 irq = IRQ_PF32;
570 break;
571#endif
572 default:
573 BUG();
574 return;
Bryan Wu1394f032007-05-06 14:50:22 -0700575 }
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800576
577 if (search) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800578 for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800579 irq += i;
580
Michael Hennerich8d022372008-11-18 17:48:22 +0800581 mask = get_gpiop_data(i) & get_gpiop_maska(i);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800582
583 while (mask) {
Yi Li6a01f232009-01-07 23:14:39 +0800584 if (mask & 1)
585 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800586 irq++;
587 mask >>= 1;
588 }
589 }
590 } else {
591 gpio = irq_to_gpio(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800592 mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800593
594 do {
Yi Li6a01f232009-01-07 23:14:39 +0800595 if (mask & 1)
596 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800597 irq++;
598 mask >>= 1;
599 } while (mask);
600 }
601
Bryan Wu1394f032007-05-06 14:50:22 -0700602}
603
Mike Frysingera055b2b2007-11-15 21:12:32 +0800604#else /* CONFIG_BF54x */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800605
606#define NR_PINT_SYS_IRQS 4
607#define NR_PINT_BITS 32
608#define NR_PINTS 160
609#define IRQ_NOT_AVAIL 0xFF
610
611#define PINT_2_BANK(x) ((x) >> 5)
612#define PINT_2_BIT(x) ((x) & 0x1F)
613#define PINT_BIT(x) (1 << (PINT_2_BIT(x)))
614
615static unsigned char irq2pint_lut[NR_PINTS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800616static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800617
618struct pin_int_t {
619 unsigned int mask_set;
620 unsigned int mask_clear;
621 unsigned int request;
622 unsigned int assign;
623 unsigned int edge_set;
624 unsigned int edge_clear;
625 unsigned int invert_set;
626 unsigned int invert_clear;
627 unsigned int pinstate;
628 unsigned int latch;
629};
630
631static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
632 (struct pin_int_t *)PINT0_MASK_SET,
633 (struct pin_int_t *)PINT1_MASK_SET,
634 (struct pin_int_t *)PINT2_MASK_SET,
635 (struct pin_int_t *)PINT3_MASK_SET,
636};
637
Michael Hennerich8d022372008-11-18 17:48:22 +0800638inline unsigned int get_irq_base(u32 bank, u8 bmap)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800639{
Michael Hennerich8d022372008-11-18 17:48:22 +0800640 unsigned int irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800641
642 if (bank < 2) { /*PA-PB */
643 irq_base = IRQ_PA0 + bmap * 16;
644 } else { /*PC-PJ */
645 irq_base = IRQ_PC0 + bmap * 16;
646 }
647
648 return irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800649}
650
651 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
652void init_pint_lut(void)
653{
654 u16 bank, bit, irq_base, bit_pos;
655 u32 pint_assign;
656 u8 bmap;
657
658 memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut));
659
660 for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) {
661
662 pint_assign = pint[bank]->assign;
663
664 for (bit = 0; bit < NR_PINT_BITS; bit++) {
665
666 bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF;
667
668 irq_base = get_irq_base(bank, bmap);
669
670 irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0);
671 bit_pos = bit + bank * NR_PINT_BITS;
672
Michael Henneriche3f23002007-07-12 16:39:29 +0800673 pint2irq_lut[bit_pos] = irq_base - SYS_IRQS;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800674 irq2pint_lut[irq_base - SYS_IRQS] = bit_pos;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800675 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800676 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800677}
678
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800679static void bfin_gpio_ack_irq(unsigned int irq)
680{
Michael Hennerich8d022372008-11-18 17:48:22 +0800681 struct irq_desc *desc = irq_desc + irq;
682 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich8baf5602007-12-24 18:51:34 +0800683 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800684 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800685
Michael Hennerich8d022372008-11-18 17:48:22 +0800686 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800687 if (pint[bank]->invert_set & pintbit)
688 pint[bank]->invert_clear = pintbit;
689 else
690 pint[bank]->invert_set = pintbit;
691 }
692 pint[bank]->request = pintbit;
693
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800694}
695
696static void bfin_gpio_mask_ack_irq(unsigned int irq)
697{
Michael Hennerich8d022372008-11-18 17:48:22 +0800698 struct irq_desc *desc = irq_desc + irq;
699 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800700 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800701 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800702
Michael Hennerich8d022372008-11-18 17:48:22 +0800703 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800704 if (pint[bank]->invert_set & pintbit)
705 pint[bank]->invert_clear = pintbit;
706 else
707 pint[bank]->invert_set = pintbit;
708 }
709
Michael Henneriche3f23002007-07-12 16:39:29 +0800710 pint[bank]->request = pintbit;
711 pint[bank]->mask_clear = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800712}
713
714static void bfin_gpio_mask_irq(unsigned int irq)
715{
Michael Hennerich8d022372008-11-18 17:48:22 +0800716 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800717
718 pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800719}
720
721static void bfin_gpio_unmask_irq(unsigned int irq)
722{
Michael Hennerich8d022372008-11-18 17:48:22 +0800723 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800724 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800725 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800726
Michael Henneriche3f23002007-07-12 16:39:29 +0800727 pint[bank]->request = pintbit;
728 pint[bank]->mask_set = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800729}
730
731static unsigned int bfin_gpio_irq_startup(unsigned int irq)
732{
Michael Hennerich8d022372008-11-18 17:48:22 +0800733 u32 gpionr = irq_to_gpio(irq);
734 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800735
Michael Hennerich50e163c2007-07-24 16:17:28 +0800736 if (pint_val == IRQ_NOT_AVAIL) {
737 printk(KERN_ERR
738 "GPIO IRQ %d :Not in PINT Assign table "
739 "Reconfigure Interrupt to Port Assignemt\n", irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800740 return -ENODEV;
Michael Hennerich50e163c2007-07-24 16:17:28 +0800741 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800742
Michael Hennerich8d022372008-11-18 17:48:22 +0800743 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800744 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800745
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800746 bfin_gpio_unmask_irq(irq);
747
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800748 return 0;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800749}
750
751static void bfin_gpio_irq_shutdown(unsigned int irq)
752{
Michael Hennerich8d022372008-11-18 17:48:22 +0800753 u32 gpionr = irq_to_gpio(irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800754
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800755 bfin_gpio_mask_irq(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800756 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800757 bfin_gpio_irq_free(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800758}
759
760static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
761{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800762 int ret;
763 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800764 u32 gpionr = irq_to_gpio(irq);
765 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800766 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800767 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800768
769 if (pint_val == IRQ_NOT_AVAIL)
770 return -ENODEV;
771
772 if (type == IRQ_TYPE_PROBE) {
773 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400774 if (test_bit(gpionr, gpio_enabled))
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800775 return 0;
776 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
777 }
778
779 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
780 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Graf Yang9570ff42009-01-07 23:14:38 +0800781
782 snprintf(buf, 16, "gpio-irq%d", irq);
783 ret = bfin_gpio_irq_request(gpionr, buf);
784 if (ret)
785 return ret;
786
Michael Hennerich8d022372008-11-18 17:48:22 +0800787 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800788 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800789
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800790 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800791 __clear_bit(gpionr, gpio_enabled);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800792 return 0;
793 }
794
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800795 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
Michael Henneriche3f23002007-07-12 16:39:29 +0800796 pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800797 else
Michael Hennerich8baf5602007-12-24 18:51:34 +0800798 pint[bank]->invert_clear = pintbit; /* high or rising edge denoted by zero */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800799
Michael Hennerich8baf5602007-12-24 18:51:34 +0800800 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
801 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800802 if (gpio_get_value(gpionr))
803 pint[bank]->invert_set = pintbit;
804 else
805 pint[bank]->invert_clear = pintbit;
Michael Hennerich8baf5602007-12-24 18:51:34 +0800806 }
807
808 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
809 pint[bank]->edge_set = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800810 bfin_set_irq_handler(irq, handle_edge_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800811 } else {
812 pint[bank]->edge_clear = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800813 bfin_set_irq_handler(irq, handle_level_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800814 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800815
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800816 return 0;
817}
818
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800819#ifdef CONFIG_PM
820u32 pint_saved_masks[NR_PINT_SYS_IRQS];
821u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
822
823int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
824{
825 u32 pint_irq;
Michael Hennerich8d022372008-11-18 17:48:22 +0800826 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800827 u32 bank = PINT_2_BANK(pint_val);
828 u32 pintbit = PINT_BIT(pint_val);
829
830 switch (bank) {
831 case 0:
832 pint_irq = IRQ_PINT0;
833 break;
834 case 2:
835 pint_irq = IRQ_PINT2;
836 break;
837 case 3:
838 pint_irq = IRQ_PINT3;
839 break;
840 case 1:
841 pint_irq = IRQ_PINT1;
842 break;
843 default:
844 return -EINVAL;
845 }
846
847 bfin_internal_set_wake(pint_irq, state);
848
849 if (state)
850 pint_wakeup_masks[bank] |= pintbit;
851 else
852 pint_wakeup_masks[bank] &= ~pintbit;
853
854 return 0;
855}
856
857u32 bfin_pm_setup(void)
858{
859 u32 val, i;
860
861 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
862 val = pint[i]->mask_clear;
863 pint_saved_masks[i] = val;
864 if (val ^ pint_wakeup_masks[i]) {
865 pint[i]->mask_clear = val;
866 pint[i]->mask_set = pint_wakeup_masks[i];
867 }
868 }
869
870 return 0;
871}
872
873void bfin_pm_restore(void)
874{
875 u32 i, val;
876
877 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
878 val = pint_saved_masks[i];
879 if (val ^ pint_wakeup_masks[i]) {
880 pint[i]->mask_clear = pint[i]->mask_clear;
881 pint[i]->mask_set = val;
882 }
883 }
884}
885#endif
886
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800887static void bfin_demux_gpio_irq(unsigned int inta_irq,
888 struct irq_desc *desc)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800889{
Michael Hennerich8d022372008-11-18 17:48:22 +0800890 u32 bank, pint_val;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800891 u32 request, irq;
892
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800893 switch (inta_irq) {
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800894 case IRQ_PINT0:
895 bank = 0;
896 break;
897 case IRQ_PINT2:
898 bank = 2;
899 break;
900 case IRQ_PINT3:
901 bank = 3;
902 break;
903 case IRQ_PINT1:
904 bank = 1;
905 break;
Michael Henneriche3f23002007-07-12 16:39:29 +0800906 default:
907 return;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800908 }
909
910 pint_val = bank * NR_PINT_BITS;
911
912 request = pint[bank]->request;
913
914 while (request) {
915 if (request & 1) {
Michael Henneriche3f23002007-07-12 16:39:29 +0800916 irq = pint2irq_lut[pint_val] + SYS_IRQS;
Yi Li6a01f232009-01-07 23:14:39 +0800917 bfin_handle_irq(irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800918 }
919 pint_val++;
920 request >>= 1;
921 }
922
923}
Mike Frysingera055b2b2007-11-15 21:12:32 +0800924#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700925
Michael Hennerich8d022372008-11-18 17:48:22 +0800926static struct irq_chip bfin_gpio_irqchip = {
927 .name = "GPIO",
928 .ack = bfin_gpio_ack_irq,
929 .mask = bfin_gpio_mask_irq,
930 .mask_ack = bfin_gpio_mask_ack_irq,
931 .unmask = bfin_gpio_unmask_irq,
932 .disable = bfin_gpio_mask_irq,
933 .enable = bfin_gpio_unmask_irq,
934 .set_type = bfin_gpio_irq_type,
935 .startup = bfin_gpio_irq_startup,
936 .shutdown = bfin_gpio_irq_shutdown,
937#ifdef CONFIG_PM
938 .set_wake = bfin_gpio_set_wake,
939#endif
940};
941
Graf Yang6b3087c2009-01-07 23:14:39 +0800942void __cpuinit init_exception_vectors(void)
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800943{
Mike Frysingerf0b5d122007-08-05 17:03:59 +0800944 /* cannot program in software:
945 * evt0 - emulation (jtag)
946 * evt1 - reset
947 */
948 bfin_write_EVT2(evt_nmi);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800949 bfin_write_EVT3(trap);
950 bfin_write_EVT5(evt_ivhw);
951 bfin_write_EVT6(evt_timer);
952 bfin_write_EVT7(evt_evt7);
953 bfin_write_EVT8(evt_evt8);
954 bfin_write_EVT9(evt_evt9);
955 bfin_write_EVT10(evt_evt10);
956 bfin_write_EVT11(evt_evt11);
957 bfin_write_EVT12(evt_evt12);
958 bfin_write_EVT13(evt_evt13);
Philippe Gerum9703a732009-06-22 18:23:48 +0200959 bfin_write_EVT14(evt_evt14);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800960 bfin_write_EVT15(evt_system_call);
961 CSYNC();
962}
963
Bryan Wu1394f032007-05-06 14:50:22 -0700964/*
965 * This function should be called during kernel startup to initialize
966 * the BFin IRQ handling routines.
967 */
Michael Hennerich8d022372008-11-18 17:48:22 +0800968
Bryan Wu1394f032007-05-06 14:50:22 -0700969int __init init_arch_irq(void)
970{
971 int irq;
972 unsigned long ilat = 0;
973 /* Disable all the peripheral intrs - page 4-29 HW Ref manual */
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800974#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
975 || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
Roy Huang24a07a12007-07-12 22:41:45 +0800976 bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
977 bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +0800978# ifdef CONFIG_BF54x
Michael Hennerich59003142007-10-21 16:54:27 +0800979 bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +0800980# endif
Graf Yang6b3087c2009-01-07 23:14:39 +0800981# ifdef CONFIG_SMP
982 bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);
983 bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);
984# endif
Roy Huang24a07a12007-07-12 22:41:45 +0800985#else
Bryan Wu1394f032007-05-06 14:50:22 -0700986 bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
Roy Huang24a07a12007-07-12 22:41:45 +0800987#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700988
989 local_irq_disable();
990
Mike Frysingerd70536e2008-08-25 17:37:35 +0800991#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
Mike Frysinger95a86b52008-08-14 15:05:01 +0800992 /* Clear EMAC Interrupt Status bits so we can demux it later */
993 bfin_write_EMAC_SYSTAT(-1);
994#endif
995
Mike Frysingera055b2b2007-11-15 21:12:32 +0800996#ifdef CONFIG_BF54x
997# ifdef CONFIG_PINTx_REASSIGN
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800998 pint[0]->assign = CONFIG_PINT0_ASSIGN;
999 pint[1]->assign = CONFIG_PINT1_ASSIGN;
1000 pint[2]->assign = CONFIG_PINT2_ASSIGN;
1001 pint[3]->assign = CONFIG_PINT3_ASSIGN;
Mike Frysingera055b2b2007-11-15 21:12:32 +08001002# endif
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001003 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
1004 init_pint_lut();
1005#endif
1006
1007 for (irq = 0; irq <= SYS_IRQS; irq++) {
Bryan Wu1394f032007-05-06 14:50:22 -07001008 if (irq <= IRQ_CORETMR)
1009 set_irq_chip(irq, &bfin_core_irqchip);
1010 else
1011 set_irq_chip(irq, &bfin_internal_irqchip);
Bryan Wu1394f032007-05-06 14:50:22 -07001012
Michael Hennerich464abc52008-02-25 13:50:20 +08001013 switch (irq) {
Michael Hennerich59003142007-10-21 16:54:27 +08001014#if defined(CONFIG_BF53x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001015 case IRQ_PROG_INTA:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001016# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
Michael Hennerich464abc52008-02-25 13:50:20 +08001017 case IRQ_MAC_RX:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001018# endif
Michael Hennerich59003142007-10-21 16:54:27 +08001019#elif defined(CONFIG_BF54x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001020 case IRQ_PINT0:
1021 case IRQ_PINT1:
1022 case IRQ_PINT2:
1023 case IRQ_PINT3:
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001024#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001025 case IRQ_PORTF_INTA:
1026 case IRQ_PORTG_INTA:
1027 case IRQ_PORTH_INTA:
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001028#elif defined(CONFIG_BF561)
Michael Hennerich464abc52008-02-25 13:50:20 +08001029 case IRQ_PROG0_INTA:
1030 case IRQ_PROG1_INTA:
1031 case IRQ_PROG2_INTA:
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001032#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
1033 case IRQ_PORTF_INTA:
Michael Hennerich59003142007-10-21 16:54:27 +08001034#endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001035
Michael Hennerich464abc52008-02-25 13:50:20 +08001036 set_irq_chained_handler(irq,
1037 bfin_demux_gpio_irq);
1038 break;
Bryan Wu1394f032007-05-06 14:50:22 -07001039#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001040 case IRQ_GENERIC_ERROR:
Yi Li6a01f232009-01-07 23:14:39 +08001041 set_irq_chained_handler(irq, bfin_demux_error_irq);
Michael Hennerich464abc52008-02-25 13:50:20 +08001042 break;
1043#endif
Graf Yang179413142009-08-18 04:29:33 +00001044
Graf Yang6b3087c2009-01-07 23:14:39 +08001045#ifdef CONFIG_SMP
Graf Yang179413142009-08-18 04:29:33 +00001046#ifdef CONFIG_TICKSOURCE_GPTMR0
1047 case IRQ_TIMER0:
1048#endif
1049#ifdef CONFIG_TICKSOURCE_CORETMR
1050 case IRQ_CORETMR:
1051#endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001052 case IRQ_SUPPLE_0:
1053 case IRQ_SUPPLE_1:
1054 set_irq_handler(irq, handle_percpu_irq);
1055 break;
1056#endif
Graf Yang179413142009-08-18 04:29:33 +00001057
Yi Li6a01f232009-01-07 23:14:39 +08001058#ifdef CONFIG_IPIPE
Philippe Geruma40494a2009-06-16 05:25:42 +02001059#ifndef CONFIG_TICKSOURCE_CORETMR
1060 case IRQ_TIMER0:
Michael Hennerich464abc52008-02-25 13:50:20 +08001061 set_irq_handler(irq, handle_simple_irq);
1062 break;
Graf Yang179413142009-08-18 04:29:33 +00001063#endif
Philippe Geruma40494a2009-06-16 05:25:42 +02001064 case IRQ_CORETMR:
1065 set_irq_handler(irq, handle_simple_irq);
1066 break;
1067 default:
1068 set_irq_handler(irq, handle_level_irq);
1069 break;
1070#else /* !CONFIG_IPIPE */
Philippe Geruma40494a2009-06-16 05:25:42 +02001071 default:
1072 set_irq_handler(irq, handle_simple_irq);
1073 break;
Graf Yang179413142009-08-18 04:29:33 +00001074#endif /* !CONFIG_IPIPE */
Bryan Wu1394f032007-05-06 14:50:22 -07001075 }
Bryan Wu1394f032007-05-06 14:50:22 -07001076 }
Michael Hennerich464abc52008-02-25 13:50:20 +08001077
Bryan Wu1394f032007-05-06 14:50:22 -07001078#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001079 for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
1080 set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
1081 handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -07001082#endif
1083
Michael Hennerich464abc52008-02-25 13:50:20 +08001084 /* if configured as edge, then will be changed to do_edge_IRQ */
1085 for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
1086 set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
1087 handle_level_irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001088
Mike Frysingera055b2b2007-11-15 21:12:32 +08001089
Bryan Wu1394f032007-05-06 14:50:22 -07001090 bfin_write_IMASK(0);
1091 CSYNC();
1092 ilat = bfin_read_ILAT();
1093 CSYNC();
1094 bfin_write_ILAT(ilat);
1095 CSYNC();
1096
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001097 printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
Mike Frysinger40059782008-11-18 17:48:22 +08001098 /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx,
Bryan Wu1394f032007-05-06 14:50:22 -07001099 * local_irq_enable()
1100 */
1101 program_IAR();
1102 /* Therefore it's better to setup IARs before interrupts enabled */
1103 search_IAR();
1104
1105 /* Enable interrupts IVG7-15 */
Mike Frysinger40059782008-11-18 17:48:22 +08001106 bfin_irq_flags |= IMASK_IVG15 |
Bryan Wu1394f032007-05-06 14:50:22 -07001107 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001108 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
Bryan Wu1394f032007-05-06 14:50:22 -07001109
Michael Hennerich349ebbc2009-04-15 08:48:08 +00001110 /* This implicitly covers ANOMALY_05000171
1111 * Boot-ROM code modifies SICA_IWRx wakeup registers
1112 */
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001113#ifdef SIC_IWR0
Michael Hennerich56f5f592008-08-06 17:55:32 +08001114 bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001115# ifdef SIC_IWR1
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001116 /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which
Michael Hennerich55546ac2008-08-13 17:41:13 +08001117 * will screw up the bootrom as it relies on MDMA0/1 waking it
1118 * up from IDLE instructions. See this report for more info:
1119 * http://blackfin.uclinux.org/gf/tracker/4323
1120 */
Mike Frysingerb7e11292008-11-18 17:48:22 +08001121 if (ANOMALY_05000435)
1122 bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
1123 else
1124 bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001125# endif
1126# ifdef SIC_IWR2
Michael Hennerich56f5f592008-08-06 17:55:32 +08001127 bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001128# endif
1129#else
Michael Hennerich56f5f592008-08-06 17:55:32 +08001130 bfin_write_SIC_IWR(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001131#endif
1132
Bryan Wu1394f032007-05-06 14:50:22 -07001133 return 0;
1134}
1135
1136#ifdef CONFIG_DO_IRQ_L1
Mike Frysingera055b2b2007-11-15 21:12:32 +08001137__attribute__((l1_text))
Bryan Wu1394f032007-05-06 14:50:22 -07001138#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001139void do_irq(int vec, struct pt_regs *fp)
1140{
1141 if (vec == EVT_IVTMR_P) {
1142 vec = IRQ_CORETMR;
1143 } else {
1144 struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
1145 struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
Mike Frysinger780172b2009-06-01 19:43:02 -04001146#if defined(SIC_ISR0) || defined(SICA_ISR0)
Roy Huang24a07a12007-07-12 22:41:45 +08001147 unsigned long sic_status[3];
Bryan Wu1394f032007-05-06 14:50:22 -07001148
Graf Yang6b3087c2009-01-07 23:14:39 +08001149 if (smp_processor_id()) {
Mike Frysinger780172b2009-06-01 19:43:02 -04001150# ifdef SICB_ISR0
Graf Yang6b3087c2009-01-07 23:14:39 +08001151 /* This will be optimized out in UP mode. */
1152 sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
1153 sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001154# endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001155 } else {
1156 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1157 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
1158 }
Mike Frysinger780172b2009-06-01 19:43:02 -04001159# ifdef SIC_ISR2
Michael Hennerich4fb45242007-10-21 16:53:53 +08001160 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001161# endif
Mike Frysinger1f83b8f2007-07-12 22:58:21 +08001162 for (;; ivg++) {
Roy Huang24a07a12007-07-12 22:41:45 +08001163 if (ivg >= ivg_stop) {
1164 atomic_inc(&num_spurious);
1165 return;
1166 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001167 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
Roy Huang24a07a12007-07-12 22:41:45 +08001168 break;
1169 }
1170#else
1171 unsigned long sic_status;
Michael Hennerich464abc52008-02-25 13:50:20 +08001172
Bryan Wu1394f032007-05-06 14:50:22 -07001173 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1174
1175 for (;; ivg++) {
1176 if (ivg >= ivg_stop) {
1177 atomic_inc(&num_spurious);
1178 return;
1179 } else if (sic_status & ivg->isrflag)
1180 break;
1181 }
Roy Huang24a07a12007-07-12 22:41:45 +08001182#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001183 vec = ivg->irqno;
1184 }
1185 asm_do_IRQ(vec, fp);
Bryan Wu1394f032007-05-06 14:50:22 -07001186}
Yi Li6a01f232009-01-07 23:14:39 +08001187
1188#ifdef CONFIG_IPIPE
1189
1190int __ipipe_get_irq_priority(unsigned irq)
1191{
1192 int ient, prio;
1193
1194 if (irq <= IRQ_CORETMR)
1195 return irq;
1196
1197 for (ient = 0; ient < NR_PERI_INTS; ient++) {
1198 struct ivgx *ivg = ivg_table + ient;
1199 if (ivg->irqno == irq) {
1200 for (prio = 0; prio <= IVG13-IVG7; prio++) {
1201 if (ivg7_13[prio].ifirst <= ivg &&
1202 ivg7_13[prio].istop > ivg)
1203 return IVG7 + prio;
1204 }
1205 }
1206 }
1207
1208 return IVG15;
1209}
1210
Yi Li6a01f232009-01-07 23:14:39 +08001211/* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */
1212#ifdef CONFIG_DO_IRQ_L1
1213__attribute__((l1_text))
1214#endif
1215asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
1216{
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001217 struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr();
Philippe Geruma40494a2009-06-16 05:25:42 +02001218 struct ipipe_domain *this_domain = __ipipe_current_domain;
Yi Li6a01f232009-01-07 23:14:39 +08001219 struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
1220 struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001221 int irq, s;
Yi Li6a01f232009-01-07 23:14:39 +08001222
Philippe Geruma40494a2009-06-16 05:25:42 +02001223 if (likely(vec == EVT_IVTMR_P))
Yi Li6a01f232009-01-07 23:14:39 +08001224 irq = IRQ_CORETMR;
Philippe Geruma40494a2009-06-16 05:25:42 +02001225 else {
Mike Frysinger780172b2009-06-01 19:43:02 -04001226#if defined(SIC_ISR0) || defined(SICA_ISR0)
Yi Li6a01f232009-01-07 23:14:39 +08001227 unsigned long sic_status[3];
1228
1229 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1230 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001231# ifdef SIC_ISR2
Yi Li6a01f232009-01-07 23:14:39 +08001232 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001233# endif
Yi Li6a01f232009-01-07 23:14:39 +08001234 for (;; ivg++) {
1235 if (ivg >= ivg_stop) {
1236 atomic_inc(&num_spurious);
1237 return 0;
1238 }
1239 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
1240 break;
1241 }
Yi Li6a01f232009-01-07 23:14:39 +08001242#else
Yi Li6a01f232009-01-07 23:14:39 +08001243 unsigned long sic_status;
1244
1245 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1246
1247 for (;; ivg++) {
1248 if (ivg >= ivg_stop) {
1249 atomic_inc(&num_spurious);
1250 return 0;
1251 } else if (sic_status & ivg->isrflag)
1252 break;
1253 }
Yi Li6a01f232009-01-07 23:14:39 +08001254#endif
Graf Yang1fa9be72009-05-15 11:01:59 +00001255 irq = ivg->irqno;
1256 }
Yi Li6a01f232009-01-07 23:14:39 +08001257
1258 if (irq == IRQ_SYSTMR) {
Philippe Geruma40494a2009-06-16 05:25:42 +02001259#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
Yi Li6a01f232009-01-07 23:14:39 +08001260 bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001261#endif
Yi Li6a01f232009-01-07 23:14:39 +08001262 /* This is basically what we need from the register frame. */
1263 __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend;
1264 __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001265 if (this_domain != ipipe_root_domain)
Yi Li6a01f232009-01-07 23:14:39 +08001266 __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001267 else
1268 __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
Yi Li6a01f232009-01-07 23:14:39 +08001269 }
1270
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001271 if (this_domain == ipipe_root_domain) {
1272 s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1273 barrier();
1274 }
Yi Li6a01f232009-01-07 23:14:39 +08001275
1276 ipipe_trace_irq_entry(irq);
1277 __ipipe_handle_irq(irq, regs);
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001278 ipipe_trace_irq_exit(irq);
Yi Li6a01f232009-01-07 23:14:39 +08001279
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001280 if (this_domain == ipipe_root_domain) {
1281 set_thread_flag(TIF_IRQ_SYNC);
1282 if (!s) {
1283 __clear_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1284 return !test_bit(IPIPE_STALL_FLAG, &p->status);
1285 }
1286 }
Yi Li6a01f232009-01-07 23:14:39 +08001287
Graf Yang1fa9be72009-05-15 11:01:59 +00001288 return 0;
Yi Li6a01f232009-01-07 23:14:39 +08001289}
1290
1291#endif /* CONFIG_IPIPE */