blob: 1873b2c1fede8b2d267d639dbe9c111e05091b10 [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>
Bryan Wu1394f032007-05-06 14:50:22 -070031
Mike Frysinger7beb7432008-11-18 17:48:22 +080032#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
33
Bryan Wu1394f032007-05-06 14:50:22 -070034#ifdef BF537_FAMILY
35# define BF537_GENERIC_ERROR_INT_DEMUX
Mike Frysinger7eb87fd2009-11-03 09:29:50 +000036# define SPI_ERR_MASK (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE) /* SPI_STAT */
37# define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF) /* SPORT_STAT */
38# define PPI_ERR_MASK (0xFFFF & ~FLD) /* PPI_STATUS */
39# define EMAC_ERR_MASK (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE) /* EMAC_SYSTAT */
40# define UART_ERR_MASK (0x6) /* UART_IIR */
41# define CAN_ERR_MASK (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF) /* CAN_GIF */
Bryan Wu1394f032007-05-06 14:50:22 -070042#else
43# undef BF537_GENERIC_ERROR_INT_DEMUX
44#endif
45
46/*
47 * NOTES:
48 * - we have separated the physical Hardware interrupt from the
49 * levels that the LINUX kernel sees (see the description in irq.h)
50 * -
51 */
52
Graf Yang6b3087c2009-01-07 23:14:39 +080053#ifndef CONFIG_SMP
Mike Frysingera99bbcc2007-10-22 00:19:31 +080054/* Initialize this to an actual value to force it into the .data
55 * section so that we know it is properly initialized at entry into
56 * the kernel but before bss is initialized to zero (which is where
57 * it would live otherwise). The 0x1f magic represents the IRQs we
58 * cannot actually mask out in hardware.
59 */
Mike Frysinger40059782008-11-18 17:48:22 +080060unsigned long bfin_irq_flags = 0x1f;
61EXPORT_SYMBOL(bfin_irq_flags);
Graf Yang6b3087c2009-01-07 23:14:39 +080062#endif
Bryan Wu1394f032007-05-06 14:50:22 -070063
64/* The number of spurious interrupts */
65atomic_t num_spurious;
66
Michael Hennerichcfefe3c2008-02-09 04:12:37 +080067#ifdef CONFIG_PM
68unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */
Michael Hennerich4a88d0c2008-08-05 17:38:41 +080069unsigned vr_wakeup;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +080070#endif
71
Bryan Wu1394f032007-05-06 14:50:22 -070072struct ivgx {
Michael Hennerich464abc52008-02-25 13:50:20 +080073 /* irq number for request_irq, available in mach-bf5xx/irq.h */
Roy Huang24a07a12007-07-12 22:41:45 +080074 unsigned int irqno;
Bryan Wu1394f032007-05-06 14:50:22 -070075 /* corresponding bit in the SIC_ISR register */
Roy Huang24a07a12007-07-12 22:41:45 +080076 unsigned int isrflag;
Bryan Wu1394f032007-05-06 14:50:22 -070077} ivg_table[NR_PERI_INTS];
78
79struct ivg_slice {
80 /* position of first irq in ivg_table for given ivg */
81 struct ivgx *ifirst;
82 struct ivgx *istop;
83} ivg7_13[IVG13 - IVG7 + 1];
84
Bryan Wu1394f032007-05-06 14:50:22 -070085
86/*
87 * Search SIC_IAR and fill tables with the irqvalues
88 * and their positions in the SIC_ISR register.
89 */
90static void __init search_IAR(void)
91{
92 unsigned ivg, irq_pos = 0;
93 for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
94 int irqn;
95
Michael Hennerich34e0fc82007-07-12 16:17:18 +080096 ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
Bryan Wu1394f032007-05-06 14:50:22 -070097
98 for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
99 int iar_shift = (irqn & 7) * 4;
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800100 if (ivg == (0xf &
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800101#if defined(CONFIG_BF52x) || defined(CONFIG_BF538) \
102 || defined(CONFIG_BF539) || defined(CONFIG_BF51x)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800103 bfin_read32((unsigned long *)SIC_IAR0 +
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800104 ((irqn % 32) >> 3) + ((irqn / 32) *
105 ((SIC_IAR4 - SIC_IAR0) / 4))) >> iar_shift)) {
Michael Hennerich59003142007-10-21 16:54:27 +0800106#else
107 bfin_read32((unsigned long *)SIC_IAR0 +
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800108 (irqn >> 3)) >> iar_shift)) {
Michael Hennerich59003142007-10-21 16:54:27 +0800109#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700110 ivg_table[irq_pos].irqno = IVG7 + irqn;
Roy Huang24a07a12007-07-12 22:41:45 +0800111 ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
Bryan Wu1394f032007-05-06 14:50:22 -0700112 ivg7_13[ivg].istop++;
113 irq_pos++;
114 }
115 }
116 }
117}
118
119/*
Michael Hennerich464abc52008-02-25 13:50:20 +0800120 * This is for core internal IRQs
Bryan Wu1394f032007-05-06 14:50:22 -0700121 */
122
Michael Hennerich464abc52008-02-25 13:50:20 +0800123static void bfin_ack_noop(unsigned int irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700124{
125 /* Dummy function. */
126}
127
128static void bfin_core_mask_irq(unsigned int irq)
129{
Mike Frysinger40059782008-11-18 17:48:22 +0800130 bfin_irq_flags &= ~(1 << irq);
Yi Li6a01f232009-01-07 23:14:39 +0800131 if (!irqs_disabled_hw())
132 local_irq_enable_hw();
Bryan Wu1394f032007-05-06 14:50:22 -0700133}
134
135static void bfin_core_unmask_irq(unsigned int irq)
136{
Mike Frysinger40059782008-11-18 17:48:22 +0800137 bfin_irq_flags |= 1 << irq;
Bryan Wu1394f032007-05-06 14:50:22 -0700138 /*
139 * If interrupts are enabled, IMASK must contain the same value
Mike Frysinger40059782008-11-18 17:48:22 +0800140 * as bfin_irq_flags. Make sure that invariant holds. If interrupts
Bryan Wu1394f032007-05-06 14:50:22 -0700141 * are currently disabled we need not do anything; one of the
142 * callers will take care of setting IMASK to the proper value
143 * when reenabling interrupts.
Mike Frysinger40059782008-11-18 17:48:22 +0800144 * local_irq_enable just does "STI bfin_irq_flags", so it's exactly
Bryan Wu1394f032007-05-06 14:50:22 -0700145 * what we need.
146 */
Yi Li6a01f232009-01-07 23:14:39 +0800147 if (!irqs_disabled_hw())
148 local_irq_enable_hw();
Bryan Wu1394f032007-05-06 14:50:22 -0700149 return;
150}
151
152static void bfin_internal_mask_irq(unsigned int irq)
153{
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800154 unsigned long flags;
155
Michael Hennerich59003142007-10-21 16:54:27 +0800156#ifdef CONFIG_BF53x
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800157 local_irq_save_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700158 bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
Michael Hennerich464abc52008-02-25 13:50:20 +0800159 ~(1 << SIC_SYSIRQ(irq)));
Roy Huang24a07a12007-07-12 22:41:45 +0800160#else
161 unsigned mask_bank, mask_bit;
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800162 local_irq_save_hw(flags);
Michael Hennerich464abc52008-02-25 13:50:20 +0800163 mask_bank = SIC_SYSIRQ(irq) / 32;
164 mask_bit = SIC_SYSIRQ(irq) % 32;
Bryan Wuc04d66b2007-07-12 17:26:31 +0800165 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
166 ~(1 << mask_bit));
Graf Yang6b3087c2009-01-07 23:14:39 +0800167#ifdef CONFIG_SMP
168 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
169 ~(1 << mask_bit));
170#endif
Roy Huang24a07a12007-07-12 22:41:45 +0800171#endif
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800172 local_irq_restore_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700173}
174
175static void bfin_internal_unmask_irq(unsigned int irq)
176{
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800177 unsigned long flags;
178
Michael Hennerich59003142007-10-21 16:54:27 +0800179#ifdef CONFIG_BF53x
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800180 local_irq_save_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700181 bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
Michael Hennerich464abc52008-02-25 13:50:20 +0800182 (1 << SIC_SYSIRQ(irq)));
Roy Huang24a07a12007-07-12 22:41:45 +0800183#else
184 unsigned mask_bank, mask_bit;
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800185 local_irq_save_hw(flags);
Michael Hennerich464abc52008-02-25 13:50:20 +0800186 mask_bank = SIC_SYSIRQ(irq) / 32;
187 mask_bit = SIC_SYSIRQ(irq) % 32;
Bryan Wuc04d66b2007-07-12 17:26:31 +0800188 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
189 (1 << mask_bit));
Graf Yang6b3087c2009-01-07 23:14:39 +0800190#ifdef CONFIG_SMP
191 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) |
192 (1 << mask_bit));
193#endif
Roy Huang24a07a12007-07-12 22:41:45 +0800194#endif
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800195 local_irq_restore_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700196}
197
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800198#ifdef CONFIG_PM
199int bfin_internal_set_wake(unsigned int irq, unsigned int state)
200{
Michael Hennerich8d022372008-11-18 17:48:22 +0800201 u32 bank, bit, wakeup = 0;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800202 unsigned long flags;
Michael Hennerich464abc52008-02-25 13:50:20 +0800203 bank = SIC_SYSIRQ(irq) / 32;
204 bit = SIC_SYSIRQ(irq) % 32;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800205
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800206 switch (irq) {
207#ifdef IRQ_RTC
208 case IRQ_RTC:
209 wakeup |= WAKE;
210 break;
211#endif
212#ifdef IRQ_CAN0_RX
213 case IRQ_CAN0_RX:
214 wakeup |= CANWE;
215 break;
216#endif
217#ifdef IRQ_CAN1_RX
218 case IRQ_CAN1_RX:
219 wakeup |= CANWE;
220 break;
221#endif
222#ifdef IRQ_USB_INT0
223 case IRQ_USB_INT0:
224 wakeup |= USBWE;
225 break;
226#endif
227#ifdef IRQ_KEY
228 case IRQ_KEY:
229 wakeup |= KPADWE;
230 break;
231#endif
Michael Hennerichd310fb42008-08-28 17:32:01 +0800232#ifdef CONFIG_BF54x
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800233 case IRQ_CNT:
234 wakeup |= ROTWE;
235 break;
236#endif
237 default:
238 break;
239 }
240
Yi Li6a01f232009-01-07 23:14:39 +0800241 local_irq_save_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800242
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800243 if (state) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800244 bfin_sic_iwr[bank] |= (1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800245 vr_wakeup |= wakeup;
246
247 } else {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800248 bfin_sic_iwr[bank] &= ~(1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800249 vr_wakeup &= ~wakeup;
250 }
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800251
Yi Li6a01f232009-01-07 23:14:39 +0800252 local_irq_restore_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800253
254 return 0;
255}
256#endif
257
Bryan Wu1394f032007-05-06 14:50:22 -0700258static struct irq_chip bfin_core_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800259 .name = "CORE",
Michael Hennerich464abc52008-02-25 13:50:20 +0800260 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700261 .mask = bfin_core_mask_irq,
262 .unmask = bfin_core_unmask_irq,
263};
264
265static struct irq_chip bfin_internal_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800266 .name = "INTN",
Michael Hennerich464abc52008-02-25 13:50:20 +0800267 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700268 .mask = bfin_internal_mask_irq,
269 .unmask = bfin_internal_unmask_irq,
Michael Hennerichce3b7bb2008-02-25 13:48:47 +0800270 .mask_ack = bfin_internal_mask_irq,
271 .disable = bfin_internal_mask_irq,
272 .enable = bfin_internal_unmask_irq,
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800273#ifdef CONFIG_PM
274 .set_wake = bfin_internal_set_wake,
275#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700276};
277
Yi Li6a01f232009-01-07 23:14:39 +0800278static void bfin_handle_irq(unsigned irq)
279{
280#ifdef CONFIG_IPIPE
281 struct pt_regs regs; /* Contents not used. */
282 ipipe_trace_irq_entry(irq);
283 __ipipe_handle_irq(irq, &regs);
284 ipipe_trace_irq_exit(irq);
285#else /* !CONFIG_IPIPE */
286 struct irq_desc *desc = irq_desc + irq;
287 desc->handle_irq(irq, desc);
288#endif /* !CONFIG_IPIPE */
289}
290
Bryan Wu1394f032007-05-06 14:50:22 -0700291#ifdef BF537_GENERIC_ERROR_INT_DEMUX
292static int error_int_mask;
293
Bryan Wu1394f032007-05-06 14:50:22 -0700294static void bfin_generic_error_mask_irq(unsigned int irq)
295{
296 error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
297
Michael Hennerich464abc52008-02-25 13:50:20 +0800298 if (!error_int_mask)
299 bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700300}
301
302static void bfin_generic_error_unmask_irq(unsigned int irq)
303{
Michael Hennerich464abc52008-02-25 13:50:20 +0800304 bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700305 error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
306}
307
308static struct irq_chip bfin_generic_error_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800309 .name = "ERROR",
Michael Hennerich464abc52008-02-25 13:50:20 +0800310 .ack = bfin_ack_noop,
311 .mask_ack = bfin_generic_error_mask_irq,
Bryan Wu1394f032007-05-06 14:50:22 -0700312 .mask = bfin_generic_error_mask_irq,
313 .unmask = bfin_generic_error_unmask_irq,
314};
315
316static void bfin_demux_error_irq(unsigned int int_err_irq,
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800317 struct irq_desc *inta_desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700318{
319 int irq = 0;
320
Bryan Wu1394f032007-05-06 14:50:22 -0700321#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
322 if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
323 irq = IRQ_MAC_ERROR;
324 else
325#endif
326 if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
327 irq = IRQ_SPORT0_ERROR;
328 else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
329 irq = IRQ_SPORT1_ERROR;
330 else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
331 irq = IRQ_PPI_ERROR;
332 else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
333 irq = IRQ_CAN_ERROR;
334 else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
335 irq = IRQ_SPI_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000336 else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700337 irq = IRQ_UART0_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000338 else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700339 irq = IRQ_UART1_ERROR;
340
341 if (irq) {
Yi Li6a01f232009-01-07 23:14:39 +0800342 if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
343 bfin_handle_irq(irq);
344 else {
Bryan Wu1394f032007-05-06 14:50:22 -0700345
346 switch (irq) {
347 case IRQ_PPI_ERROR:
348 bfin_write_PPI_STATUS(PPI_ERR_MASK);
349 break;
350#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
351 case IRQ_MAC_ERROR:
352 bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
353 break;
354#endif
355 case IRQ_SPORT0_ERROR:
356 bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
357 break;
358
359 case IRQ_SPORT1_ERROR:
360 bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
361 break;
362
363 case IRQ_CAN_ERROR:
364 bfin_write_CAN_GIS(CAN_ERR_MASK);
365 break;
366
367 case IRQ_SPI_ERROR:
368 bfin_write_SPI_STAT(SPI_ERR_MASK);
369 break;
370
371 default:
372 break;
373 }
374
375 pr_debug("IRQ %d:"
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800376 " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
377 irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700378 }
379 } else
380 printk(KERN_ERR
381 "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
382 " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
Harvey Harrisonb85d8582008-04-23 09:39:01 +0800383 __func__, __FILE__, __LINE__);
Bryan Wu1394f032007-05-06 14:50:22 -0700384
Bryan Wu1394f032007-05-06 14:50:22 -0700385}
386#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
387
Graf Yangbfd15112008-10-08 18:02:44 +0800388static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
389{
Yi Li6a01f232009-01-07 23:14:39 +0800390#ifdef CONFIG_IPIPE
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800391 _set_irq_handler(irq, handle_level_irq);
Yi Li6a01f232009-01-07 23:14:39 +0800392#else
Graf Yangbfd15112008-10-08 18:02:44 +0800393 struct irq_desc *desc = irq_desc + irq;
394 /* May not call generic set_irq_handler() due to spinlock
395 recursion. */
396 desc->handle_irq = handle;
Yi Li6a01f232009-01-07 23:14:39 +0800397#endif
Graf Yangbfd15112008-10-08 18:02:44 +0800398}
399
Michael Hennerich8d022372008-11-18 17:48:22 +0800400static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800401extern void bfin_gpio_irq_prepare(unsigned gpio);
Michael Hennerich6fce6a82007-12-24 16:56:12 +0800402
Michael Hennerich8d022372008-11-18 17:48:22 +0800403#if !defined(CONFIG_BF54x)
404
Bryan Wu1394f032007-05-06 14:50:22 -0700405static void bfin_gpio_ack_irq(unsigned int irq)
406{
Michael Hennerich8d022372008-11-18 17:48:22 +0800407 /* AFAIK ack_irq in case mask_ack is provided
408 * get's only called for edge sense irqs
409 */
410 set_gpio_data(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700411}
412
413static void bfin_gpio_mask_ack_irq(unsigned int irq)
414{
Michael Hennerich8d022372008-11-18 17:48:22 +0800415 struct irq_desc *desc = irq_desc + irq;
416 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700417
Michael Hennerich8d022372008-11-18 17:48:22 +0800418 if (desc->handle_irq == handle_edge_irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700419 set_gpio_data(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700420
421 set_gpio_maska(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700422}
423
424static void bfin_gpio_mask_irq(unsigned int irq)
425{
Michael Hennerich8d022372008-11-18 17:48:22 +0800426 set_gpio_maska(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700427}
428
429static void bfin_gpio_unmask_irq(unsigned int irq)
430{
Michael Hennerich8d022372008-11-18 17:48:22 +0800431 set_gpio_maska(irq_to_gpio(irq), 1);
Bryan Wu1394f032007-05-06 14:50:22 -0700432}
433
434static unsigned int bfin_gpio_irq_startup(unsigned int irq)
435{
Michael Hennerich8d022372008-11-18 17:48:22 +0800436 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700437
Michael Hennerich8d022372008-11-18 17:48:22 +0800438 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800439 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700440
Bryan Wu1394f032007-05-06 14:50:22 -0700441 bfin_gpio_unmask_irq(irq);
442
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800443 return 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700444}
445
446static void bfin_gpio_irq_shutdown(unsigned int irq)
447{
Graf Yang30af6d42008-11-18 17:48:21 +0800448 u32 gpionr = irq_to_gpio(irq);
449
Bryan Wu1394f032007-05-06 14:50:22 -0700450 bfin_gpio_mask_irq(irq);
Graf Yang30af6d42008-11-18 17:48:21 +0800451 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800452 bfin_gpio_irq_free(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700453}
454
455static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
456{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800457 int ret;
458 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800459 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700460
461 if (type == IRQ_TYPE_PROBE) {
462 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400463 if (test_bit(gpionr, gpio_enabled))
Bryan Wu1394f032007-05-06 14:50:22 -0700464 return 0;
465 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
466 }
467
468 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800469 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Michael Hennerich8d022372008-11-18 17:48:22 +0800470
Graf Yang9570ff42009-01-07 23:14:38 +0800471 snprintf(buf, 16, "gpio-irq%d", irq);
472 ret = bfin_gpio_irq_request(gpionr, buf);
473 if (ret)
474 return ret;
475
Michael Hennerich8d022372008-11-18 17:48:22 +0800476 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800477 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700478
Bryan Wu1394f032007-05-06 14:50:22 -0700479 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800480 __clear_bit(gpionr, gpio_enabled);
Bryan Wu1394f032007-05-06 14:50:22 -0700481 return 0;
482 }
483
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800484 set_gpio_inen(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700485 set_gpio_dir(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700486
487 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
488 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
489 set_gpio_both(gpionr, 1);
490 else
491 set_gpio_both(gpionr, 0);
492
493 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
494 set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
495 else
496 set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
497
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800498 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
499 set_gpio_edge(gpionr, 1);
500 set_gpio_inen(gpionr, 1);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800501 set_gpio_data(gpionr, 0);
502
503 } else {
504 set_gpio_edge(gpionr, 0);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800505 set_gpio_inen(gpionr, 1);
506 }
507
Bryan Wu1394f032007-05-06 14:50:22 -0700508 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
Graf Yangbfd15112008-10-08 18:02:44 +0800509 bfin_set_irq_handler(irq, handle_edge_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700510 else
Graf Yangbfd15112008-10-08 18:02:44 +0800511 bfin_set_irq_handler(irq, handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700512
513 return 0;
514}
515
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800516#ifdef CONFIG_PM
517int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
518{
519 unsigned gpio = irq_to_gpio(irq);
520
521 if (state)
522 gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE);
523 else
524 gpio_pm_wakeup_free(gpio);
525
526 return 0;
527}
528#endif
529
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800530static void bfin_demux_gpio_irq(unsigned int inta_irq,
531 struct irq_desc *desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700532{
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800533 unsigned int i, gpio, mask, irq, search = 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700534
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800535 switch (inta_irq) {
536#if defined(CONFIG_BF53x)
537 case IRQ_PROG_INTA:
538 irq = IRQ_PF0;
539 search = 1;
540 break;
541# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
542 case IRQ_MAC_RX:
543 irq = IRQ_PH0;
544 break;
545# endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800546#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
547 case IRQ_PORTF_INTA:
548 irq = IRQ_PF0;
549 break;
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800550#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800551 case IRQ_PORTF_INTA:
552 irq = IRQ_PF0;
553 break;
554 case IRQ_PORTG_INTA:
555 irq = IRQ_PG0;
556 break;
557 case IRQ_PORTH_INTA:
558 irq = IRQ_PH0;
559 break;
560#elif defined(CONFIG_BF561)
561 case IRQ_PROG0_INTA:
562 irq = IRQ_PF0;
563 break;
564 case IRQ_PROG1_INTA:
565 irq = IRQ_PF16;
566 break;
567 case IRQ_PROG2_INTA:
568 irq = IRQ_PF32;
569 break;
570#endif
571 default:
572 BUG();
573 return;
Bryan Wu1394f032007-05-06 14:50:22 -0700574 }
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800575
576 if (search) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800577 for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800578 irq += i;
579
Michael Hennerich8d022372008-11-18 17:48:22 +0800580 mask = get_gpiop_data(i) & get_gpiop_maska(i);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800581
582 while (mask) {
Yi Li6a01f232009-01-07 23:14:39 +0800583 if (mask & 1)
584 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800585 irq++;
586 mask >>= 1;
587 }
588 }
589 } else {
590 gpio = irq_to_gpio(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800591 mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800592
593 do {
Yi Li6a01f232009-01-07 23:14:39 +0800594 if (mask & 1)
595 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800596 irq++;
597 mask >>= 1;
598 } while (mask);
599 }
600
Bryan Wu1394f032007-05-06 14:50:22 -0700601}
602
Mike Frysingera055b2b2007-11-15 21:12:32 +0800603#else /* CONFIG_BF54x */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800604
605#define NR_PINT_SYS_IRQS 4
606#define NR_PINT_BITS 32
607#define NR_PINTS 160
608#define IRQ_NOT_AVAIL 0xFF
609
610#define PINT_2_BANK(x) ((x) >> 5)
611#define PINT_2_BIT(x) ((x) & 0x1F)
612#define PINT_BIT(x) (1 << (PINT_2_BIT(x)))
613
614static unsigned char irq2pint_lut[NR_PINTS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800615static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800616
617struct pin_int_t {
618 unsigned int mask_set;
619 unsigned int mask_clear;
620 unsigned int request;
621 unsigned int assign;
622 unsigned int edge_set;
623 unsigned int edge_clear;
624 unsigned int invert_set;
625 unsigned int invert_clear;
626 unsigned int pinstate;
627 unsigned int latch;
628};
629
630static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
631 (struct pin_int_t *)PINT0_MASK_SET,
632 (struct pin_int_t *)PINT1_MASK_SET,
633 (struct pin_int_t *)PINT2_MASK_SET,
634 (struct pin_int_t *)PINT3_MASK_SET,
635};
636
Michael Hennerich8d022372008-11-18 17:48:22 +0800637inline unsigned int get_irq_base(u32 bank, u8 bmap)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800638{
Michael Hennerich8d022372008-11-18 17:48:22 +0800639 unsigned int irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800640
641 if (bank < 2) { /*PA-PB */
642 irq_base = IRQ_PA0 + bmap * 16;
643 } else { /*PC-PJ */
644 irq_base = IRQ_PC0 + bmap * 16;
645 }
646
647 return irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800648}
649
650 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
651void init_pint_lut(void)
652{
653 u16 bank, bit, irq_base, bit_pos;
654 u32 pint_assign;
655 u8 bmap;
656
657 memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut));
658
659 for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) {
660
661 pint_assign = pint[bank]->assign;
662
663 for (bit = 0; bit < NR_PINT_BITS; bit++) {
664
665 bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF;
666
667 irq_base = get_irq_base(bank, bmap);
668
669 irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0);
670 bit_pos = bit + bank * NR_PINT_BITS;
671
Michael Henneriche3f23002007-07-12 16:39:29 +0800672 pint2irq_lut[bit_pos] = irq_base - SYS_IRQS;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800673 irq2pint_lut[irq_base - SYS_IRQS] = bit_pos;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800674 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800675 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800676}
677
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800678static void bfin_gpio_ack_irq(unsigned int irq)
679{
Michael Hennerich8d022372008-11-18 17:48:22 +0800680 struct irq_desc *desc = irq_desc + irq;
681 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich8baf5602007-12-24 18:51:34 +0800682 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800683 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800684
Michael Hennerich8d022372008-11-18 17:48:22 +0800685 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800686 if (pint[bank]->invert_set & pintbit)
687 pint[bank]->invert_clear = pintbit;
688 else
689 pint[bank]->invert_set = pintbit;
690 }
691 pint[bank]->request = pintbit;
692
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800693}
694
695static void bfin_gpio_mask_ack_irq(unsigned int irq)
696{
Michael Hennerich8d022372008-11-18 17:48:22 +0800697 struct irq_desc *desc = irq_desc + irq;
698 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800699 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800700 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800701
Michael Hennerich8d022372008-11-18 17:48:22 +0800702 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800703 if (pint[bank]->invert_set & pintbit)
704 pint[bank]->invert_clear = pintbit;
705 else
706 pint[bank]->invert_set = pintbit;
707 }
708
Michael Henneriche3f23002007-07-12 16:39:29 +0800709 pint[bank]->request = pintbit;
710 pint[bank]->mask_clear = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800711}
712
713static void bfin_gpio_mask_irq(unsigned int irq)
714{
Michael Hennerich8d022372008-11-18 17:48:22 +0800715 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800716
717 pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800718}
719
720static void bfin_gpio_unmask_irq(unsigned int irq)
721{
Michael Hennerich8d022372008-11-18 17:48:22 +0800722 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800723 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800724 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800725
Michael Henneriche3f23002007-07-12 16:39:29 +0800726 pint[bank]->request = pintbit;
727 pint[bank]->mask_set = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800728}
729
730static unsigned int bfin_gpio_irq_startup(unsigned int irq)
731{
Michael Hennerich8d022372008-11-18 17:48:22 +0800732 u32 gpionr = irq_to_gpio(irq);
733 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800734
Michael Hennerich50e163c2007-07-24 16:17:28 +0800735 if (pint_val == IRQ_NOT_AVAIL) {
736 printk(KERN_ERR
737 "GPIO IRQ %d :Not in PINT Assign table "
738 "Reconfigure Interrupt to Port Assignemt\n", irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800739 return -ENODEV;
Michael Hennerich50e163c2007-07-24 16:17:28 +0800740 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800741
Michael Hennerich8d022372008-11-18 17:48:22 +0800742 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800743 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800744
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800745 bfin_gpio_unmask_irq(irq);
746
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800747 return 0;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800748}
749
750static void bfin_gpio_irq_shutdown(unsigned int irq)
751{
Michael Hennerich8d022372008-11-18 17:48:22 +0800752 u32 gpionr = irq_to_gpio(irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800753
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800754 bfin_gpio_mask_irq(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800755 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800756 bfin_gpio_irq_free(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800757}
758
759static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
760{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800761 int ret;
762 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800763 u32 gpionr = irq_to_gpio(irq);
764 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800765 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800766 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800767
768 if (pint_val == IRQ_NOT_AVAIL)
769 return -ENODEV;
770
771 if (type == IRQ_TYPE_PROBE) {
772 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400773 if (test_bit(gpionr, gpio_enabled))
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800774 return 0;
775 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
776 }
777
778 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
779 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Graf Yang9570ff42009-01-07 23:14:38 +0800780
781 snprintf(buf, 16, "gpio-irq%d", irq);
782 ret = bfin_gpio_irq_request(gpionr, buf);
783 if (ret)
784 return ret;
785
Michael Hennerich8d022372008-11-18 17:48:22 +0800786 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800787 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800788
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800789 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800790 __clear_bit(gpionr, gpio_enabled);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800791 return 0;
792 }
793
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800794 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
Michael Henneriche3f23002007-07-12 16:39:29 +0800795 pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800796 else
Michael Hennerich8baf5602007-12-24 18:51:34 +0800797 pint[bank]->invert_clear = pintbit; /* high or rising edge denoted by zero */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800798
Michael Hennerich8baf5602007-12-24 18:51:34 +0800799 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
800 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800801 if (gpio_get_value(gpionr))
802 pint[bank]->invert_set = pintbit;
803 else
804 pint[bank]->invert_clear = pintbit;
Michael Hennerich8baf5602007-12-24 18:51:34 +0800805 }
806
807 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
808 pint[bank]->edge_set = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800809 bfin_set_irq_handler(irq, handle_edge_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800810 } else {
811 pint[bank]->edge_clear = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800812 bfin_set_irq_handler(irq, handle_level_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800813 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800814
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800815 return 0;
816}
817
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800818#ifdef CONFIG_PM
819u32 pint_saved_masks[NR_PINT_SYS_IRQS];
820u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
821
822int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
823{
824 u32 pint_irq;
Michael Hennerich8d022372008-11-18 17:48:22 +0800825 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800826 u32 bank = PINT_2_BANK(pint_val);
827 u32 pintbit = PINT_BIT(pint_val);
828
829 switch (bank) {
830 case 0:
831 pint_irq = IRQ_PINT0;
832 break;
833 case 2:
834 pint_irq = IRQ_PINT2;
835 break;
836 case 3:
837 pint_irq = IRQ_PINT3;
838 break;
839 case 1:
840 pint_irq = IRQ_PINT1;
841 break;
842 default:
843 return -EINVAL;
844 }
845
846 bfin_internal_set_wake(pint_irq, state);
847
848 if (state)
849 pint_wakeup_masks[bank] |= pintbit;
850 else
851 pint_wakeup_masks[bank] &= ~pintbit;
852
853 return 0;
854}
855
856u32 bfin_pm_setup(void)
857{
858 u32 val, i;
859
860 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
861 val = pint[i]->mask_clear;
862 pint_saved_masks[i] = val;
863 if (val ^ pint_wakeup_masks[i]) {
864 pint[i]->mask_clear = val;
865 pint[i]->mask_set = pint_wakeup_masks[i];
866 }
867 }
868
869 return 0;
870}
871
872void bfin_pm_restore(void)
873{
874 u32 i, val;
875
876 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
877 val = pint_saved_masks[i];
878 if (val ^ pint_wakeup_masks[i]) {
879 pint[i]->mask_clear = pint[i]->mask_clear;
880 pint[i]->mask_set = val;
881 }
882 }
883}
884#endif
885
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800886static void bfin_demux_gpio_irq(unsigned int inta_irq,
887 struct irq_desc *desc)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800888{
Michael Hennerich8d022372008-11-18 17:48:22 +0800889 u32 bank, pint_val;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800890 u32 request, irq;
891
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800892 switch (inta_irq) {
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800893 case IRQ_PINT0:
894 bank = 0;
895 break;
896 case IRQ_PINT2:
897 bank = 2;
898 break;
899 case IRQ_PINT3:
900 bank = 3;
901 break;
902 case IRQ_PINT1:
903 bank = 1;
904 break;
Michael Henneriche3f23002007-07-12 16:39:29 +0800905 default:
906 return;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800907 }
908
909 pint_val = bank * NR_PINT_BITS;
910
911 request = pint[bank]->request;
912
913 while (request) {
914 if (request & 1) {
Michael Henneriche3f23002007-07-12 16:39:29 +0800915 irq = pint2irq_lut[pint_val] + SYS_IRQS;
Yi Li6a01f232009-01-07 23:14:39 +0800916 bfin_handle_irq(irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800917 }
918 pint_val++;
919 request >>= 1;
920 }
921
922}
Mike Frysingera055b2b2007-11-15 21:12:32 +0800923#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700924
Michael Hennerich8d022372008-11-18 17:48:22 +0800925static struct irq_chip bfin_gpio_irqchip = {
926 .name = "GPIO",
927 .ack = bfin_gpio_ack_irq,
928 .mask = bfin_gpio_mask_irq,
929 .mask_ack = bfin_gpio_mask_ack_irq,
930 .unmask = bfin_gpio_unmask_irq,
931 .disable = bfin_gpio_mask_irq,
932 .enable = bfin_gpio_unmask_irq,
933 .set_type = bfin_gpio_irq_type,
934 .startup = bfin_gpio_irq_startup,
935 .shutdown = bfin_gpio_irq_shutdown,
936#ifdef CONFIG_PM
937 .set_wake = bfin_gpio_set_wake,
938#endif
939};
940
Graf Yang6b3087c2009-01-07 23:14:39 +0800941void __cpuinit init_exception_vectors(void)
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800942{
Mike Frysingerf0b5d122007-08-05 17:03:59 +0800943 /* cannot program in software:
944 * evt0 - emulation (jtag)
945 * evt1 - reset
946 */
947 bfin_write_EVT2(evt_nmi);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800948 bfin_write_EVT3(trap);
949 bfin_write_EVT5(evt_ivhw);
950 bfin_write_EVT6(evt_timer);
951 bfin_write_EVT7(evt_evt7);
952 bfin_write_EVT8(evt_evt8);
953 bfin_write_EVT9(evt_evt9);
954 bfin_write_EVT10(evt_evt10);
955 bfin_write_EVT11(evt_evt11);
956 bfin_write_EVT12(evt_evt12);
957 bfin_write_EVT13(evt_evt13);
Philippe Gerum9703a732009-06-22 18:23:48 +0200958 bfin_write_EVT14(evt_evt14);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800959 bfin_write_EVT15(evt_system_call);
960 CSYNC();
961}
962
Bryan Wu1394f032007-05-06 14:50:22 -0700963/*
964 * This function should be called during kernel startup to initialize
965 * the BFin IRQ handling routines.
966 */
Michael Hennerich8d022372008-11-18 17:48:22 +0800967
Bryan Wu1394f032007-05-06 14:50:22 -0700968int __init init_arch_irq(void)
969{
970 int irq;
971 unsigned long ilat = 0;
972 /* Disable all the peripheral intrs - page 4-29 HW Ref manual */
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800973#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
974 || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
Roy Huang24a07a12007-07-12 22:41:45 +0800975 bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
976 bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +0800977# ifdef CONFIG_BF54x
Michael Hennerich59003142007-10-21 16:54:27 +0800978 bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +0800979# endif
Graf Yang6b3087c2009-01-07 23:14:39 +0800980# ifdef CONFIG_SMP
981 bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);
982 bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);
983# endif
Roy Huang24a07a12007-07-12 22:41:45 +0800984#else
Bryan Wu1394f032007-05-06 14:50:22 -0700985 bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
Roy Huang24a07a12007-07-12 22:41:45 +0800986#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700987
988 local_irq_disable();
989
Mike Frysingerd70536e2008-08-25 17:37:35 +0800990#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
Mike Frysinger95a86b52008-08-14 15:05:01 +0800991 /* Clear EMAC Interrupt Status bits so we can demux it later */
992 bfin_write_EMAC_SYSTAT(-1);
993#endif
994
Mike Frysingera055b2b2007-11-15 21:12:32 +0800995#ifdef CONFIG_BF54x
996# ifdef CONFIG_PINTx_REASSIGN
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800997 pint[0]->assign = CONFIG_PINT0_ASSIGN;
998 pint[1]->assign = CONFIG_PINT1_ASSIGN;
999 pint[2]->assign = CONFIG_PINT2_ASSIGN;
1000 pint[3]->assign = CONFIG_PINT3_ASSIGN;
Mike Frysingera055b2b2007-11-15 21:12:32 +08001001# endif
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001002 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
1003 init_pint_lut();
1004#endif
1005
1006 for (irq = 0; irq <= SYS_IRQS; irq++) {
Bryan Wu1394f032007-05-06 14:50:22 -07001007 if (irq <= IRQ_CORETMR)
1008 set_irq_chip(irq, &bfin_core_irqchip);
1009 else
1010 set_irq_chip(irq, &bfin_internal_irqchip);
Bryan Wu1394f032007-05-06 14:50:22 -07001011
Michael Hennerich464abc52008-02-25 13:50:20 +08001012 switch (irq) {
Michael Hennerich59003142007-10-21 16:54:27 +08001013#if defined(CONFIG_BF53x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001014 case IRQ_PROG_INTA:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001015# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
Michael Hennerich464abc52008-02-25 13:50:20 +08001016 case IRQ_MAC_RX:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001017# endif
Michael Hennerich59003142007-10-21 16:54:27 +08001018#elif defined(CONFIG_BF54x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001019 case IRQ_PINT0:
1020 case IRQ_PINT1:
1021 case IRQ_PINT2:
1022 case IRQ_PINT3:
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001023#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001024 case IRQ_PORTF_INTA:
1025 case IRQ_PORTG_INTA:
1026 case IRQ_PORTH_INTA:
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001027#elif defined(CONFIG_BF561)
Michael Hennerich464abc52008-02-25 13:50:20 +08001028 case IRQ_PROG0_INTA:
1029 case IRQ_PROG1_INTA:
1030 case IRQ_PROG2_INTA:
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001031#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
1032 case IRQ_PORTF_INTA:
Michael Hennerich59003142007-10-21 16:54:27 +08001033#endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001034
Michael Hennerich464abc52008-02-25 13:50:20 +08001035 set_irq_chained_handler(irq,
1036 bfin_demux_gpio_irq);
1037 break;
Bryan Wu1394f032007-05-06 14:50:22 -07001038#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001039 case IRQ_GENERIC_ERROR:
Yi Li6a01f232009-01-07 23:14:39 +08001040 set_irq_chained_handler(irq, bfin_demux_error_irq);
Michael Hennerich464abc52008-02-25 13:50:20 +08001041 break;
1042#endif
Graf Yang179413142009-08-18 04:29:33 +00001043
Graf Yang6b3087c2009-01-07 23:14:39 +08001044#ifdef CONFIG_SMP
Graf Yang179413142009-08-18 04:29:33 +00001045#ifdef CONFIG_TICKSOURCE_GPTMR0
1046 case IRQ_TIMER0:
1047#endif
1048#ifdef CONFIG_TICKSOURCE_CORETMR
1049 case IRQ_CORETMR:
1050#endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001051 case IRQ_SUPPLE_0:
1052 case IRQ_SUPPLE_1:
1053 set_irq_handler(irq, handle_percpu_irq);
1054 break;
1055#endif
Graf Yang179413142009-08-18 04:29:33 +00001056
Yi Li6a01f232009-01-07 23:14:39 +08001057#ifdef CONFIG_IPIPE
Philippe Geruma40494a2009-06-16 05:25:42 +02001058#ifndef CONFIG_TICKSOURCE_CORETMR
1059 case IRQ_TIMER0:
Michael Hennerich464abc52008-02-25 13:50:20 +08001060 set_irq_handler(irq, handle_simple_irq);
1061 break;
Graf Yang179413142009-08-18 04:29:33 +00001062#endif
Philippe Geruma40494a2009-06-16 05:25:42 +02001063 case IRQ_CORETMR:
1064 set_irq_handler(irq, handle_simple_irq);
1065 break;
1066 default:
1067 set_irq_handler(irq, handle_level_irq);
1068 break;
1069#else /* !CONFIG_IPIPE */
Philippe Geruma40494a2009-06-16 05:25:42 +02001070 default:
1071 set_irq_handler(irq, handle_simple_irq);
1072 break;
Graf Yang179413142009-08-18 04:29:33 +00001073#endif /* !CONFIG_IPIPE */
Bryan Wu1394f032007-05-06 14:50:22 -07001074 }
Bryan Wu1394f032007-05-06 14:50:22 -07001075 }
Michael Hennerich464abc52008-02-25 13:50:20 +08001076
Bryan Wu1394f032007-05-06 14:50:22 -07001077#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001078 for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
1079 set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
1080 handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -07001081#endif
1082
Michael Hennerich464abc52008-02-25 13:50:20 +08001083 /* if configured as edge, then will be changed to do_edge_IRQ */
1084 for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
1085 set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
1086 handle_level_irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001087
Mike Frysingera055b2b2007-11-15 21:12:32 +08001088
Bryan Wu1394f032007-05-06 14:50:22 -07001089 bfin_write_IMASK(0);
1090 CSYNC();
1091 ilat = bfin_read_ILAT();
1092 CSYNC();
1093 bfin_write_ILAT(ilat);
1094 CSYNC();
1095
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001096 printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
Mike Frysinger40059782008-11-18 17:48:22 +08001097 /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx,
Bryan Wu1394f032007-05-06 14:50:22 -07001098 * local_irq_enable()
1099 */
1100 program_IAR();
1101 /* Therefore it's better to setup IARs before interrupts enabled */
1102 search_IAR();
1103
1104 /* Enable interrupts IVG7-15 */
Mike Frysinger40059782008-11-18 17:48:22 +08001105 bfin_irq_flags |= IMASK_IVG15 |
Bryan Wu1394f032007-05-06 14:50:22 -07001106 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001107 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
Bryan Wu1394f032007-05-06 14:50:22 -07001108
Michael Hennerich349ebbc2009-04-15 08:48:08 +00001109 /* This implicitly covers ANOMALY_05000171
1110 * Boot-ROM code modifies SICA_IWRx wakeup registers
1111 */
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001112#ifdef SIC_IWR0
Michael Hennerich56f5f592008-08-06 17:55:32 +08001113 bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001114# ifdef SIC_IWR1
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001115 /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which
Michael Hennerich55546ac2008-08-13 17:41:13 +08001116 * will screw up the bootrom as it relies on MDMA0/1 waking it
1117 * up from IDLE instructions. See this report for more info:
1118 * http://blackfin.uclinux.org/gf/tracker/4323
1119 */
Mike Frysingerb7e11292008-11-18 17:48:22 +08001120 if (ANOMALY_05000435)
1121 bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
1122 else
1123 bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001124# endif
1125# ifdef SIC_IWR2
Michael Hennerich56f5f592008-08-06 17:55:32 +08001126 bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001127# endif
1128#else
Michael Hennerich56f5f592008-08-06 17:55:32 +08001129 bfin_write_SIC_IWR(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001130#endif
1131
Bryan Wu1394f032007-05-06 14:50:22 -07001132 return 0;
1133}
1134
1135#ifdef CONFIG_DO_IRQ_L1
Mike Frysingera055b2b2007-11-15 21:12:32 +08001136__attribute__((l1_text))
Bryan Wu1394f032007-05-06 14:50:22 -07001137#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001138void do_irq(int vec, struct pt_regs *fp)
1139{
1140 if (vec == EVT_IVTMR_P) {
1141 vec = IRQ_CORETMR;
1142 } else {
1143 struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
1144 struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
Mike Frysinger780172b2009-06-01 19:43:02 -04001145#if defined(SIC_ISR0) || defined(SICA_ISR0)
Roy Huang24a07a12007-07-12 22:41:45 +08001146 unsigned long sic_status[3];
Bryan Wu1394f032007-05-06 14:50:22 -07001147
Graf Yang6b3087c2009-01-07 23:14:39 +08001148 if (smp_processor_id()) {
Mike Frysinger780172b2009-06-01 19:43:02 -04001149# ifdef SICB_ISR0
Graf Yang6b3087c2009-01-07 23:14:39 +08001150 /* This will be optimized out in UP mode. */
1151 sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
1152 sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001153# endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001154 } else {
1155 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1156 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
1157 }
Mike Frysinger780172b2009-06-01 19:43:02 -04001158# ifdef SIC_ISR2
Michael Hennerich4fb45242007-10-21 16:53:53 +08001159 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001160# endif
Mike Frysinger1f83b8f2007-07-12 22:58:21 +08001161 for (;; ivg++) {
Roy Huang24a07a12007-07-12 22:41:45 +08001162 if (ivg >= ivg_stop) {
1163 atomic_inc(&num_spurious);
1164 return;
1165 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001166 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
Roy Huang24a07a12007-07-12 22:41:45 +08001167 break;
1168 }
1169#else
1170 unsigned long sic_status;
Michael Hennerich464abc52008-02-25 13:50:20 +08001171
Bryan Wu1394f032007-05-06 14:50:22 -07001172 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1173
1174 for (;; ivg++) {
1175 if (ivg >= ivg_stop) {
1176 atomic_inc(&num_spurious);
1177 return;
1178 } else if (sic_status & ivg->isrflag)
1179 break;
1180 }
Roy Huang24a07a12007-07-12 22:41:45 +08001181#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001182 vec = ivg->irqno;
1183 }
1184 asm_do_IRQ(vec, fp);
Bryan Wu1394f032007-05-06 14:50:22 -07001185}
Yi Li6a01f232009-01-07 23:14:39 +08001186
1187#ifdef CONFIG_IPIPE
1188
1189int __ipipe_get_irq_priority(unsigned irq)
1190{
1191 int ient, prio;
1192
1193 if (irq <= IRQ_CORETMR)
1194 return irq;
1195
1196 for (ient = 0; ient < NR_PERI_INTS; ient++) {
1197 struct ivgx *ivg = ivg_table + ient;
1198 if (ivg->irqno == irq) {
1199 for (prio = 0; prio <= IVG13-IVG7; prio++) {
1200 if (ivg7_13[prio].ifirst <= ivg &&
1201 ivg7_13[prio].istop > ivg)
1202 return IVG7 + prio;
1203 }
1204 }
1205 }
1206
1207 return IVG15;
1208}
1209
Yi Li6a01f232009-01-07 23:14:39 +08001210/* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */
1211#ifdef CONFIG_DO_IRQ_L1
1212__attribute__((l1_text))
1213#endif
1214asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
1215{
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001216 struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr();
Philippe Geruma40494a2009-06-16 05:25:42 +02001217 struct ipipe_domain *this_domain = __ipipe_current_domain;
Yi Li6a01f232009-01-07 23:14:39 +08001218 struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
1219 struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001220 int irq, s;
Yi Li6a01f232009-01-07 23:14:39 +08001221
Philippe Geruma40494a2009-06-16 05:25:42 +02001222 if (likely(vec == EVT_IVTMR_P))
Yi Li6a01f232009-01-07 23:14:39 +08001223 irq = IRQ_CORETMR;
Philippe Geruma40494a2009-06-16 05:25:42 +02001224 else {
Mike Frysinger780172b2009-06-01 19:43:02 -04001225#if defined(SIC_ISR0) || defined(SICA_ISR0)
Yi Li6a01f232009-01-07 23:14:39 +08001226 unsigned long sic_status[3];
1227
1228 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1229 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001230# ifdef SIC_ISR2
Yi Li6a01f232009-01-07 23:14:39 +08001231 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001232# endif
Yi Li6a01f232009-01-07 23:14:39 +08001233 for (;; ivg++) {
1234 if (ivg >= ivg_stop) {
1235 atomic_inc(&num_spurious);
1236 return 0;
1237 }
1238 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
1239 break;
1240 }
Yi Li6a01f232009-01-07 23:14:39 +08001241#else
Yi Li6a01f232009-01-07 23:14:39 +08001242 unsigned long sic_status;
1243
1244 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1245
1246 for (;; ivg++) {
1247 if (ivg >= ivg_stop) {
1248 atomic_inc(&num_spurious);
1249 return 0;
1250 } else if (sic_status & ivg->isrflag)
1251 break;
1252 }
Yi Li6a01f232009-01-07 23:14:39 +08001253#endif
Graf Yang1fa9be72009-05-15 11:01:59 +00001254 irq = ivg->irqno;
1255 }
Yi Li6a01f232009-01-07 23:14:39 +08001256
1257 if (irq == IRQ_SYSTMR) {
Philippe Geruma40494a2009-06-16 05:25:42 +02001258#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
Yi Li6a01f232009-01-07 23:14:39 +08001259 bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001260#endif
Yi Li6a01f232009-01-07 23:14:39 +08001261 /* This is basically what we need from the register frame. */
1262 __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend;
1263 __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001264 if (this_domain != ipipe_root_domain)
Yi Li6a01f232009-01-07 23:14:39 +08001265 __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001266 else
1267 __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
Yi Li6a01f232009-01-07 23:14:39 +08001268 }
1269
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001270 if (this_domain == ipipe_root_domain) {
1271 s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1272 barrier();
1273 }
Yi Li6a01f232009-01-07 23:14:39 +08001274
1275 ipipe_trace_irq_entry(irq);
1276 __ipipe_handle_irq(irq, regs);
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001277 ipipe_trace_irq_exit(irq);
Yi Li6a01f232009-01-07 23:14:39 +08001278
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001279 if (this_domain == ipipe_root_domain) {
1280 set_thread_flag(TIF_IRQ_SYNC);
1281 if (!s) {
1282 __clear_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1283 return !test_bit(IPIPE_STALL_FLAG, &p->status);
1284 }
1285 }
Yi Li6a01f232009-01-07 23:14:39 +08001286
Graf Yang1fa9be72009-05-15 11:01:59 +00001287 return 0;
Yi Li6a01f232009-01-07 23:14:39 +08001288}
1289
1290#endif /* CONFIG_IPIPE */