blob: a5d243409d23683008313dedd29e547da6f7f6cb [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
Sonic Zhang0325f252009-12-28 07:29:57 +0000176#ifdef CONFIG_SMP
177static void bfin_internal_unmask_irq_affinity(unsigned int irq,
178 const struct cpumask *affinity)
179#else
Bryan Wu1394f032007-05-06 14:50:22 -0700180static void bfin_internal_unmask_irq(unsigned int irq)
Sonic Zhang0325f252009-12-28 07:29:57 +0000181#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700182{
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800183 unsigned long flags;
184
Michael Hennerich59003142007-10-21 16:54:27 +0800185#ifdef CONFIG_BF53x
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800186 local_irq_save_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700187 bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
Michael Hennerich464abc52008-02-25 13:50:20 +0800188 (1 << SIC_SYSIRQ(irq)));
Roy Huang24a07a12007-07-12 22:41:45 +0800189#else
190 unsigned mask_bank, mask_bit;
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800191 local_irq_save_hw(flags);
Michael Hennerich464abc52008-02-25 13:50:20 +0800192 mask_bank = SIC_SYSIRQ(irq) / 32;
193 mask_bit = SIC_SYSIRQ(irq) % 32;
Graf Yang6b3087c2009-01-07 23:14:39 +0800194#ifdef CONFIG_SMP
Sonic Zhang0325f252009-12-28 07:29:57 +0000195 if (cpumask_test_cpu(0, affinity))
196#endif
197 bfin_write_SIC_IMASK(mask_bank,
198 bfin_read_SIC_IMASK(mask_bank) |
199 (1 << mask_bit));
200#ifdef CONFIG_SMP
201 if (cpumask_test_cpu(1, affinity))
202 bfin_write_SICB_IMASK(mask_bank,
203 bfin_read_SICB_IMASK(mask_bank) |
204 (1 << mask_bit));
Graf Yang6b3087c2009-01-07 23:14:39 +0800205#endif
Roy Huang24a07a12007-07-12 22:41:45 +0800206#endif
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800207 local_irq_restore_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700208}
209
Sonic Zhang0325f252009-12-28 07:29:57 +0000210#ifdef CONFIG_SMP
211static void bfin_internal_unmask_irq(unsigned int irq)
212{
213 struct irq_desc *desc = irq_to_desc(irq);
214 bfin_internal_unmask_irq_affinity(irq, desc->affinity);
215}
216
217static int bfin_internal_set_affinity(unsigned int irq, const struct cpumask *mask)
218{
219 bfin_internal_mask_irq(irq);
220 bfin_internal_unmask_irq_affinity(irq, mask);
221
222 return 0;
223}
224#endif
225
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800226#ifdef CONFIG_PM
227int bfin_internal_set_wake(unsigned int irq, unsigned int state)
228{
Michael Hennerich8d022372008-11-18 17:48:22 +0800229 u32 bank, bit, wakeup = 0;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800230 unsigned long flags;
Michael Hennerich464abc52008-02-25 13:50:20 +0800231 bank = SIC_SYSIRQ(irq) / 32;
232 bit = SIC_SYSIRQ(irq) % 32;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800233
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800234 switch (irq) {
235#ifdef IRQ_RTC
236 case IRQ_RTC:
237 wakeup |= WAKE;
238 break;
239#endif
240#ifdef IRQ_CAN0_RX
241 case IRQ_CAN0_RX:
242 wakeup |= CANWE;
243 break;
244#endif
245#ifdef IRQ_CAN1_RX
246 case IRQ_CAN1_RX:
247 wakeup |= CANWE;
248 break;
249#endif
250#ifdef IRQ_USB_INT0
251 case IRQ_USB_INT0:
252 wakeup |= USBWE;
253 break;
254#endif
255#ifdef IRQ_KEY
256 case IRQ_KEY:
257 wakeup |= KPADWE;
258 break;
259#endif
Michael Hennerichd310fb42008-08-28 17:32:01 +0800260#ifdef CONFIG_BF54x
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800261 case IRQ_CNT:
262 wakeup |= ROTWE;
263 break;
264#endif
265 default:
266 break;
267 }
268
Yi Li6a01f232009-01-07 23:14:39 +0800269 local_irq_save_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800270
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800271 if (state) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800272 bfin_sic_iwr[bank] |= (1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800273 vr_wakeup |= wakeup;
274
275 } else {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800276 bfin_sic_iwr[bank] &= ~(1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800277 vr_wakeup &= ~wakeup;
278 }
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800279
Yi Li6a01f232009-01-07 23:14:39 +0800280 local_irq_restore_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800281
282 return 0;
283}
284#endif
285
Bryan Wu1394f032007-05-06 14:50:22 -0700286static struct irq_chip bfin_core_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800287 .name = "CORE",
Michael Hennerich464abc52008-02-25 13:50:20 +0800288 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700289 .mask = bfin_core_mask_irq,
290 .unmask = bfin_core_unmask_irq,
291};
292
293static struct irq_chip bfin_internal_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800294 .name = "INTN",
Michael Hennerich464abc52008-02-25 13:50:20 +0800295 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700296 .mask = bfin_internal_mask_irq,
297 .unmask = bfin_internal_unmask_irq,
Michael Hennerichce3b7bb2008-02-25 13:48:47 +0800298 .mask_ack = bfin_internal_mask_irq,
299 .disable = bfin_internal_mask_irq,
300 .enable = bfin_internal_unmask_irq,
Sonic Zhang0325f252009-12-28 07:29:57 +0000301#ifdef CONFIG_SMP
302 .set_affinity = bfin_internal_set_affinity,
303#endif
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800304#ifdef CONFIG_PM
305 .set_wake = bfin_internal_set_wake,
306#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700307};
308
Yi Li6a01f232009-01-07 23:14:39 +0800309static void bfin_handle_irq(unsigned irq)
310{
311#ifdef CONFIG_IPIPE
312 struct pt_regs regs; /* Contents not used. */
313 ipipe_trace_irq_entry(irq);
314 __ipipe_handle_irq(irq, &regs);
315 ipipe_trace_irq_exit(irq);
316#else /* !CONFIG_IPIPE */
317 struct irq_desc *desc = irq_desc + irq;
318 desc->handle_irq(irq, desc);
319#endif /* !CONFIG_IPIPE */
320}
321
Bryan Wu1394f032007-05-06 14:50:22 -0700322#ifdef BF537_GENERIC_ERROR_INT_DEMUX
323static int error_int_mask;
324
Bryan Wu1394f032007-05-06 14:50:22 -0700325static void bfin_generic_error_mask_irq(unsigned int irq)
326{
327 error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
328
Michael Hennerich464abc52008-02-25 13:50:20 +0800329 if (!error_int_mask)
330 bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700331}
332
333static void bfin_generic_error_unmask_irq(unsigned int irq)
334{
Michael Hennerich464abc52008-02-25 13:50:20 +0800335 bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700336 error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
337}
338
339static struct irq_chip bfin_generic_error_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800340 .name = "ERROR",
Michael Hennerich464abc52008-02-25 13:50:20 +0800341 .ack = bfin_ack_noop,
342 .mask_ack = bfin_generic_error_mask_irq,
Bryan Wu1394f032007-05-06 14:50:22 -0700343 .mask = bfin_generic_error_mask_irq,
344 .unmask = bfin_generic_error_unmask_irq,
345};
346
347static void bfin_demux_error_irq(unsigned int int_err_irq,
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800348 struct irq_desc *inta_desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700349{
350 int irq = 0;
351
Bryan Wu1394f032007-05-06 14:50:22 -0700352#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
353 if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
354 irq = IRQ_MAC_ERROR;
355 else
356#endif
357 if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
358 irq = IRQ_SPORT0_ERROR;
359 else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
360 irq = IRQ_SPORT1_ERROR;
361 else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
362 irq = IRQ_PPI_ERROR;
363 else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
364 irq = IRQ_CAN_ERROR;
365 else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
366 irq = IRQ_SPI_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000367 else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700368 irq = IRQ_UART0_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000369 else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700370 irq = IRQ_UART1_ERROR;
371
372 if (irq) {
Yi Li6a01f232009-01-07 23:14:39 +0800373 if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
374 bfin_handle_irq(irq);
375 else {
Bryan Wu1394f032007-05-06 14:50:22 -0700376
377 switch (irq) {
378 case IRQ_PPI_ERROR:
379 bfin_write_PPI_STATUS(PPI_ERR_MASK);
380 break;
381#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
382 case IRQ_MAC_ERROR:
383 bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
384 break;
385#endif
386 case IRQ_SPORT0_ERROR:
387 bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
388 break;
389
390 case IRQ_SPORT1_ERROR:
391 bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
392 break;
393
394 case IRQ_CAN_ERROR:
395 bfin_write_CAN_GIS(CAN_ERR_MASK);
396 break;
397
398 case IRQ_SPI_ERROR:
399 bfin_write_SPI_STAT(SPI_ERR_MASK);
400 break;
401
402 default:
403 break;
404 }
405
406 pr_debug("IRQ %d:"
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800407 " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
408 irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700409 }
410 } else
411 printk(KERN_ERR
412 "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
413 " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
Harvey Harrisonb85d8582008-04-23 09:39:01 +0800414 __func__, __FILE__, __LINE__);
Bryan Wu1394f032007-05-06 14:50:22 -0700415
Bryan Wu1394f032007-05-06 14:50:22 -0700416}
417#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
418
Graf Yangbfd15112008-10-08 18:02:44 +0800419static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
420{
Yi Li6a01f232009-01-07 23:14:39 +0800421#ifdef CONFIG_IPIPE
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800422 _set_irq_handler(irq, handle_level_irq);
Yi Li6a01f232009-01-07 23:14:39 +0800423#else
Graf Yangbfd15112008-10-08 18:02:44 +0800424 struct irq_desc *desc = irq_desc + irq;
425 /* May not call generic set_irq_handler() due to spinlock
426 recursion. */
427 desc->handle_irq = handle;
Yi Li6a01f232009-01-07 23:14:39 +0800428#endif
Graf Yangbfd15112008-10-08 18:02:44 +0800429}
430
Michael Hennerich8d022372008-11-18 17:48:22 +0800431static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800432extern void bfin_gpio_irq_prepare(unsigned gpio);
Michael Hennerich6fce6a82007-12-24 16:56:12 +0800433
Michael Hennerich8d022372008-11-18 17:48:22 +0800434#if !defined(CONFIG_BF54x)
435
Bryan Wu1394f032007-05-06 14:50:22 -0700436static void bfin_gpio_ack_irq(unsigned int irq)
437{
Michael Hennerich8d022372008-11-18 17:48:22 +0800438 /* AFAIK ack_irq in case mask_ack is provided
439 * get's only called for edge sense irqs
440 */
441 set_gpio_data(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700442}
443
444static void bfin_gpio_mask_ack_irq(unsigned int irq)
445{
Michael Hennerich8d022372008-11-18 17:48:22 +0800446 struct irq_desc *desc = irq_desc + irq;
447 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700448
Michael Hennerich8d022372008-11-18 17:48:22 +0800449 if (desc->handle_irq == handle_edge_irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700450 set_gpio_data(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700451
452 set_gpio_maska(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700453}
454
455static void bfin_gpio_mask_irq(unsigned int irq)
456{
Michael Hennerich8d022372008-11-18 17:48:22 +0800457 set_gpio_maska(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700458}
459
460static void bfin_gpio_unmask_irq(unsigned int irq)
461{
Michael Hennerich8d022372008-11-18 17:48:22 +0800462 set_gpio_maska(irq_to_gpio(irq), 1);
Bryan Wu1394f032007-05-06 14:50:22 -0700463}
464
465static unsigned int bfin_gpio_irq_startup(unsigned int irq)
466{
Michael Hennerich8d022372008-11-18 17:48:22 +0800467 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700468
Michael Hennerich8d022372008-11-18 17:48:22 +0800469 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800470 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700471
Bryan Wu1394f032007-05-06 14:50:22 -0700472 bfin_gpio_unmask_irq(irq);
473
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800474 return 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700475}
476
477static void bfin_gpio_irq_shutdown(unsigned int irq)
478{
Graf Yang30af6d42008-11-18 17:48:21 +0800479 u32 gpionr = irq_to_gpio(irq);
480
Bryan Wu1394f032007-05-06 14:50:22 -0700481 bfin_gpio_mask_irq(irq);
Graf Yang30af6d42008-11-18 17:48:21 +0800482 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800483 bfin_gpio_irq_free(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700484}
485
486static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
487{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800488 int ret;
489 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800490 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700491
492 if (type == IRQ_TYPE_PROBE) {
493 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400494 if (test_bit(gpionr, gpio_enabled))
Bryan Wu1394f032007-05-06 14:50:22 -0700495 return 0;
496 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
497 }
498
499 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800500 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Michael Hennerich8d022372008-11-18 17:48:22 +0800501
Graf Yang9570ff42009-01-07 23:14:38 +0800502 snprintf(buf, 16, "gpio-irq%d", irq);
503 ret = bfin_gpio_irq_request(gpionr, buf);
504 if (ret)
505 return ret;
506
Michael Hennerich8d022372008-11-18 17:48:22 +0800507 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800508 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700509
Bryan Wu1394f032007-05-06 14:50:22 -0700510 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800511 __clear_bit(gpionr, gpio_enabled);
Bryan Wu1394f032007-05-06 14:50:22 -0700512 return 0;
513 }
514
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800515 set_gpio_inen(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700516 set_gpio_dir(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700517
518 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
519 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
520 set_gpio_both(gpionr, 1);
521 else
522 set_gpio_both(gpionr, 0);
523
524 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
525 set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
526 else
527 set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
528
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800529 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
530 set_gpio_edge(gpionr, 1);
531 set_gpio_inen(gpionr, 1);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800532 set_gpio_data(gpionr, 0);
533
534 } else {
535 set_gpio_edge(gpionr, 0);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800536 set_gpio_inen(gpionr, 1);
537 }
538
Bryan Wu1394f032007-05-06 14:50:22 -0700539 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
Graf Yangbfd15112008-10-08 18:02:44 +0800540 bfin_set_irq_handler(irq, handle_edge_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700541 else
Graf Yangbfd15112008-10-08 18:02:44 +0800542 bfin_set_irq_handler(irq, handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700543
544 return 0;
545}
546
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800547#ifdef CONFIG_PM
548int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
549{
550 unsigned gpio = irq_to_gpio(irq);
551
552 if (state)
553 gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE);
554 else
555 gpio_pm_wakeup_free(gpio);
556
557 return 0;
558}
559#endif
560
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800561static void bfin_demux_gpio_irq(unsigned int inta_irq,
562 struct irq_desc *desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700563{
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800564 unsigned int i, gpio, mask, irq, search = 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700565
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800566 switch (inta_irq) {
567#if defined(CONFIG_BF53x)
568 case IRQ_PROG_INTA:
569 irq = IRQ_PF0;
570 search = 1;
571 break;
572# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
573 case IRQ_MAC_RX:
574 irq = IRQ_PH0;
575 break;
576# endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800577#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
578 case IRQ_PORTF_INTA:
579 irq = IRQ_PF0;
580 break;
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800581#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800582 case IRQ_PORTF_INTA:
583 irq = IRQ_PF0;
584 break;
585 case IRQ_PORTG_INTA:
586 irq = IRQ_PG0;
587 break;
588 case IRQ_PORTH_INTA:
589 irq = IRQ_PH0;
590 break;
591#elif defined(CONFIG_BF561)
592 case IRQ_PROG0_INTA:
593 irq = IRQ_PF0;
594 break;
595 case IRQ_PROG1_INTA:
596 irq = IRQ_PF16;
597 break;
598 case IRQ_PROG2_INTA:
599 irq = IRQ_PF32;
600 break;
601#endif
602 default:
603 BUG();
604 return;
Bryan Wu1394f032007-05-06 14:50:22 -0700605 }
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800606
607 if (search) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800608 for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800609 irq += i;
610
Michael Hennerich8d022372008-11-18 17:48:22 +0800611 mask = get_gpiop_data(i) & get_gpiop_maska(i);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800612
613 while (mask) {
Yi Li6a01f232009-01-07 23:14:39 +0800614 if (mask & 1)
615 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800616 irq++;
617 mask >>= 1;
618 }
619 }
620 } else {
621 gpio = irq_to_gpio(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800622 mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800623
624 do {
Yi Li6a01f232009-01-07 23:14:39 +0800625 if (mask & 1)
626 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800627 irq++;
628 mask >>= 1;
629 } while (mask);
630 }
631
Bryan Wu1394f032007-05-06 14:50:22 -0700632}
633
Mike Frysingera055b2b2007-11-15 21:12:32 +0800634#else /* CONFIG_BF54x */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800635
636#define NR_PINT_SYS_IRQS 4
637#define NR_PINT_BITS 32
638#define NR_PINTS 160
639#define IRQ_NOT_AVAIL 0xFF
640
641#define PINT_2_BANK(x) ((x) >> 5)
642#define PINT_2_BIT(x) ((x) & 0x1F)
643#define PINT_BIT(x) (1 << (PINT_2_BIT(x)))
644
645static unsigned char irq2pint_lut[NR_PINTS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800646static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800647
648struct pin_int_t {
649 unsigned int mask_set;
650 unsigned int mask_clear;
651 unsigned int request;
652 unsigned int assign;
653 unsigned int edge_set;
654 unsigned int edge_clear;
655 unsigned int invert_set;
656 unsigned int invert_clear;
657 unsigned int pinstate;
658 unsigned int latch;
659};
660
661static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
662 (struct pin_int_t *)PINT0_MASK_SET,
663 (struct pin_int_t *)PINT1_MASK_SET,
664 (struct pin_int_t *)PINT2_MASK_SET,
665 (struct pin_int_t *)PINT3_MASK_SET,
666};
667
Michael Hennerich8d022372008-11-18 17:48:22 +0800668inline unsigned int get_irq_base(u32 bank, u8 bmap)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800669{
Michael Hennerich8d022372008-11-18 17:48:22 +0800670 unsigned int irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800671
672 if (bank < 2) { /*PA-PB */
673 irq_base = IRQ_PA0 + bmap * 16;
674 } else { /*PC-PJ */
675 irq_base = IRQ_PC0 + bmap * 16;
676 }
677
678 return irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800679}
680
681 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
682void init_pint_lut(void)
683{
684 u16 bank, bit, irq_base, bit_pos;
685 u32 pint_assign;
686 u8 bmap;
687
688 memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut));
689
690 for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) {
691
692 pint_assign = pint[bank]->assign;
693
694 for (bit = 0; bit < NR_PINT_BITS; bit++) {
695
696 bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF;
697
698 irq_base = get_irq_base(bank, bmap);
699
700 irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0);
701 bit_pos = bit + bank * NR_PINT_BITS;
702
Michael Henneriche3f23002007-07-12 16:39:29 +0800703 pint2irq_lut[bit_pos] = irq_base - SYS_IRQS;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800704 irq2pint_lut[irq_base - SYS_IRQS] = bit_pos;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800705 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800706 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800707}
708
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800709static void bfin_gpio_ack_irq(unsigned int irq)
710{
Michael Hennerich8d022372008-11-18 17:48:22 +0800711 struct irq_desc *desc = irq_desc + irq;
712 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich8baf5602007-12-24 18:51:34 +0800713 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800714 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800715
Michael Hennerich8d022372008-11-18 17:48:22 +0800716 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800717 if (pint[bank]->invert_set & pintbit)
718 pint[bank]->invert_clear = pintbit;
719 else
720 pint[bank]->invert_set = pintbit;
721 }
722 pint[bank]->request = pintbit;
723
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800724}
725
726static void bfin_gpio_mask_ack_irq(unsigned int irq)
727{
Michael Hennerich8d022372008-11-18 17:48:22 +0800728 struct irq_desc *desc = irq_desc + irq;
729 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800730 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800731 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800732
Michael Hennerich8d022372008-11-18 17:48:22 +0800733 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800734 if (pint[bank]->invert_set & pintbit)
735 pint[bank]->invert_clear = pintbit;
736 else
737 pint[bank]->invert_set = pintbit;
738 }
739
Michael Henneriche3f23002007-07-12 16:39:29 +0800740 pint[bank]->request = pintbit;
741 pint[bank]->mask_clear = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800742}
743
744static void bfin_gpio_mask_irq(unsigned int irq)
745{
Michael Hennerich8d022372008-11-18 17:48:22 +0800746 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800747
748 pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800749}
750
751static void bfin_gpio_unmask_irq(unsigned int irq)
752{
Michael Hennerich8d022372008-11-18 17:48:22 +0800753 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800754 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800755 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800756
Michael Henneriche3f23002007-07-12 16:39:29 +0800757 pint[bank]->request = pintbit;
758 pint[bank]->mask_set = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800759}
760
761static unsigned int bfin_gpio_irq_startup(unsigned int irq)
762{
Michael Hennerich8d022372008-11-18 17:48:22 +0800763 u32 gpionr = irq_to_gpio(irq);
764 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800765
Michael Hennerich50e163c2007-07-24 16:17:28 +0800766 if (pint_val == IRQ_NOT_AVAIL) {
767 printk(KERN_ERR
768 "GPIO IRQ %d :Not in PINT Assign table "
769 "Reconfigure Interrupt to Port Assignemt\n", irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800770 return -ENODEV;
Michael Hennerich50e163c2007-07-24 16:17:28 +0800771 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800772
Michael Hennerich8d022372008-11-18 17:48:22 +0800773 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800774 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800775
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800776 bfin_gpio_unmask_irq(irq);
777
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800778 return 0;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800779}
780
781static void bfin_gpio_irq_shutdown(unsigned int irq)
782{
Michael Hennerich8d022372008-11-18 17:48:22 +0800783 u32 gpionr = irq_to_gpio(irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800784
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800785 bfin_gpio_mask_irq(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800786 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800787 bfin_gpio_irq_free(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800788}
789
790static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
791{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800792 int ret;
793 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800794 u32 gpionr = irq_to_gpio(irq);
795 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800796 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800797 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800798
799 if (pint_val == IRQ_NOT_AVAIL)
800 return -ENODEV;
801
802 if (type == IRQ_TYPE_PROBE) {
803 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400804 if (test_bit(gpionr, gpio_enabled))
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800805 return 0;
806 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
807 }
808
809 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
810 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Graf Yang9570ff42009-01-07 23:14:38 +0800811
812 snprintf(buf, 16, "gpio-irq%d", irq);
813 ret = bfin_gpio_irq_request(gpionr, buf);
814 if (ret)
815 return ret;
816
Michael Hennerich8d022372008-11-18 17:48:22 +0800817 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800818 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800819
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800820 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800821 __clear_bit(gpionr, gpio_enabled);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800822 return 0;
823 }
824
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800825 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
Michael Henneriche3f23002007-07-12 16:39:29 +0800826 pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800827 else
Michael Hennerich8baf5602007-12-24 18:51:34 +0800828 pint[bank]->invert_clear = pintbit; /* high or rising edge denoted by zero */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800829
Michael Hennerich8baf5602007-12-24 18:51:34 +0800830 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
831 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800832 if (gpio_get_value(gpionr))
833 pint[bank]->invert_set = pintbit;
834 else
835 pint[bank]->invert_clear = pintbit;
Michael Hennerich8baf5602007-12-24 18:51:34 +0800836 }
837
838 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
839 pint[bank]->edge_set = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800840 bfin_set_irq_handler(irq, handle_edge_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800841 } else {
842 pint[bank]->edge_clear = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800843 bfin_set_irq_handler(irq, handle_level_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800844 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800845
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800846 return 0;
847}
848
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800849#ifdef CONFIG_PM
850u32 pint_saved_masks[NR_PINT_SYS_IRQS];
851u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
852
853int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
854{
855 u32 pint_irq;
Michael Hennerich8d022372008-11-18 17:48:22 +0800856 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800857 u32 bank = PINT_2_BANK(pint_val);
858 u32 pintbit = PINT_BIT(pint_val);
859
860 switch (bank) {
861 case 0:
862 pint_irq = IRQ_PINT0;
863 break;
864 case 2:
865 pint_irq = IRQ_PINT2;
866 break;
867 case 3:
868 pint_irq = IRQ_PINT3;
869 break;
870 case 1:
871 pint_irq = IRQ_PINT1;
872 break;
873 default:
874 return -EINVAL;
875 }
876
877 bfin_internal_set_wake(pint_irq, state);
878
879 if (state)
880 pint_wakeup_masks[bank] |= pintbit;
881 else
882 pint_wakeup_masks[bank] &= ~pintbit;
883
884 return 0;
885}
886
887u32 bfin_pm_setup(void)
888{
889 u32 val, i;
890
891 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
892 val = pint[i]->mask_clear;
893 pint_saved_masks[i] = val;
894 if (val ^ pint_wakeup_masks[i]) {
895 pint[i]->mask_clear = val;
896 pint[i]->mask_set = pint_wakeup_masks[i];
897 }
898 }
899
900 return 0;
901}
902
903void bfin_pm_restore(void)
904{
905 u32 i, val;
906
907 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
908 val = pint_saved_masks[i];
909 if (val ^ pint_wakeup_masks[i]) {
910 pint[i]->mask_clear = pint[i]->mask_clear;
911 pint[i]->mask_set = val;
912 }
913 }
914}
915#endif
916
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800917static void bfin_demux_gpio_irq(unsigned int inta_irq,
918 struct irq_desc *desc)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800919{
Michael Hennerich8d022372008-11-18 17:48:22 +0800920 u32 bank, pint_val;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800921 u32 request, irq;
922
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800923 switch (inta_irq) {
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800924 case IRQ_PINT0:
925 bank = 0;
926 break;
927 case IRQ_PINT2:
928 bank = 2;
929 break;
930 case IRQ_PINT3:
931 bank = 3;
932 break;
933 case IRQ_PINT1:
934 bank = 1;
935 break;
Michael Henneriche3f23002007-07-12 16:39:29 +0800936 default:
937 return;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800938 }
939
940 pint_val = bank * NR_PINT_BITS;
941
942 request = pint[bank]->request;
943
944 while (request) {
945 if (request & 1) {
Michael Henneriche3f23002007-07-12 16:39:29 +0800946 irq = pint2irq_lut[pint_val] + SYS_IRQS;
Yi Li6a01f232009-01-07 23:14:39 +0800947 bfin_handle_irq(irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800948 }
949 pint_val++;
950 request >>= 1;
951 }
952
953}
Mike Frysingera055b2b2007-11-15 21:12:32 +0800954#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700955
Michael Hennerich8d022372008-11-18 17:48:22 +0800956static struct irq_chip bfin_gpio_irqchip = {
957 .name = "GPIO",
958 .ack = bfin_gpio_ack_irq,
959 .mask = bfin_gpio_mask_irq,
960 .mask_ack = bfin_gpio_mask_ack_irq,
961 .unmask = bfin_gpio_unmask_irq,
962 .disable = bfin_gpio_mask_irq,
963 .enable = bfin_gpio_unmask_irq,
964 .set_type = bfin_gpio_irq_type,
965 .startup = bfin_gpio_irq_startup,
966 .shutdown = bfin_gpio_irq_shutdown,
967#ifdef CONFIG_PM
968 .set_wake = bfin_gpio_set_wake,
969#endif
970};
971
Graf Yang6b3087c2009-01-07 23:14:39 +0800972void __cpuinit init_exception_vectors(void)
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800973{
Mike Frysingerf0b5d122007-08-05 17:03:59 +0800974 /* cannot program in software:
975 * evt0 - emulation (jtag)
976 * evt1 - reset
977 */
978 bfin_write_EVT2(evt_nmi);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800979 bfin_write_EVT3(trap);
980 bfin_write_EVT5(evt_ivhw);
981 bfin_write_EVT6(evt_timer);
982 bfin_write_EVT7(evt_evt7);
983 bfin_write_EVT8(evt_evt8);
984 bfin_write_EVT9(evt_evt9);
985 bfin_write_EVT10(evt_evt10);
986 bfin_write_EVT11(evt_evt11);
987 bfin_write_EVT12(evt_evt12);
988 bfin_write_EVT13(evt_evt13);
Philippe Gerum9703a732009-06-22 18:23:48 +0200989 bfin_write_EVT14(evt_evt14);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800990 bfin_write_EVT15(evt_system_call);
991 CSYNC();
992}
993
Bryan Wu1394f032007-05-06 14:50:22 -0700994/*
995 * This function should be called during kernel startup to initialize
996 * the BFin IRQ handling routines.
997 */
Michael Hennerich8d022372008-11-18 17:48:22 +0800998
Bryan Wu1394f032007-05-06 14:50:22 -0700999int __init init_arch_irq(void)
1000{
1001 int irq;
1002 unsigned long ilat = 0;
1003 /* Disable all the peripheral intrs - page 4-29 HW Ref manual */
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001004#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
1005 || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
Roy Huang24a07a12007-07-12 22:41:45 +08001006 bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
1007 bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +08001008# ifdef CONFIG_BF54x
Michael Hennerich59003142007-10-21 16:54:27 +08001009 bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +08001010# endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001011# ifdef CONFIG_SMP
1012 bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);
1013 bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);
1014# endif
Roy Huang24a07a12007-07-12 22:41:45 +08001015#else
Bryan Wu1394f032007-05-06 14:50:22 -07001016 bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
Roy Huang24a07a12007-07-12 22:41:45 +08001017#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001018
1019 local_irq_disable();
1020
Mike Frysingerd70536e2008-08-25 17:37:35 +08001021#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
Mike Frysinger95a86b52008-08-14 15:05:01 +08001022 /* Clear EMAC Interrupt Status bits so we can demux it later */
1023 bfin_write_EMAC_SYSTAT(-1);
1024#endif
1025
Mike Frysingera055b2b2007-11-15 21:12:32 +08001026#ifdef CONFIG_BF54x
1027# ifdef CONFIG_PINTx_REASSIGN
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001028 pint[0]->assign = CONFIG_PINT0_ASSIGN;
1029 pint[1]->assign = CONFIG_PINT1_ASSIGN;
1030 pint[2]->assign = CONFIG_PINT2_ASSIGN;
1031 pint[3]->assign = CONFIG_PINT3_ASSIGN;
Mike Frysingera055b2b2007-11-15 21:12:32 +08001032# endif
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001033 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
1034 init_pint_lut();
1035#endif
1036
1037 for (irq = 0; irq <= SYS_IRQS; irq++) {
Bryan Wu1394f032007-05-06 14:50:22 -07001038 if (irq <= IRQ_CORETMR)
1039 set_irq_chip(irq, &bfin_core_irqchip);
1040 else
1041 set_irq_chip(irq, &bfin_internal_irqchip);
Bryan Wu1394f032007-05-06 14:50:22 -07001042
Michael Hennerich464abc52008-02-25 13:50:20 +08001043 switch (irq) {
Michael Hennerich59003142007-10-21 16:54:27 +08001044#if defined(CONFIG_BF53x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001045 case IRQ_PROG_INTA:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001046# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
Michael Hennerich464abc52008-02-25 13:50:20 +08001047 case IRQ_MAC_RX:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001048# endif
Michael Hennerich59003142007-10-21 16:54:27 +08001049#elif defined(CONFIG_BF54x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001050 case IRQ_PINT0:
1051 case IRQ_PINT1:
1052 case IRQ_PINT2:
1053 case IRQ_PINT3:
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001054#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001055 case IRQ_PORTF_INTA:
1056 case IRQ_PORTG_INTA:
1057 case IRQ_PORTH_INTA:
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001058#elif defined(CONFIG_BF561)
Michael Hennerich464abc52008-02-25 13:50:20 +08001059 case IRQ_PROG0_INTA:
1060 case IRQ_PROG1_INTA:
1061 case IRQ_PROG2_INTA:
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001062#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
1063 case IRQ_PORTF_INTA:
Michael Hennerich59003142007-10-21 16:54:27 +08001064#endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001065
Michael Hennerich464abc52008-02-25 13:50:20 +08001066 set_irq_chained_handler(irq,
1067 bfin_demux_gpio_irq);
1068 break;
Bryan Wu1394f032007-05-06 14:50:22 -07001069#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001070 case IRQ_GENERIC_ERROR:
Yi Li6a01f232009-01-07 23:14:39 +08001071 set_irq_chained_handler(irq, bfin_demux_error_irq);
Michael Hennerich464abc52008-02-25 13:50:20 +08001072 break;
1073#endif
Graf Yang179413142009-08-18 04:29:33 +00001074
Graf Yang6b3087c2009-01-07 23:14:39 +08001075#ifdef CONFIG_SMP
Graf Yang179413142009-08-18 04:29:33 +00001076#ifdef CONFIG_TICKSOURCE_GPTMR0
1077 case IRQ_TIMER0:
1078#endif
1079#ifdef CONFIG_TICKSOURCE_CORETMR
1080 case IRQ_CORETMR:
1081#endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001082 case IRQ_SUPPLE_0:
1083 case IRQ_SUPPLE_1:
1084 set_irq_handler(irq, handle_percpu_irq);
1085 break;
1086#endif
Graf Yang179413142009-08-18 04:29:33 +00001087
Yi Li6a01f232009-01-07 23:14:39 +08001088#ifdef CONFIG_IPIPE
Philippe Geruma40494a2009-06-16 05:25:42 +02001089#ifndef CONFIG_TICKSOURCE_CORETMR
1090 case IRQ_TIMER0:
Michael Hennerich464abc52008-02-25 13:50:20 +08001091 set_irq_handler(irq, handle_simple_irq);
1092 break;
Graf Yang179413142009-08-18 04:29:33 +00001093#endif
Philippe Geruma40494a2009-06-16 05:25:42 +02001094 case IRQ_CORETMR:
1095 set_irq_handler(irq, handle_simple_irq);
1096 break;
1097 default:
1098 set_irq_handler(irq, handle_level_irq);
1099 break;
1100#else /* !CONFIG_IPIPE */
Philippe Geruma40494a2009-06-16 05:25:42 +02001101 default:
1102 set_irq_handler(irq, handle_simple_irq);
1103 break;
Graf Yang179413142009-08-18 04:29:33 +00001104#endif /* !CONFIG_IPIPE */
Bryan Wu1394f032007-05-06 14:50:22 -07001105 }
Bryan Wu1394f032007-05-06 14:50:22 -07001106 }
Michael Hennerich464abc52008-02-25 13:50:20 +08001107
Bryan Wu1394f032007-05-06 14:50:22 -07001108#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001109 for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
1110 set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
1111 handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -07001112#endif
1113
Michael Hennerich464abc52008-02-25 13:50:20 +08001114 /* if configured as edge, then will be changed to do_edge_IRQ */
1115 for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
1116 set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
1117 handle_level_irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001118
Mike Frysingera055b2b2007-11-15 21:12:32 +08001119
Bryan Wu1394f032007-05-06 14:50:22 -07001120 bfin_write_IMASK(0);
1121 CSYNC();
1122 ilat = bfin_read_ILAT();
1123 CSYNC();
1124 bfin_write_ILAT(ilat);
1125 CSYNC();
1126
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001127 printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
Mike Frysinger40059782008-11-18 17:48:22 +08001128 /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx,
Bryan Wu1394f032007-05-06 14:50:22 -07001129 * local_irq_enable()
1130 */
1131 program_IAR();
1132 /* Therefore it's better to setup IARs before interrupts enabled */
1133 search_IAR();
1134
1135 /* Enable interrupts IVG7-15 */
Mike Frysinger40059782008-11-18 17:48:22 +08001136 bfin_irq_flags |= IMASK_IVG15 |
Bryan Wu1394f032007-05-06 14:50:22 -07001137 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001138 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
Bryan Wu1394f032007-05-06 14:50:22 -07001139
Michael Hennerich349ebbc2009-04-15 08:48:08 +00001140 /* This implicitly covers ANOMALY_05000171
1141 * Boot-ROM code modifies SICA_IWRx wakeup registers
1142 */
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001143#ifdef SIC_IWR0
Michael Hennerich56f5f592008-08-06 17:55:32 +08001144 bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001145# ifdef SIC_IWR1
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001146 /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which
Michael Hennerich55546ac2008-08-13 17:41:13 +08001147 * will screw up the bootrom as it relies on MDMA0/1 waking it
1148 * up from IDLE instructions. See this report for more info:
1149 * http://blackfin.uclinux.org/gf/tracker/4323
1150 */
Mike Frysingerb7e11292008-11-18 17:48:22 +08001151 if (ANOMALY_05000435)
1152 bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
1153 else
1154 bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001155# endif
1156# ifdef SIC_IWR2
Michael Hennerich56f5f592008-08-06 17:55:32 +08001157 bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001158# endif
1159#else
Michael Hennerich56f5f592008-08-06 17:55:32 +08001160 bfin_write_SIC_IWR(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001161#endif
1162
Bryan Wu1394f032007-05-06 14:50:22 -07001163 return 0;
1164}
1165
1166#ifdef CONFIG_DO_IRQ_L1
Mike Frysingera055b2b2007-11-15 21:12:32 +08001167__attribute__((l1_text))
Bryan Wu1394f032007-05-06 14:50:22 -07001168#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001169void do_irq(int vec, struct pt_regs *fp)
1170{
1171 if (vec == EVT_IVTMR_P) {
1172 vec = IRQ_CORETMR;
1173 } else {
1174 struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
1175 struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
Mike Frysinger780172b2009-06-01 19:43:02 -04001176#if defined(SIC_ISR0) || defined(SICA_ISR0)
Roy Huang24a07a12007-07-12 22:41:45 +08001177 unsigned long sic_status[3];
Bryan Wu1394f032007-05-06 14:50:22 -07001178
Graf Yang6b3087c2009-01-07 23:14:39 +08001179 if (smp_processor_id()) {
Mike Frysinger780172b2009-06-01 19:43:02 -04001180# ifdef SICB_ISR0
Graf Yang6b3087c2009-01-07 23:14:39 +08001181 /* This will be optimized out in UP mode. */
1182 sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
1183 sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001184# endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001185 } else {
1186 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1187 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
1188 }
Mike Frysinger780172b2009-06-01 19:43:02 -04001189# ifdef SIC_ISR2
Michael Hennerich4fb45242007-10-21 16:53:53 +08001190 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001191# endif
Mike Frysinger1f83b8f2007-07-12 22:58:21 +08001192 for (;; ivg++) {
Roy Huang24a07a12007-07-12 22:41:45 +08001193 if (ivg >= ivg_stop) {
1194 atomic_inc(&num_spurious);
1195 return;
1196 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001197 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
Roy Huang24a07a12007-07-12 22:41:45 +08001198 break;
1199 }
1200#else
1201 unsigned long sic_status;
Michael Hennerich464abc52008-02-25 13:50:20 +08001202
Bryan Wu1394f032007-05-06 14:50:22 -07001203 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1204
1205 for (;; ivg++) {
1206 if (ivg >= ivg_stop) {
1207 atomic_inc(&num_spurious);
1208 return;
1209 } else if (sic_status & ivg->isrflag)
1210 break;
1211 }
Roy Huang24a07a12007-07-12 22:41:45 +08001212#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001213 vec = ivg->irqno;
1214 }
1215 asm_do_IRQ(vec, fp);
Bryan Wu1394f032007-05-06 14:50:22 -07001216}
Yi Li6a01f232009-01-07 23:14:39 +08001217
1218#ifdef CONFIG_IPIPE
1219
1220int __ipipe_get_irq_priority(unsigned irq)
1221{
1222 int ient, prio;
1223
1224 if (irq <= IRQ_CORETMR)
1225 return irq;
1226
1227 for (ient = 0; ient < NR_PERI_INTS; ient++) {
1228 struct ivgx *ivg = ivg_table + ient;
1229 if (ivg->irqno == irq) {
1230 for (prio = 0; prio <= IVG13-IVG7; prio++) {
1231 if (ivg7_13[prio].ifirst <= ivg &&
1232 ivg7_13[prio].istop > ivg)
1233 return IVG7 + prio;
1234 }
1235 }
1236 }
1237
1238 return IVG15;
1239}
1240
Yi Li6a01f232009-01-07 23:14:39 +08001241/* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */
1242#ifdef CONFIG_DO_IRQ_L1
1243__attribute__((l1_text))
1244#endif
1245asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
1246{
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001247 struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr();
Philippe Geruma40494a2009-06-16 05:25:42 +02001248 struct ipipe_domain *this_domain = __ipipe_current_domain;
Yi Li6a01f232009-01-07 23:14:39 +08001249 struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
1250 struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001251 int irq, s;
Yi Li6a01f232009-01-07 23:14:39 +08001252
Philippe Geruma40494a2009-06-16 05:25:42 +02001253 if (likely(vec == EVT_IVTMR_P))
Yi Li6a01f232009-01-07 23:14:39 +08001254 irq = IRQ_CORETMR;
Philippe Geruma40494a2009-06-16 05:25:42 +02001255 else {
Mike Frysinger780172b2009-06-01 19:43:02 -04001256#if defined(SIC_ISR0) || defined(SICA_ISR0)
Yi Li6a01f232009-01-07 23:14:39 +08001257 unsigned long sic_status[3];
1258
1259 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1260 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001261# ifdef SIC_ISR2
Yi Li6a01f232009-01-07 23:14:39 +08001262 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001263# endif
Yi Li6a01f232009-01-07 23:14:39 +08001264 for (;; ivg++) {
1265 if (ivg >= ivg_stop) {
1266 atomic_inc(&num_spurious);
1267 return 0;
1268 }
1269 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
1270 break;
1271 }
Yi Li6a01f232009-01-07 23:14:39 +08001272#else
Yi Li6a01f232009-01-07 23:14:39 +08001273 unsigned long sic_status;
1274
1275 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1276
1277 for (;; ivg++) {
1278 if (ivg >= ivg_stop) {
1279 atomic_inc(&num_spurious);
1280 return 0;
1281 } else if (sic_status & ivg->isrflag)
1282 break;
1283 }
Yi Li6a01f232009-01-07 23:14:39 +08001284#endif
Graf Yang1fa9be72009-05-15 11:01:59 +00001285 irq = ivg->irqno;
1286 }
Yi Li6a01f232009-01-07 23:14:39 +08001287
1288 if (irq == IRQ_SYSTMR) {
Philippe Geruma40494a2009-06-16 05:25:42 +02001289#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
Yi Li6a01f232009-01-07 23:14:39 +08001290 bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001291#endif
Yi Li6a01f232009-01-07 23:14:39 +08001292 /* This is basically what we need from the register frame. */
1293 __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend;
1294 __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001295 if (this_domain != ipipe_root_domain)
Yi Li6a01f232009-01-07 23:14:39 +08001296 __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001297 else
1298 __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
Yi Li6a01f232009-01-07 23:14:39 +08001299 }
1300
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001301 if (this_domain == ipipe_root_domain) {
1302 s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1303 barrier();
1304 }
Yi Li6a01f232009-01-07 23:14:39 +08001305
1306 ipipe_trace_irq_entry(irq);
1307 __ipipe_handle_irq(irq, regs);
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001308 ipipe_trace_irq_exit(irq);
Yi Li6a01f232009-01-07 23:14:39 +08001309
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001310 if (this_domain == ipipe_root_domain) {
1311 set_thread_flag(TIF_IRQ_SYNC);
1312 if (!s) {
1313 __clear_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1314 return !test_bit(IPIPE_STALL_FLAG, &p->status);
1315 }
1316 }
Yi Li6a01f232009-01-07 23:14:39 +08001317
Graf Yang1fa9be72009-05-15 11:01:59 +00001318 return 0;
Yi Li6a01f232009-01-07 23:14:39 +08001319}
1320
1321#endif /* CONFIG_IPIPE */