blob: 11c05f3e178b812123bd52d630e4a6b810a7a234 [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));
Michael Hennerich464abc52008-02-25 13:50:20 +0800328 if (!error_int_mask)
329 bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700330}
331
332static void bfin_generic_error_unmask_irq(unsigned int irq)
333{
Michael Hennerich464abc52008-02-25 13:50:20 +0800334 bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700335 error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
336}
337
338static struct irq_chip bfin_generic_error_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800339 .name = "ERROR",
Michael Hennerich464abc52008-02-25 13:50:20 +0800340 .ack = bfin_ack_noop,
341 .mask_ack = bfin_generic_error_mask_irq,
Bryan Wu1394f032007-05-06 14:50:22 -0700342 .mask = bfin_generic_error_mask_irq,
343 .unmask = bfin_generic_error_unmask_irq,
344};
345
346static void bfin_demux_error_irq(unsigned int int_err_irq,
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800347 struct irq_desc *inta_desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700348{
349 int irq = 0;
350
Bryan Wu1394f032007-05-06 14:50:22 -0700351#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
352 if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
353 irq = IRQ_MAC_ERROR;
354 else
355#endif
356 if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
357 irq = IRQ_SPORT0_ERROR;
358 else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
359 irq = IRQ_SPORT1_ERROR;
360 else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
361 irq = IRQ_PPI_ERROR;
362 else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
363 irq = IRQ_CAN_ERROR;
364 else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
365 irq = IRQ_SPI_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000366 else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700367 irq = IRQ_UART0_ERROR;
Mike Frysinger7eb87fd2009-11-03 09:29:50 +0000368 else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
Bryan Wu1394f032007-05-06 14:50:22 -0700369 irq = IRQ_UART1_ERROR;
370
371 if (irq) {
Yi Li6a01f232009-01-07 23:14:39 +0800372 if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
373 bfin_handle_irq(irq);
374 else {
Bryan Wu1394f032007-05-06 14:50:22 -0700375
376 switch (irq) {
377 case IRQ_PPI_ERROR:
378 bfin_write_PPI_STATUS(PPI_ERR_MASK);
379 break;
380#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
381 case IRQ_MAC_ERROR:
382 bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
383 break;
384#endif
385 case IRQ_SPORT0_ERROR:
386 bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
387 break;
388
389 case IRQ_SPORT1_ERROR:
390 bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
391 break;
392
393 case IRQ_CAN_ERROR:
394 bfin_write_CAN_GIS(CAN_ERR_MASK);
395 break;
396
397 case IRQ_SPI_ERROR:
398 bfin_write_SPI_STAT(SPI_ERR_MASK);
399 break;
400
401 default:
402 break;
403 }
404
405 pr_debug("IRQ %d:"
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800406 " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
407 irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700408 }
409 } else
410 printk(KERN_ERR
411 "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
412 " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
Harvey Harrisonb85d8582008-04-23 09:39:01 +0800413 __func__, __FILE__, __LINE__);
Bryan Wu1394f032007-05-06 14:50:22 -0700414
Bryan Wu1394f032007-05-06 14:50:22 -0700415}
416#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
417
Michael Hennerichaec59c92010-02-19 15:09:10 +0000418#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
419static int mac_stat_int_mask;
420
421static void bfin_mac_status_ack_irq(unsigned int irq)
422{
423 switch (irq) {
424 case IRQ_MAC_MMCINT:
425 bfin_write_EMAC_MMC_TIRQS(
426 bfin_read_EMAC_MMC_TIRQE() &
427 bfin_read_EMAC_MMC_TIRQS());
428 bfin_write_EMAC_MMC_RIRQS(
429 bfin_read_EMAC_MMC_RIRQE() &
430 bfin_read_EMAC_MMC_RIRQS());
431 break;
432 case IRQ_MAC_RXFSINT:
433 bfin_write_EMAC_RX_STKY(
434 bfin_read_EMAC_RX_IRQE() &
435 bfin_read_EMAC_RX_STKY());
436 break;
437 case IRQ_MAC_TXFSINT:
438 bfin_write_EMAC_TX_STKY(
439 bfin_read_EMAC_TX_IRQE() &
440 bfin_read_EMAC_TX_STKY());
441 break;
442 case IRQ_MAC_WAKEDET:
443 bfin_write_EMAC_WKUP_CTL(
444 bfin_read_EMAC_WKUP_CTL() | MPKS | RWKS);
445 break;
446 default:
447 /* These bits are W1C */
448 bfin_write_EMAC_SYSTAT(1L << (irq - IRQ_MAC_PHYINT));
449 break;
450 }
451}
452
453static void bfin_mac_status_mask_irq(unsigned int irq)
454{
455 mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT));
456#ifdef BF537_GENERIC_ERROR_INT_DEMUX
457 switch (irq) {
458 case IRQ_MAC_PHYINT:
459 bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE);
460 break;
461 default:
462 break;
463 }
464#else
465 if (!mac_stat_int_mask)
466 bfin_internal_mask_irq(IRQ_MAC_ERROR);
467#endif
468 bfin_mac_status_ack_irq(irq);
469}
470
471static void bfin_mac_status_unmask_irq(unsigned int irq)
472{
473#ifdef BF537_GENERIC_ERROR_INT_DEMUX
474 switch (irq) {
475 case IRQ_MAC_PHYINT:
476 bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE);
477 break;
478 default:
479 break;
480 }
481#else
482 if (!mac_stat_int_mask)
483 bfin_internal_unmask_irq(IRQ_MAC_ERROR);
484#endif
485 mac_stat_int_mask |= 1L << (irq - IRQ_MAC_PHYINT);
486}
487
488#ifdef CONFIG_PM
489int bfin_mac_status_set_wake(unsigned int irq, unsigned int state)
490{
491#ifdef BF537_GENERIC_ERROR_INT_DEMUX
492 return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state);
493#else
494 return bfin_internal_set_wake(IRQ_MAC_ERROR, state);
495#endif
496}
497#endif
498
499static struct irq_chip bfin_mac_status_irqchip = {
500 .name = "MACST",
501 .ack = bfin_ack_noop,
502 .mask_ack = bfin_mac_status_mask_irq,
503 .mask = bfin_mac_status_mask_irq,
504 .unmask = bfin_mac_status_unmask_irq,
505#ifdef CONFIG_PM
506 .set_wake = bfin_mac_status_set_wake,
507#endif
508};
509
510static void bfin_demux_mac_status_irq(unsigned int int_err_irq,
511 struct irq_desc *inta_desc)
512{
513 int i, irq = 0;
514 u32 status = bfin_read_EMAC_SYSTAT();
515
516 for (i = 0; i < (IRQ_MAC_STMDONE - IRQ_MAC_PHYINT); i++)
517 if (status & (1L << i)) {
518 irq = IRQ_MAC_PHYINT + i;
519 break;
520 }
521
522 if (irq) {
523 if (mac_stat_int_mask & (1L << (irq - IRQ_MAC_PHYINT))) {
524 bfin_handle_irq(irq);
525 } else {
526 bfin_mac_status_ack_irq(irq);
527 pr_debug("IRQ %d:"
528 " MASKED MAC ERROR INTERRUPT ASSERTED\n",
529 irq);
530 }
531 } else
532 printk(KERN_ERR
533 "%s : %s : LINE %d :\nIRQ ?: MAC ERROR"
534 " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
535 __func__, __FILE__, __LINE__);
536}
537#endif
538
Graf Yangbfd15112008-10-08 18:02:44 +0800539static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
540{
Yi Li6a01f232009-01-07 23:14:39 +0800541#ifdef CONFIG_IPIPE
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800542 _set_irq_handler(irq, handle_level_irq);
Yi Li6a01f232009-01-07 23:14:39 +0800543#else
Graf Yangbfd15112008-10-08 18:02:44 +0800544 struct irq_desc *desc = irq_desc + irq;
545 /* May not call generic set_irq_handler() due to spinlock
546 recursion. */
547 desc->handle_irq = handle;
Yi Li6a01f232009-01-07 23:14:39 +0800548#endif
Graf Yangbfd15112008-10-08 18:02:44 +0800549}
550
Michael Hennerich8d022372008-11-18 17:48:22 +0800551static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800552extern void bfin_gpio_irq_prepare(unsigned gpio);
Michael Hennerich6fce6a82007-12-24 16:56:12 +0800553
Michael Hennerich8d022372008-11-18 17:48:22 +0800554#if !defined(CONFIG_BF54x)
555
Bryan Wu1394f032007-05-06 14:50:22 -0700556static void bfin_gpio_ack_irq(unsigned int irq)
557{
Michael Hennerich8d022372008-11-18 17:48:22 +0800558 /* AFAIK ack_irq in case mask_ack is provided
559 * get's only called for edge sense irqs
560 */
561 set_gpio_data(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700562}
563
564static void bfin_gpio_mask_ack_irq(unsigned int irq)
565{
Michael Hennerich8d022372008-11-18 17:48:22 +0800566 struct irq_desc *desc = irq_desc + irq;
567 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700568
Michael Hennerich8d022372008-11-18 17:48:22 +0800569 if (desc->handle_irq == handle_edge_irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700570 set_gpio_data(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700571
572 set_gpio_maska(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700573}
574
575static void bfin_gpio_mask_irq(unsigned int irq)
576{
Michael Hennerich8d022372008-11-18 17:48:22 +0800577 set_gpio_maska(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700578}
579
580static void bfin_gpio_unmask_irq(unsigned int irq)
581{
Michael Hennerich8d022372008-11-18 17:48:22 +0800582 set_gpio_maska(irq_to_gpio(irq), 1);
Bryan Wu1394f032007-05-06 14:50:22 -0700583}
584
585static unsigned int bfin_gpio_irq_startup(unsigned int irq)
586{
Michael Hennerich8d022372008-11-18 17:48:22 +0800587 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700588
Michael Hennerich8d022372008-11-18 17:48:22 +0800589 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800590 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700591
Bryan Wu1394f032007-05-06 14:50:22 -0700592 bfin_gpio_unmask_irq(irq);
593
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800594 return 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700595}
596
597static void bfin_gpio_irq_shutdown(unsigned int irq)
598{
Graf Yang30af6d42008-11-18 17:48:21 +0800599 u32 gpionr = irq_to_gpio(irq);
600
Bryan Wu1394f032007-05-06 14:50:22 -0700601 bfin_gpio_mask_irq(irq);
Graf Yang30af6d42008-11-18 17:48:21 +0800602 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800603 bfin_gpio_irq_free(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700604}
605
606static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
607{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800608 int ret;
609 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800610 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700611
612 if (type == IRQ_TYPE_PROBE) {
613 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400614 if (test_bit(gpionr, gpio_enabled))
Bryan Wu1394f032007-05-06 14:50:22 -0700615 return 0;
616 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
617 }
618
619 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800620 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Michael Hennerich8d022372008-11-18 17:48:22 +0800621
Graf Yang9570ff42009-01-07 23:14:38 +0800622 snprintf(buf, 16, "gpio-irq%d", irq);
623 ret = bfin_gpio_irq_request(gpionr, buf);
624 if (ret)
625 return ret;
626
Michael Hennerich8d022372008-11-18 17:48:22 +0800627 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800628 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700629
Bryan Wu1394f032007-05-06 14:50:22 -0700630 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800631 __clear_bit(gpionr, gpio_enabled);
Bryan Wu1394f032007-05-06 14:50:22 -0700632 return 0;
633 }
634
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800635 set_gpio_inen(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700636 set_gpio_dir(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700637
638 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
639 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
640 set_gpio_both(gpionr, 1);
641 else
642 set_gpio_both(gpionr, 0);
643
644 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
645 set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
646 else
647 set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
648
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800649 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
650 set_gpio_edge(gpionr, 1);
651 set_gpio_inen(gpionr, 1);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800652 set_gpio_data(gpionr, 0);
653
654 } else {
655 set_gpio_edge(gpionr, 0);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800656 set_gpio_inen(gpionr, 1);
657 }
658
Bryan Wu1394f032007-05-06 14:50:22 -0700659 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
Graf Yangbfd15112008-10-08 18:02:44 +0800660 bfin_set_irq_handler(irq, handle_edge_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700661 else
Graf Yangbfd15112008-10-08 18:02:44 +0800662 bfin_set_irq_handler(irq, handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700663
664 return 0;
665}
666
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800667#ifdef CONFIG_PM
668int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
669{
670 unsigned gpio = irq_to_gpio(irq);
671
672 if (state)
673 gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE);
674 else
675 gpio_pm_wakeup_free(gpio);
676
677 return 0;
678}
679#endif
680
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800681static void bfin_demux_gpio_irq(unsigned int inta_irq,
682 struct irq_desc *desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700683{
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800684 unsigned int i, gpio, mask, irq, search = 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700685
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800686 switch (inta_irq) {
687#if defined(CONFIG_BF53x)
688 case IRQ_PROG_INTA:
689 irq = IRQ_PF0;
690 search = 1;
691 break;
692# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
693 case IRQ_MAC_RX:
694 irq = IRQ_PH0;
695 break;
696# endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800697#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
698 case IRQ_PORTF_INTA:
699 irq = IRQ_PF0;
700 break;
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800701#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800702 case IRQ_PORTF_INTA:
703 irq = IRQ_PF0;
704 break;
705 case IRQ_PORTG_INTA:
706 irq = IRQ_PG0;
707 break;
708 case IRQ_PORTH_INTA:
709 irq = IRQ_PH0;
710 break;
711#elif defined(CONFIG_BF561)
712 case IRQ_PROG0_INTA:
713 irq = IRQ_PF0;
714 break;
715 case IRQ_PROG1_INTA:
716 irq = IRQ_PF16;
717 break;
718 case IRQ_PROG2_INTA:
719 irq = IRQ_PF32;
720 break;
721#endif
722 default:
723 BUG();
724 return;
Bryan Wu1394f032007-05-06 14:50:22 -0700725 }
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800726
727 if (search) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800728 for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800729 irq += i;
730
Michael Hennerich8d022372008-11-18 17:48:22 +0800731 mask = get_gpiop_data(i) & get_gpiop_maska(i);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800732
733 while (mask) {
Yi Li6a01f232009-01-07 23:14:39 +0800734 if (mask & 1)
735 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800736 irq++;
737 mask >>= 1;
738 }
739 }
740 } else {
741 gpio = irq_to_gpio(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800742 mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800743
744 do {
Yi Li6a01f232009-01-07 23:14:39 +0800745 if (mask & 1)
746 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800747 irq++;
748 mask >>= 1;
749 } while (mask);
750 }
751
Bryan Wu1394f032007-05-06 14:50:22 -0700752}
753
Mike Frysingera055b2b2007-11-15 21:12:32 +0800754#else /* CONFIG_BF54x */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800755
756#define NR_PINT_SYS_IRQS 4
757#define NR_PINT_BITS 32
758#define NR_PINTS 160
759#define IRQ_NOT_AVAIL 0xFF
760
761#define PINT_2_BANK(x) ((x) >> 5)
762#define PINT_2_BIT(x) ((x) & 0x1F)
763#define PINT_BIT(x) (1 << (PINT_2_BIT(x)))
764
765static unsigned char irq2pint_lut[NR_PINTS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800766static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800767
768struct pin_int_t {
769 unsigned int mask_set;
770 unsigned int mask_clear;
771 unsigned int request;
772 unsigned int assign;
773 unsigned int edge_set;
774 unsigned int edge_clear;
775 unsigned int invert_set;
776 unsigned int invert_clear;
777 unsigned int pinstate;
778 unsigned int latch;
779};
780
781static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
782 (struct pin_int_t *)PINT0_MASK_SET,
783 (struct pin_int_t *)PINT1_MASK_SET,
784 (struct pin_int_t *)PINT2_MASK_SET,
785 (struct pin_int_t *)PINT3_MASK_SET,
786};
787
Michael Hennerich8d022372008-11-18 17:48:22 +0800788inline unsigned int get_irq_base(u32 bank, u8 bmap)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800789{
Michael Hennerich8d022372008-11-18 17:48:22 +0800790 unsigned int irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800791
792 if (bank < 2) { /*PA-PB */
793 irq_base = IRQ_PA0 + bmap * 16;
794 } else { /*PC-PJ */
795 irq_base = IRQ_PC0 + bmap * 16;
796 }
797
798 return irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800799}
800
801 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
802void init_pint_lut(void)
803{
804 u16 bank, bit, irq_base, bit_pos;
805 u32 pint_assign;
806 u8 bmap;
807
808 memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut));
809
810 for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) {
811
812 pint_assign = pint[bank]->assign;
813
814 for (bit = 0; bit < NR_PINT_BITS; bit++) {
815
816 bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF;
817
818 irq_base = get_irq_base(bank, bmap);
819
820 irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0);
821 bit_pos = bit + bank * NR_PINT_BITS;
822
Michael Henneriche3f23002007-07-12 16:39:29 +0800823 pint2irq_lut[bit_pos] = irq_base - SYS_IRQS;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800824 irq2pint_lut[irq_base - SYS_IRQS] = bit_pos;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800825 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800826 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800827}
828
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800829static void bfin_gpio_ack_irq(unsigned int irq)
830{
Michael Hennerich8d022372008-11-18 17:48:22 +0800831 struct irq_desc *desc = irq_desc + irq;
832 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich8baf5602007-12-24 18:51:34 +0800833 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800834 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800835
Michael Hennerich8d022372008-11-18 17:48:22 +0800836 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800837 if (pint[bank]->invert_set & pintbit)
838 pint[bank]->invert_clear = pintbit;
839 else
840 pint[bank]->invert_set = pintbit;
841 }
842 pint[bank]->request = pintbit;
843
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800844}
845
846static void bfin_gpio_mask_ack_irq(unsigned int irq)
847{
Michael Hennerich8d022372008-11-18 17:48:22 +0800848 struct irq_desc *desc = irq_desc + irq;
849 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800850 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800851 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800852
Michael Hennerich8d022372008-11-18 17:48:22 +0800853 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800854 if (pint[bank]->invert_set & pintbit)
855 pint[bank]->invert_clear = pintbit;
856 else
857 pint[bank]->invert_set = pintbit;
858 }
859
Michael Henneriche3f23002007-07-12 16:39:29 +0800860 pint[bank]->request = pintbit;
861 pint[bank]->mask_clear = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800862}
863
864static void bfin_gpio_mask_irq(unsigned int irq)
865{
Michael Hennerich8d022372008-11-18 17:48:22 +0800866 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800867
868 pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800869}
870
871static void bfin_gpio_unmask_irq(unsigned int irq)
872{
Michael Hennerich8d022372008-11-18 17:48:22 +0800873 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800874 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800875 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800876
Michael Henneriche3f23002007-07-12 16:39:29 +0800877 pint[bank]->request = pintbit;
878 pint[bank]->mask_set = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800879}
880
881static unsigned int bfin_gpio_irq_startup(unsigned int irq)
882{
Michael Hennerich8d022372008-11-18 17:48:22 +0800883 u32 gpionr = irq_to_gpio(irq);
884 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800885
Michael Hennerich50e163c2007-07-24 16:17:28 +0800886 if (pint_val == IRQ_NOT_AVAIL) {
887 printk(KERN_ERR
888 "GPIO IRQ %d :Not in PINT Assign table "
889 "Reconfigure Interrupt to Port Assignemt\n", irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800890 return -ENODEV;
Michael Hennerich50e163c2007-07-24 16:17:28 +0800891 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800892
Michael Hennerich8d022372008-11-18 17:48:22 +0800893 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800894 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800895
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800896 bfin_gpio_unmask_irq(irq);
897
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800898 return 0;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800899}
900
901static void bfin_gpio_irq_shutdown(unsigned int irq)
902{
Michael Hennerich8d022372008-11-18 17:48:22 +0800903 u32 gpionr = irq_to_gpio(irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800904
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800905 bfin_gpio_mask_irq(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800906 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800907 bfin_gpio_irq_free(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800908}
909
910static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
911{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800912 int ret;
913 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800914 u32 gpionr = irq_to_gpio(irq);
915 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800916 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800917 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800918
919 if (pint_val == IRQ_NOT_AVAIL)
920 return -ENODEV;
921
922 if (type == IRQ_TYPE_PROBE) {
923 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400924 if (test_bit(gpionr, gpio_enabled))
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800925 return 0;
926 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
927 }
928
929 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
930 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Graf Yang9570ff42009-01-07 23:14:38 +0800931
932 snprintf(buf, 16, "gpio-irq%d", irq);
933 ret = bfin_gpio_irq_request(gpionr, buf);
934 if (ret)
935 return ret;
936
Michael Hennerich8d022372008-11-18 17:48:22 +0800937 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800938 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800939
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800940 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800941 __clear_bit(gpionr, gpio_enabled);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800942 return 0;
943 }
944
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800945 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
Michael Henneriche3f23002007-07-12 16:39:29 +0800946 pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800947 else
Michael Hennerich8baf5602007-12-24 18:51:34 +0800948 pint[bank]->invert_clear = pintbit; /* high or rising edge denoted by zero */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800949
Michael Hennerich8baf5602007-12-24 18:51:34 +0800950 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
951 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800952 if (gpio_get_value(gpionr))
953 pint[bank]->invert_set = pintbit;
954 else
955 pint[bank]->invert_clear = pintbit;
Michael Hennerich8baf5602007-12-24 18:51:34 +0800956 }
957
958 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
959 pint[bank]->edge_set = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800960 bfin_set_irq_handler(irq, handle_edge_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800961 } else {
962 pint[bank]->edge_clear = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800963 bfin_set_irq_handler(irq, handle_level_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800964 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800965
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800966 return 0;
967}
968
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800969#ifdef CONFIG_PM
970u32 pint_saved_masks[NR_PINT_SYS_IRQS];
971u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
972
973int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
974{
975 u32 pint_irq;
Michael Hennerich8d022372008-11-18 17:48:22 +0800976 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800977 u32 bank = PINT_2_BANK(pint_val);
978 u32 pintbit = PINT_BIT(pint_val);
979
980 switch (bank) {
981 case 0:
982 pint_irq = IRQ_PINT0;
983 break;
984 case 2:
985 pint_irq = IRQ_PINT2;
986 break;
987 case 3:
988 pint_irq = IRQ_PINT3;
989 break;
990 case 1:
991 pint_irq = IRQ_PINT1;
992 break;
993 default:
994 return -EINVAL;
995 }
996
997 bfin_internal_set_wake(pint_irq, state);
998
999 if (state)
1000 pint_wakeup_masks[bank] |= pintbit;
1001 else
1002 pint_wakeup_masks[bank] &= ~pintbit;
1003
1004 return 0;
1005}
1006
1007u32 bfin_pm_setup(void)
1008{
1009 u32 val, i;
1010
1011 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
1012 val = pint[i]->mask_clear;
1013 pint_saved_masks[i] = val;
1014 if (val ^ pint_wakeup_masks[i]) {
1015 pint[i]->mask_clear = val;
1016 pint[i]->mask_set = pint_wakeup_masks[i];
1017 }
1018 }
1019
1020 return 0;
1021}
1022
1023void bfin_pm_restore(void)
1024{
1025 u32 i, val;
1026
1027 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
1028 val = pint_saved_masks[i];
1029 if (val ^ pint_wakeup_masks[i]) {
1030 pint[i]->mask_clear = pint[i]->mask_clear;
1031 pint[i]->mask_set = val;
1032 }
1033 }
1034}
1035#endif
1036
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001037static void bfin_demux_gpio_irq(unsigned int inta_irq,
1038 struct irq_desc *desc)
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001039{
Michael Hennerich8d022372008-11-18 17:48:22 +08001040 u32 bank, pint_val;
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001041 u32 request, irq;
1042
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001043 switch (inta_irq) {
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001044 case IRQ_PINT0:
1045 bank = 0;
1046 break;
1047 case IRQ_PINT2:
1048 bank = 2;
1049 break;
1050 case IRQ_PINT3:
1051 bank = 3;
1052 break;
1053 case IRQ_PINT1:
1054 bank = 1;
1055 break;
Michael Henneriche3f23002007-07-12 16:39:29 +08001056 default:
1057 return;
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001058 }
1059
1060 pint_val = bank * NR_PINT_BITS;
1061
1062 request = pint[bank]->request;
1063
1064 while (request) {
1065 if (request & 1) {
Michael Henneriche3f23002007-07-12 16:39:29 +08001066 irq = pint2irq_lut[pint_val] + SYS_IRQS;
Yi Li6a01f232009-01-07 23:14:39 +08001067 bfin_handle_irq(irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001068 }
1069 pint_val++;
1070 request >>= 1;
1071 }
1072
1073}
Mike Frysingera055b2b2007-11-15 21:12:32 +08001074#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001075
Michael Hennerich8d022372008-11-18 17:48:22 +08001076static struct irq_chip bfin_gpio_irqchip = {
1077 .name = "GPIO",
1078 .ack = bfin_gpio_ack_irq,
1079 .mask = bfin_gpio_mask_irq,
1080 .mask_ack = bfin_gpio_mask_ack_irq,
1081 .unmask = bfin_gpio_unmask_irq,
1082 .disable = bfin_gpio_mask_irq,
1083 .enable = bfin_gpio_unmask_irq,
1084 .set_type = bfin_gpio_irq_type,
1085 .startup = bfin_gpio_irq_startup,
1086 .shutdown = bfin_gpio_irq_shutdown,
1087#ifdef CONFIG_PM
1088 .set_wake = bfin_gpio_set_wake,
1089#endif
1090};
1091
Graf Yang6b3087c2009-01-07 23:14:39 +08001092void __cpuinit init_exception_vectors(void)
Bernd Schmidt8be80ed2007-07-25 14:44:49 +08001093{
Mike Frysingerf0b5d122007-08-05 17:03:59 +08001094 /* cannot program in software:
1095 * evt0 - emulation (jtag)
1096 * evt1 - reset
1097 */
1098 bfin_write_EVT2(evt_nmi);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +08001099 bfin_write_EVT3(trap);
1100 bfin_write_EVT5(evt_ivhw);
1101 bfin_write_EVT6(evt_timer);
1102 bfin_write_EVT7(evt_evt7);
1103 bfin_write_EVT8(evt_evt8);
1104 bfin_write_EVT9(evt_evt9);
1105 bfin_write_EVT10(evt_evt10);
1106 bfin_write_EVT11(evt_evt11);
1107 bfin_write_EVT12(evt_evt12);
1108 bfin_write_EVT13(evt_evt13);
Philippe Gerum9703a732009-06-22 18:23:48 +02001109 bfin_write_EVT14(evt_evt14);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +08001110 bfin_write_EVT15(evt_system_call);
1111 CSYNC();
1112}
1113
Bryan Wu1394f032007-05-06 14:50:22 -07001114/*
1115 * This function should be called during kernel startup to initialize
1116 * the BFin IRQ handling routines.
1117 */
Michael Hennerich8d022372008-11-18 17:48:22 +08001118
Bryan Wu1394f032007-05-06 14:50:22 -07001119int __init init_arch_irq(void)
1120{
1121 int irq;
1122 unsigned long ilat = 0;
1123 /* Disable all the peripheral intrs - page 4-29 HW Ref manual */
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001124#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
1125 || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
Roy Huang24a07a12007-07-12 22:41:45 +08001126 bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
1127 bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +08001128# ifdef CONFIG_BF54x
Michael Hennerich59003142007-10-21 16:54:27 +08001129 bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +08001130# endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001131# ifdef CONFIG_SMP
1132 bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);
1133 bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);
1134# endif
Roy Huang24a07a12007-07-12 22:41:45 +08001135#else
Bryan Wu1394f032007-05-06 14:50:22 -07001136 bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
Roy Huang24a07a12007-07-12 22:41:45 +08001137#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001138
1139 local_irq_disable();
1140
Mike Frysingerd70536e2008-08-25 17:37:35 +08001141#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
Mike Frysinger95a86b52008-08-14 15:05:01 +08001142 /* Clear EMAC Interrupt Status bits so we can demux it later */
1143 bfin_write_EMAC_SYSTAT(-1);
1144#endif
1145
Mike Frysingera055b2b2007-11-15 21:12:32 +08001146#ifdef CONFIG_BF54x
1147# ifdef CONFIG_PINTx_REASSIGN
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001148 pint[0]->assign = CONFIG_PINT0_ASSIGN;
1149 pint[1]->assign = CONFIG_PINT1_ASSIGN;
1150 pint[2]->assign = CONFIG_PINT2_ASSIGN;
1151 pint[3]->assign = CONFIG_PINT3_ASSIGN;
Mike Frysingera055b2b2007-11-15 21:12:32 +08001152# endif
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001153 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
1154 init_pint_lut();
1155#endif
1156
1157 for (irq = 0; irq <= SYS_IRQS; irq++) {
Bryan Wu1394f032007-05-06 14:50:22 -07001158 if (irq <= IRQ_CORETMR)
1159 set_irq_chip(irq, &bfin_core_irqchip);
1160 else
1161 set_irq_chip(irq, &bfin_internal_irqchip);
Bryan Wu1394f032007-05-06 14:50:22 -07001162
Michael Hennerich464abc52008-02-25 13:50:20 +08001163 switch (irq) {
Michael Hennerich59003142007-10-21 16:54:27 +08001164#if defined(CONFIG_BF53x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001165 case IRQ_PROG_INTA:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001166# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
Michael Hennerich464abc52008-02-25 13:50:20 +08001167 case IRQ_MAC_RX:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001168# endif
Michael Hennerich59003142007-10-21 16:54:27 +08001169#elif defined(CONFIG_BF54x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001170 case IRQ_PINT0:
1171 case IRQ_PINT1:
1172 case IRQ_PINT2:
1173 case IRQ_PINT3:
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001174#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001175 case IRQ_PORTF_INTA:
1176 case IRQ_PORTG_INTA:
1177 case IRQ_PORTH_INTA:
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001178#elif defined(CONFIG_BF561)
Michael Hennerich464abc52008-02-25 13:50:20 +08001179 case IRQ_PROG0_INTA:
1180 case IRQ_PROG1_INTA:
1181 case IRQ_PROG2_INTA:
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001182#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
1183 case IRQ_PORTF_INTA:
Michael Hennerich59003142007-10-21 16:54:27 +08001184#endif
Michael Hennerich464abc52008-02-25 13:50:20 +08001185 set_irq_chained_handler(irq,
1186 bfin_demux_gpio_irq);
1187 break;
Bryan Wu1394f032007-05-06 14:50:22 -07001188#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001189 case IRQ_GENERIC_ERROR:
Yi Li6a01f232009-01-07 23:14:39 +08001190 set_irq_chained_handler(irq, bfin_demux_error_irq);
Michael Hennerich464abc52008-02-25 13:50:20 +08001191 break;
1192#endif
Michael Hennerichaec59c92010-02-19 15:09:10 +00001193#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
1194 case IRQ_MAC_ERROR:
1195 set_irq_chained_handler(irq, bfin_demux_mac_status_irq);
1196 break;
1197#endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001198#ifdef CONFIG_SMP
1199 case IRQ_SUPPLE_0:
1200 case IRQ_SUPPLE_1:
1201 set_irq_handler(irq, handle_percpu_irq);
1202 break;
1203#endif
Graf Yang179413142009-08-18 04:29:33 +00001204
Yi Licb191712009-12-30 07:12:50 +00001205#ifdef CONFIG_TICKSOURCE_CORETMR
1206 case IRQ_CORETMR:
1207# ifdef CONFIG_SMP
1208 set_irq_handler(irq, handle_percpu_irq);
1209 break;
1210# else
1211 set_irq_handler(irq, handle_simple_irq);
1212 break;
1213# endif
1214#endif
1215
1216#ifdef CONFIG_TICKSOURCE_GPTMR0
Philippe Geruma40494a2009-06-16 05:25:42 +02001217 case IRQ_TIMER0:
Michael Hennerich464abc52008-02-25 13:50:20 +08001218 set_irq_handler(irq, handle_simple_irq);
1219 break;
Graf Yang179413142009-08-18 04:29:33 +00001220#endif
Yi Licb191712009-12-30 07:12:50 +00001221
1222#ifdef CONFIG_IPIPE
Philippe Geruma40494a2009-06-16 05:25:42 +02001223 default:
1224 set_irq_handler(irq, handle_level_irq);
1225 break;
1226#else /* !CONFIG_IPIPE */
Philippe Geruma40494a2009-06-16 05:25:42 +02001227 default:
1228 set_irq_handler(irq, handle_simple_irq);
1229 break;
Graf Yang179413142009-08-18 04:29:33 +00001230#endif /* !CONFIG_IPIPE */
Bryan Wu1394f032007-05-06 14:50:22 -07001231 }
Bryan Wu1394f032007-05-06 14:50:22 -07001232 }
Michael Hennerich464abc52008-02-25 13:50:20 +08001233
Bryan Wu1394f032007-05-06 14:50:22 -07001234#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001235 for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
1236 set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
1237 handle_level_irq);
Michael Hennerichaec59c92010-02-19 15:09:10 +00001238#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
1239 set_irq_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
1240#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001241#endif
1242
Michael Hennerichaec59c92010-02-19 15:09:10 +00001243#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
1244 for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++)
1245 set_irq_chip_and_handler(irq, &bfin_mac_status_irqchip,
1246 handle_level_irq);
1247#endif
Michael Hennerich464abc52008-02-25 13:50:20 +08001248 /* if configured as edge, then will be changed to do_edge_IRQ */
Michael Hennerichaec59c92010-02-19 15:09:10 +00001249 for (irq = GPIO_IRQ_BASE;
1250 irq < (GPIO_IRQ_BASE + MAX_BLACKFIN_GPIOS); irq++)
Michael Hennerich464abc52008-02-25 13:50:20 +08001251 set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
1252 handle_level_irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001253
Bryan Wu1394f032007-05-06 14:50:22 -07001254 bfin_write_IMASK(0);
1255 CSYNC();
1256 ilat = bfin_read_ILAT();
1257 CSYNC();
1258 bfin_write_ILAT(ilat);
1259 CSYNC();
1260
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001261 printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
Mike Frysinger40059782008-11-18 17:48:22 +08001262 /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx,
Bryan Wu1394f032007-05-06 14:50:22 -07001263 * local_irq_enable()
1264 */
1265 program_IAR();
1266 /* Therefore it's better to setup IARs before interrupts enabled */
1267 search_IAR();
1268
1269 /* Enable interrupts IVG7-15 */
Mike Frysinger40059782008-11-18 17:48:22 +08001270 bfin_irq_flags |= IMASK_IVG15 |
Bryan Wu1394f032007-05-06 14:50:22 -07001271 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001272 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
Bryan Wu1394f032007-05-06 14:50:22 -07001273
Michael Hennerich349ebbc2009-04-15 08:48:08 +00001274 /* This implicitly covers ANOMALY_05000171
1275 * Boot-ROM code modifies SICA_IWRx wakeup registers
1276 */
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001277#ifdef SIC_IWR0
Michael Hennerich56f5f592008-08-06 17:55:32 +08001278 bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001279# ifdef SIC_IWR1
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001280 /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which
Michael Hennerich55546ac2008-08-13 17:41:13 +08001281 * will screw up the bootrom as it relies on MDMA0/1 waking it
1282 * up from IDLE instructions. See this report for more info:
1283 * http://blackfin.uclinux.org/gf/tracker/4323
1284 */
Mike Frysingerb7e11292008-11-18 17:48:22 +08001285 if (ANOMALY_05000435)
1286 bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
1287 else
1288 bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001289# endif
1290# ifdef SIC_IWR2
Michael Hennerich56f5f592008-08-06 17:55:32 +08001291 bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001292# endif
1293#else
Michael Hennerich56f5f592008-08-06 17:55:32 +08001294 bfin_write_SIC_IWR(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001295#endif
1296
Bryan Wu1394f032007-05-06 14:50:22 -07001297 return 0;
1298}
1299
1300#ifdef CONFIG_DO_IRQ_L1
Mike Frysingera055b2b2007-11-15 21:12:32 +08001301__attribute__((l1_text))
Bryan Wu1394f032007-05-06 14:50:22 -07001302#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001303void do_irq(int vec, struct pt_regs *fp)
1304{
1305 if (vec == EVT_IVTMR_P) {
1306 vec = IRQ_CORETMR;
1307 } else {
1308 struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
1309 struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
Mike Frysinger780172b2009-06-01 19:43:02 -04001310#if defined(SIC_ISR0) || defined(SICA_ISR0)
Roy Huang24a07a12007-07-12 22:41:45 +08001311 unsigned long sic_status[3];
Bryan Wu1394f032007-05-06 14:50:22 -07001312
Graf Yang6b3087c2009-01-07 23:14:39 +08001313 if (smp_processor_id()) {
Mike Frysinger780172b2009-06-01 19:43:02 -04001314# ifdef SICB_ISR0
Graf Yang6b3087c2009-01-07 23:14:39 +08001315 /* This will be optimized out in UP mode. */
1316 sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
1317 sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001318# endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001319 } else {
1320 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1321 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
1322 }
Mike Frysinger780172b2009-06-01 19:43:02 -04001323# ifdef SIC_ISR2
Michael Hennerich4fb45242007-10-21 16:53:53 +08001324 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001325# endif
Mike Frysinger1f83b8f2007-07-12 22:58:21 +08001326 for (;; ivg++) {
Roy Huang24a07a12007-07-12 22:41:45 +08001327 if (ivg >= ivg_stop) {
1328 atomic_inc(&num_spurious);
1329 return;
1330 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001331 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
Roy Huang24a07a12007-07-12 22:41:45 +08001332 break;
1333 }
1334#else
1335 unsigned long sic_status;
Michael Hennerich464abc52008-02-25 13:50:20 +08001336
Bryan Wu1394f032007-05-06 14:50:22 -07001337 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1338
1339 for (;; ivg++) {
1340 if (ivg >= ivg_stop) {
1341 atomic_inc(&num_spurious);
1342 return;
1343 } else if (sic_status & ivg->isrflag)
1344 break;
1345 }
Roy Huang24a07a12007-07-12 22:41:45 +08001346#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001347 vec = ivg->irqno;
1348 }
1349 asm_do_IRQ(vec, fp);
Bryan Wu1394f032007-05-06 14:50:22 -07001350}
Yi Li6a01f232009-01-07 23:14:39 +08001351
1352#ifdef CONFIG_IPIPE
1353
1354int __ipipe_get_irq_priority(unsigned irq)
1355{
1356 int ient, prio;
1357
1358 if (irq <= IRQ_CORETMR)
1359 return irq;
1360
1361 for (ient = 0; ient < NR_PERI_INTS; ient++) {
1362 struct ivgx *ivg = ivg_table + ient;
1363 if (ivg->irqno == irq) {
1364 for (prio = 0; prio <= IVG13-IVG7; prio++) {
1365 if (ivg7_13[prio].ifirst <= ivg &&
1366 ivg7_13[prio].istop > ivg)
1367 return IVG7 + prio;
1368 }
1369 }
1370 }
1371
1372 return IVG15;
1373}
1374
Yi Li6a01f232009-01-07 23:14:39 +08001375/* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */
1376#ifdef CONFIG_DO_IRQ_L1
1377__attribute__((l1_text))
1378#endif
1379asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
1380{
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001381 struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr();
Philippe Geruma40494a2009-06-16 05:25:42 +02001382 struct ipipe_domain *this_domain = __ipipe_current_domain;
Yi Li6a01f232009-01-07 23:14:39 +08001383 struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
1384 struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001385 int irq, s;
Yi Li6a01f232009-01-07 23:14:39 +08001386
Philippe Geruma40494a2009-06-16 05:25:42 +02001387 if (likely(vec == EVT_IVTMR_P))
Yi Li6a01f232009-01-07 23:14:39 +08001388 irq = IRQ_CORETMR;
Philippe Geruma40494a2009-06-16 05:25:42 +02001389 else {
Mike Frysinger780172b2009-06-01 19:43:02 -04001390#if defined(SIC_ISR0) || defined(SICA_ISR0)
Yi Li6a01f232009-01-07 23:14:39 +08001391 unsigned long sic_status[3];
1392
1393 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1394 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001395# ifdef SIC_ISR2
Yi Li6a01f232009-01-07 23:14:39 +08001396 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001397# endif
Yi Li6a01f232009-01-07 23:14:39 +08001398 for (;; ivg++) {
1399 if (ivg >= ivg_stop) {
1400 atomic_inc(&num_spurious);
1401 return 0;
1402 }
1403 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
1404 break;
1405 }
Yi Li6a01f232009-01-07 23:14:39 +08001406#else
Yi Li6a01f232009-01-07 23:14:39 +08001407 unsigned long sic_status;
1408
1409 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1410
1411 for (;; ivg++) {
1412 if (ivg >= ivg_stop) {
1413 atomic_inc(&num_spurious);
1414 return 0;
1415 } else if (sic_status & ivg->isrflag)
1416 break;
1417 }
Yi Li6a01f232009-01-07 23:14:39 +08001418#endif
Graf Yang1fa9be72009-05-15 11:01:59 +00001419 irq = ivg->irqno;
1420 }
Yi Li6a01f232009-01-07 23:14:39 +08001421
1422 if (irq == IRQ_SYSTMR) {
Philippe Geruma40494a2009-06-16 05:25:42 +02001423#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
Yi Li6a01f232009-01-07 23:14:39 +08001424 bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001425#endif
Yi Li6a01f232009-01-07 23:14:39 +08001426 /* This is basically what we need from the register frame. */
1427 __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend;
1428 __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001429 if (this_domain != ipipe_root_domain)
Yi Li6a01f232009-01-07 23:14:39 +08001430 __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001431 else
1432 __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
Yi Li6a01f232009-01-07 23:14:39 +08001433 }
1434
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001435 if (this_domain == ipipe_root_domain) {
1436 s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1437 barrier();
1438 }
Yi Li6a01f232009-01-07 23:14:39 +08001439
1440 ipipe_trace_irq_entry(irq);
1441 __ipipe_handle_irq(irq, regs);
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001442 ipipe_trace_irq_exit(irq);
Yi Li6a01f232009-01-07 23:14:39 +08001443
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001444 if (this_domain == ipipe_root_domain) {
1445 set_thread_flag(TIF_IRQ_SYNC);
1446 if (!s) {
1447 __clear_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1448 return !test_bit(IPIPE_STALL_FLAG, &p->status);
1449 }
1450 }
Yi Li6a01f232009-01-07 23:14:39 +08001451
Graf Yang1fa9be72009-05-15 11:01:59 +00001452 return 0;
Yi Li6a01f232009-01-07 23:14:39 +08001453}
1454
1455#endif /* CONFIG_IPIPE */