blob: 0d84fb28233da543220ebfca2a285c6495dede9a [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>
Bryan Wu1394f032007-05-06 14:50:22 -070029
Mike Frysinger7beb7432008-11-18 17:48:22 +080030#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
31
Bryan Wu1394f032007-05-06 14:50:22 -070032#ifdef BF537_FAMILY
33# define BF537_GENERIC_ERROR_INT_DEMUX
34#else
35# undef BF537_GENERIC_ERROR_INT_DEMUX
36#endif
37
38/*
39 * NOTES:
40 * - we have separated the physical Hardware interrupt from the
41 * levels that the LINUX kernel sees (see the description in irq.h)
42 * -
43 */
44
Graf Yang6b3087c2009-01-07 23:14:39 +080045#ifndef CONFIG_SMP
Mike Frysingera99bbcc2007-10-22 00:19:31 +080046/* Initialize this to an actual value to force it into the .data
47 * section so that we know it is properly initialized at entry into
48 * the kernel but before bss is initialized to zero (which is where
49 * it would live otherwise). The 0x1f magic represents the IRQs we
50 * cannot actually mask out in hardware.
51 */
Mike Frysinger40059782008-11-18 17:48:22 +080052unsigned long bfin_irq_flags = 0x1f;
53EXPORT_SYMBOL(bfin_irq_flags);
Graf Yang6b3087c2009-01-07 23:14:39 +080054#endif
Bryan Wu1394f032007-05-06 14:50:22 -070055
56/* The number of spurious interrupts */
57atomic_t num_spurious;
58
Michael Hennerichcfefe3c2008-02-09 04:12:37 +080059#ifdef CONFIG_PM
60unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */
Michael Hennerich4a88d0c2008-08-05 17:38:41 +080061unsigned vr_wakeup;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +080062#endif
63
Bryan Wu1394f032007-05-06 14:50:22 -070064struct ivgx {
Michael Hennerich464abc52008-02-25 13:50:20 +080065 /* irq number for request_irq, available in mach-bf5xx/irq.h */
Roy Huang24a07a12007-07-12 22:41:45 +080066 unsigned int irqno;
Bryan Wu1394f032007-05-06 14:50:22 -070067 /* corresponding bit in the SIC_ISR register */
Roy Huang24a07a12007-07-12 22:41:45 +080068 unsigned int isrflag;
Bryan Wu1394f032007-05-06 14:50:22 -070069} ivg_table[NR_PERI_INTS];
70
71struct ivg_slice {
72 /* position of first irq in ivg_table for given ivg */
73 struct ivgx *ifirst;
74 struct ivgx *istop;
75} ivg7_13[IVG13 - IVG7 + 1];
76
Bryan Wu1394f032007-05-06 14:50:22 -070077
78/*
79 * Search SIC_IAR and fill tables with the irqvalues
80 * and their positions in the SIC_ISR register.
81 */
82static void __init search_IAR(void)
83{
84 unsigned ivg, irq_pos = 0;
85 for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
86 int irqn;
87
Michael Hennerich34e0fc82007-07-12 16:17:18 +080088 ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
Bryan Wu1394f032007-05-06 14:50:22 -070089
90 for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
91 int iar_shift = (irqn & 7) * 4;
Michael Hennerich2c4f8292008-02-09 04:11:14 +080092 if (ivg == (0xf &
Bryan Wu2f6f4bc2008-11-18 17:48:21 +080093#if defined(CONFIG_BF52x) || defined(CONFIG_BF538) \
94 || defined(CONFIG_BF539) || defined(CONFIG_BF51x)
Michael Hennerich34e0fc82007-07-12 16:17:18 +080095 bfin_read32((unsigned long *)SIC_IAR0 +
Michael Hennerichdc26aec2008-11-18 17:48:22 +080096 ((irqn % 32) >> 3) + ((irqn / 32) *
97 ((SIC_IAR4 - SIC_IAR0) / 4))) >> iar_shift)) {
Michael Hennerich59003142007-10-21 16:54:27 +080098#else
99 bfin_read32((unsigned long *)SIC_IAR0 +
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800100 (irqn >> 3)) >> iar_shift)) {
Michael Hennerich59003142007-10-21 16:54:27 +0800101#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700102 ivg_table[irq_pos].irqno = IVG7 + irqn;
Roy Huang24a07a12007-07-12 22:41:45 +0800103 ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
Bryan Wu1394f032007-05-06 14:50:22 -0700104 ivg7_13[ivg].istop++;
105 irq_pos++;
106 }
107 }
108 }
109}
110
111/*
Michael Hennerich464abc52008-02-25 13:50:20 +0800112 * This is for core internal IRQs
Bryan Wu1394f032007-05-06 14:50:22 -0700113 */
114
Michael Hennerich464abc52008-02-25 13:50:20 +0800115static void bfin_ack_noop(unsigned int irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700116{
117 /* Dummy function. */
118}
119
120static void bfin_core_mask_irq(unsigned int irq)
121{
Mike Frysinger40059782008-11-18 17:48:22 +0800122 bfin_irq_flags &= ~(1 << irq);
Yi Li6a01f232009-01-07 23:14:39 +0800123 if (!irqs_disabled_hw())
124 local_irq_enable_hw();
Bryan Wu1394f032007-05-06 14:50:22 -0700125}
126
127static void bfin_core_unmask_irq(unsigned int irq)
128{
Mike Frysinger40059782008-11-18 17:48:22 +0800129 bfin_irq_flags |= 1 << irq;
Bryan Wu1394f032007-05-06 14:50:22 -0700130 /*
131 * If interrupts are enabled, IMASK must contain the same value
Mike Frysinger40059782008-11-18 17:48:22 +0800132 * as bfin_irq_flags. Make sure that invariant holds. If interrupts
Bryan Wu1394f032007-05-06 14:50:22 -0700133 * are currently disabled we need not do anything; one of the
134 * callers will take care of setting IMASK to the proper value
135 * when reenabling interrupts.
Mike Frysinger40059782008-11-18 17:48:22 +0800136 * local_irq_enable just does "STI bfin_irq_flags", so it's exactly
Bryan Wu1394f032007-05-06 14:50:22 -0700137 * what we need.
138 */
Yi Li6a01f232009-01-07 23:14:39 +0800139 if (!irqs_disabled_hw())
140 local_irq_enable_hw();
Bryan Wu1394f032007-05-06 14:50:22 -0700141 return;
142}
143
144static void bfin_internal_mask_irq(unsigned int irq)
145{
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800146 unsigned long flags;
147
Michael Hennerich59003142007-10-21 16:54:27 +0800148#ifdef CONFIG_BF53x
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800149 local_irq_save_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700150 bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
Michael Hennerich464abc52008-02-25 13:50:20 +0800151 ~(1 << SIC_SYSIRQ(irq)));
Roy Huang24a07a12007-07-12 22:41:45 +0800152#else
153 unsigned mask_bank, mask_bit;
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800154 local_irq_save_hw(flags);
Michael Hennerich464abc52008-02-25 13:50:20 +0800155 mask_bank = SIC_SYSIRQ(irq) / 32;
156 mask_bit = SIC_SYSIRQ(irq) % 32;
Bryan Wuc04d66b2007-07-12 17:26:31 +0800157 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
158 ~(1 << mask_bit));
Graf Yang6b3087c2009-01-07 23:14:39 +0800159#ifdef CONFIG_SMP
160 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
161 ~(1 << mask_bit));
162#endif
Roy Huang24a07a12007-07-12 22:41:45 +0800163#endif
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800164 local_irq_restore_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700165}
166
167static void bfin_internal_unmask_irq(unsigned int irq)
168{
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800169 unsigned long flags;
170
Michael Hennerich59003142007-10-21 16:54:27 +0800171#ifdef CONFIG_BF53x
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800172 local_irq_save_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700173 bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
Michael Hennerich464abc52008-02-25 13:50:20 +0800174 (1 << SIC_SYSIRQ(irq)));
Roy Huang24a07a12007-07-12 22:41:45 +0800175#else
176 unsigned mask_bank, mask_bit;
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800177 local_irq_save_hw(flags);
Michael Hennerich464abc52008-02-25 13:50:20 +0800178 mask_bank = SIC_SYSIRQ(irq) / 32;
179 mask_bit = SIC_SYSIRQ(irq) % 32;
Bryan Wuc04d66b2007-07-12 17:26:31 +0800180 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
181 (1 << mask_bit));
Graf Yang6b3087c2009-01-07 23:14:39 +0800182#ifdef CONFIG_SMP
183 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) |
184 (1 << mask_bit));
185#endif
Roy Huang24a07a12007-07-12 22:41:45 +0800186#endif
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800187 local_irq_restore_hw(flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700188}
189
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800190#ifdef CONFIG_PM
191int bfin_internal_set_wake(unsigned int irq, unsigned int state)
192{
Michael Hennerich8d022372008-11-18 17:48:22 +0800193 u32 bank, bit, wakeup = 0;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800194 unsigned long flags;
Michael Hennerich464abc52008-02-25 13:50:20 +0800195 bank = SIC_SYSIRQ(irq) / 32;
196 bit = SIC_SYSIRQ(irq) % 32;
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800197
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800198 switch (irq) {
199#ifdef IRQ_RTC
200 case IRQ_RTC:
201 wakeup |= WAKE;
202 break;
203#endif
204#ifdef IRQ_CAN0_RX
205 case IRQ_CAN0_RX:
206 wakeup |= CANWE;
207 break;
208#endif
209#ifdef IRQ_CAN1_RX
210 case IRQ_CAN1_RX:
211 wakeup |= CANWE;
212 break;
213#endif
214#ifdef IRQ_USB_INT0
215 case IRQ_USB_INT0:
216 wakeup |= USBWE;
217 break;
218#endif
219#ifdef IRQ_KEY
220 case IRQ_KEY:
221 wakeup |= KPADWE;
222 break;
223#endif
Michael Hennerichd310fb42008-08-28 17:32:01 +0800224#ifdef CONFIG_BF54x
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800225 case IRQ_CNT:
226 wakeup |= ROTWE;
227 break;
228#endif
229 default:
230 break;
231 }
232
Yi Li6a01f232009-01-07 23:14:39 +0800233 local_irq_save_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800234
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800235 if (state) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800236 bfin_sic_iwr[bank] |= (1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800237 vr_wakeup |= wakeup;
238
239 } else {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800240 bfin_sic_iwr[bank] &= ~(1 << bit);
Michael Hennerich4a88d0c2008-08-05 17:38:41 +0800241 vr_wakeup &= ~wakeup;
242 }
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800243
Yi Li6a01f232009-01-07 23:14:39 +0800244 local_irq_restore_hw(flags);
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800245
246 return 0;
247}
248#endif
249
Bryan Wu1394f032007-05-06 14:50:22 -0700250static struct irq_chip bfin_core_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800251 .name = "CORE",
Michael Hennerich464abc52008-02-25 13:50:20 +0800252 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700253 .mask = bfin_core_mask_irq,
254 .unmask = bfin_core_unmask_irq,
255};
256
257static struct irq_chip bfin_internal_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800258 .name = "INTN",
Michael Hennerich464abc52008-02-25 13:50:20 +0800259 .ack = bfin_ack_noop,
Bryan Wu1394f032007-05-06 14:50:22 -0700260 .mask = bfin_internal_mask_irq,
261 .unmask = bfin_internal_unmask_irq,
Michael Hennerichce3b7bb2008-02-25 13:48:47 +0800262 .mask_ack = bfin_internal_mask_irq,
263 .disable = bfin_internal_mask_irq,
264 .enable = bfin_internal_unmask_irq,
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800265#ifdef CONFIG_PM
266 .set_wake = bfin_internal_set_wake,
267#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700268};
269
Yi Li6a01f232009-01-07 23:14:39 +0800270static void bfin_handle_irq(unsigned irq)
271{
272#ifdef CONFIG_IPIPE
273 struct pt_regs regs; /* Contents not used. */
274 ipipe_trace_irq_entry(irq);
275 __ipipe_handle_irq(irq, &regs);
276 ipipe_trace_irq_exit(irq);
277#else /* !CONFIG_IPIPE */
278 struct irq_desc *desc = irq_desc + irq;
279 desc->handle_irq(irq, desc);
280#endif /* !CONFIG_IPIPE */
281}
282
Bryan Wu1394f032007-05-06 14:50:22 -0700283#ifdef BF537_GENERIC_ERROR_INT_DEMUX
284static int error_int_mask;
285
Bryan Wu1394f032007-05-06 14:50:22 -0700286static void bfin_generic_error_mask_irq(unsigned int irq)
287{
288 error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
289
Michael Hennerich464abc52008-02-25 13:50:20 +0800290 if (!error_int_mask)
291 bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700292}
293
294static void bfin_generic_error_unmask_irq(unsigned int irq)
295{
Michael Hennerich464abc52008-02-25 13:50:20 +0800296 bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
Bryan Wu1394f032007-05-06 14:50:22 -0700297 error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
298}
299
300static struct irq_chip bfin_generic_error_irqchip = {
Graf Yang763e63c2008-10-08 17:08:15 +0800301 .name = "ERROR",
Michael Hennerich464abc52008-02-25 13:50:20 +0800302 .ack = bfin_ack_noop,
303 .mask_ack = bfin_generic_error_mask_irq,
Bryan Wu1394f032007-05-06 14:50:22 -0700304 .mask = bfin_generic_error_mask_irq,
305 .unmask = bfin_generic_error_unmask_irq,
306};
307
308static void bfin_demux_error_irq(unsigned int int_err_irq,
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800309 struct irq_desc *inta_desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700310{
311 int irq = 0;
312
Bryan Wu1394f032007-05-06 14:50:22 -0700313#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
314 if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
315 irq = IRQ_MAC_ERROR;
316 else
317#endif
318 if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
319 irq = IRQ_SPORT0_ERROR;
320 else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
321 irq = IRQ_SPORT1_ERROR;
322 else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
323 irq = IRQ_PPI_ERROR;
324 else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
325 irq = IRQ_CAN_ERROR;
326 else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
327 irq = IRQ_SPI_ERROR;
328 else if ((bfin_read_UART0_IIR() & UART_ERR_MASK_STAT1) &&
329 (bfin_read_UART0_IIR() & UART_ERR_MASK_STAT0))
330 irq = IRQ_UART0_ERROR;
331 else if ((bfin_read_UART1_IIR() & UART_ERR_MASK_STAT1) &&
332 (bfin_read_UART1_IIR() & UART_ERR_MASK_STAT0))
333 irq = IRQ_UART1_ERROR;
334
335 if (irq) {
Yi Li6a01f232009-01-07 23:14:39 +0800336 if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
337 bfin_handle_irq(irq);
338 else {
Bryan Wu1394f032007-05-06 14:50:22 -0700339
340 switch (irq) {
341 case IRQ_PPI_ERROR:
342 bfin_write_PPI_STATUS(PPI_ERR_MASK);
343 break;
344#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
345 case IRQ_MAC_ERROR:
346 bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
347 break;
348#endif
349 case IRQ_SPORT0_ERROR:
350 bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
351 break;
352
353 case IRQ_SPORT1_ERROR:
354 bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
355 break;
356
357 case IRQ_CAN_ERROR:
358 bfin_write_CAN_GIS(CAN_ERR_MASK);
359 break;
360
361 case IRQ_SPI_ERROR:
362 bfin_write_SPI_STAT(SPI_ERR_MASK);
363 break;
364
365 default:
366 break;
367 }
368
369 pr_debug("IRQ %d:"
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800370 " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
371 irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700372 }
373 } else
374 printk(KERN_ERR
375 "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
376 " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
Harvey Harrisonb85d8582008-04-23 09:39:01 +0800377 __func__, __FILE__, __LINE__);
Bryan Wu1394f032007-05-06 14:50:22 -0700378
Bryan Wu1394f032007-05-06 14:50:22 -0700379}
380#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
381
Graf Yangbfd15112008-10-08 18:02:44 +0800382static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
383{
Yi Li6a01f232009-01-07 23:14:39 +0800384#ifdef CONFIG_IPIPE
Philippe Gerum9bd50df2009-03-04 16:52:38 +0800385 _set_irq_handler(irq, handle_level_irq);
Yi Li6a01f232009-01-07 23:14:39 +0800386#else
Graf Yangbfd15112008-10-08 18:02:44 +0800387 struct irq_desc *desc = irq_desc + irq;
388 /* May not call generic set_irq_handler() due to spinlock
389 recursion. */
390 desc->handle_irq = handle;
Yi Li6a01f232009-01-07 23:14:39 +0800391#endif
Graf Yangbfd15112008-10-08 18:02:44 +0800392}
393
Michael Hennerich8d022372008-11-18 17:48:22 +0800394static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800395extern void bfin_gpio_irq_prepare(unsigned gpio);
Michael Hennerich6fce6a82007-12-24 16:56:12 +0800396
Michael Hennerich8d022372008-11-18 17:48:22 +0800397#if !defined(CONFIG_BF54x)
398
Bryan Wu1394f032007-05-06 14:50:22 -0700399static void bfin_gpio_ack_irq(unsigned int irq)
400{
Michael Hennerich8d022372008-11-18 17:48:22 +0800401 /* AFAIK ack_irq in case mask_ack is provided
402 * get's only called for edge sense irqs
403 */
404 set_gpio_data(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700405}
406
407static void bfin_gpio_mask_ack_irq(unsigned int irq)
408{
Michael Hennerich8d022372008-11-18 17:48:22 +0800409 struct irq_desc *desc = irq_desc + irq;
410 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700411
Michael Hennerich8d022372008-11-18 17:48:22 +0800412 if (desc->handle_irq == handle_edge_irq)
Bryan Wu1394f032007-05-06 14:50:22 -0700413 set_gpio_data(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700414
415 set_gpio_maska(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700416}
417
418static void bfin_gpio_mask_irq(unsigned int irq)
419{
Michael Hennerich8d022372008-11-18 17:48:22 +0800420 set_gpio_maska(irq_to_gpio(irq), 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700421}
422
423static void bfin_gpio_unmask_irq(unsigned int irq)
424{
Michael Hennerich8d022372008-11-18 17:48:22 +0800425 set_gpio_maska(irq_to_gpio(irq), 1);
Bryan Wu1394f032007-05-06 14:50:22 -0700426}
427
428static unsigned int bfin_gpio_irq_startup(unsigned int irq)
429{
Michael Hennerich8d022372008-11-18 17:48:22 +0800430 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700431
Michael Hennerich8d022372008-11-18 17:48:22 +0800432 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800433 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700434
Bryan Wu1394f032007-05-06 14:50:22 -0700435 bfin_gpio_unmask_irq(irq);
436
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800437 return 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700438}
439
440static void bfin_gpio_irq_shutdown(unsigned int irq)
441{
Graf Yang30af6d42008-11-18 17:48:21 +0800442 u32 gpionr = irq_to_gpio(irq);
443
Bryan Wu1394f032007-05-06 14:50:22 -0700444 bfin_gpio_mask_irq(irq);
Graf Yang30af6d42008-11-18 17:48:21 +0800445 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800446 bfin_gpio_irq_free(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700447}
448
449static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
450{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800451 int ret;
452 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800453 u32 gpionr = irq_to_gpio(irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700454
455 if (type == IRQ_TYPE_PROBE) {
456 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400457 if (test_bit(gpionr, gpio_enabled))
Bryan Wu1394f032007-05-06 14:50:22 -0700458 return 0;
459 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
460 }
461
462 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800463 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Michael Hennerich8d022372008-11-18 17:48:22 +0800464
Graf Yang9570ff42009-01-07 23:14:38 +0800465 snprintf(buf, 16, "gpio-irq%d", irq);
466 ret = bfin_gpio_irq_request(gpionr, buf);
467 if (ret)
468 return ret;
469
Michael Hennerich8d022372008-11-18 17:48:22 +0800470 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800471 bfin_gpio_irq_prepare(gpionr);
Bryan Wu1394f032007-05-06 14:50:22 -0700472
Bryan Wu1394f032007-05-06 14:50:22 -0700473 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800474 __clear_bit(gpionr, gpio_enabled);
Bryan Wu1394f032007-05-06 14:50:22 -0700475 return 0;
476 }
477
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800478 set_gpio_inen(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700479 set_gpio_dir(gpionr, 0);
Bryan Wu1394f032007-05-06 14:50:22 -0700480
481 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
482 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
483 set_gpio_both(gpionr, 1);
484 else
485 set_gpio_both(gpionr, 0);
486
487 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
488 set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
489 else
490 set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
491
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800492 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
493 set_gpio_edge(gpionr, 1);
494 set_gpio_inen(gpionr, 1);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800495 set_gpio_data(gpionr, 0);
496
497 } else {
498 set_gpio_edge(gpionr, 0);
Michael Hennerichf1bceb42008-02-02 16:17:52 +0800499 set_gpio_inen(gpionr, 1);
500 }
501
Bryan Wu1394f032007-05-06 14:50:22 -0700502 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
Graf Yangbfd15112008-10-08 18:02:44 +0800503 bfin_set_irq_handler(irq, handle_edge_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700504 else
Graf Yangbfd15112008-10-08 18:02:44 +0800505 bfin_set_irq_handler(irq, handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -0700506
507 return 0;
508}
509
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800510#ifdef CONFIG_PM
511int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
512{
513 unsigned gpio = irq_to_gpio(irq);
514
515 if (state)
516 gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE);
517 else
518 gpio_pm_wakeup_free(gpio);
519
520 return 0;
521}
522#endif
523
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800524static void bfin_demux_gpio_irq(unsigned int inta_irq,
525 struct irq_desc *desc)
Bryan Wu1394f032007-05-06 14:50:22 -0700526{
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800527 unsigned int i, gpio, mask, irq, search = 0;
Bryan Wu1394f032007-05-06 14:50:22 -0700528
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800529 switch (inta_irq) {
530#if defined(CONFIG_BF53x)
531 case IRQ_PROG_INTA:
532 irq = IRQ_PF0;
533 search = 1;
534 break;
535# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
536 case IRQ_MAC_RX:
537 irq = IRQ_PH0;
538 break;
539# endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +0800540#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
541 case IRQ_PORTF_INTA:
542 irq = IRQ_PF0;
543 break;
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800544#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800545 case IRQ_PORTF_INTA:
546 irq = IRQ_PF0;
547 break;
548 case IRQ_PORTG_INTA:
549 irq = IRQ_PG0;
550 break;
551 case IRQ_PORTH_INTA:
552 irq = IRQ_PH0;
553 break;
554#elif defined(CONFIG_BF561)
555 case IRQ_PROG0_INTA:
556 irq = IRQ_PF0;
557 break;
558 case IRQ_PROG1_INTA:
559 irq = IRQ_PF16;
560 break;
561 case IRQ_PROG2_INTA:
562 irq = IRQ_PF32;
563 break;
564#endif
565 default:
566 BUG();
567 return;
Bryan Wu1394f032007-05-06 14:50:22 -0700568 }
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800569
570 if (search) {
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800571 for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800572 irq += i;
573
Michael Hennerich8d022372008-11-18 17:48:22 +0800574 mask = get_gpiop_data(i) & get_gpiop_maska(i);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800575
576 while (mask) {
Yi Li6a01f232009-01-07 23:14:39 +0800577 if (mask & 1)
578 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800579 irq++;
580 mask >>= 1;
581 }
582 }
583 } else {
584 gpio = irq_to_gpio(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800585 mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800586
587 do {
Yi Li6a01f232009-01-07 23:14:39 +0800588 if (mask & 1)
589 bfin_handle_irq(irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800590 irq++;
591 mask >>= 1;
592 } while (mask);
593 }
594
Bryan Wu1394f032007-05-06 14:50:22 -0700595}
596
Mike Frysingera055b2b2007-11-15 21:12:32 +0800597#else /* CONFIG_BF54x */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800598
599#define NR_PINT_SYS_IRQS 4
600#define NR_PINT_BITS 32
601#define NR_PINTS 160
602#define IRQ_NOT_AVAIL 0xFF
603
604#define PINT_2_BANK(x) ((x) >> 5)
605#define PINT_2_BIT(x) ((x) & 0x1F)
606#define PINT_BIT(x) (1 << (PINT_2_BIT(x)))
607
608static unsigned char irq2pint_lut[NR_PINTS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800609static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800610
611struct pin_int_t {
612 unsigned int mask_set;
613 unsigned int mask_clear;
614 unsigned int request;
615 unsigned int assign;
616 unsigned int edge_set;
617 unsigned int edge_clear;
618 unsigned int invert_set;
619 unsigned int invert_clear;
620 unsigned int pinstate;
621 unsigned int latch;
622};
623
624static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
625 (struct pin_int_t *)PINT0_MASK_SET,
626 (struct pin_int_t *)PINT1_MASK_SET,
627 (struct pin_int_t *)PINT2_MASK_SET,
628 (struct pin_int_t *)PINT3_MASK_SET,
629};
630
Michael Hennerich8d022372008-11-18 17:48:22 +0800631inline unsigned int get_irq_base(u32 bank, u8 bmap)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800632{
Michael Hennerich8d022372008-11-18 17:48:22 +0800633 unsigned int irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800634
635 if (bank < 2) { /*PA-PB */
636 irq_base = IRQ_PA0 + bmap * 16;
637 } else { /*PC-PJ */
638 irq_base = IRQ_PC0 + bmap * 16;
639 }
640
641 return irq_base;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800642}
643
644 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
645void init_pint_lut(void)
646{
647 u16 bank, bit, irq_base, bit_pos;
648 u32 pint_assign;
649 u8 bmap;
650
651 memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut));
652
653 for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) {
654
655 pint_assign = pint[bank]->assign;
656
657 for (bit = 0; bit < NR_PINT_BITS; bit++) {
658
659 bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF;
660
661 irq_base = get_irq_base(bank, bmap);
662
663 irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0);
664 bit_pos = bit + bank * NR_PINT_BITS;
665
Michael Henneriche3f23002007-07-12 16:39:29 +0800666 pint2irq_lut[bit_pos] = irq_base - SYS_IRQS;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800667 irq2pint_lut[irq_base - SYS_IRQS] = bit_pos;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800668 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800669 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800670}
671
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800672static void bfin_gpio_ack_irq(unsigned int irq)
673{
Michael Hennerich8d022372008-11-18 17:48:22 +0800674 struct irq_desc *desc = irq_desc + irq;
675 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich8baf5602007-12-24 18:51:34 +0800676 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800677 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800678
Michael Hennerich8d022372008-11-18 17:48:22 +0800679 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800680 if (pint[bank]->invert_set & pintbit)
681 pint[bank]->invert_clear = pintbit;
682 else
683 pint[bank]->invert_set = pintbit;
684 }
685 pint[bank]->request = pintbit;
686
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800687}
688
689static void bfin_gpio_mask_ack_irq(unsigned int irq)
690{
Michael Hennerich8d022372008-11-18 17:48:22 +0800691 struct irq_desc *desc = irq_desc + irq;
692 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800693 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800694 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800695
Michael Hennerich8d022372008-11-18 17:48:22 +0800696 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800697 if (pint[bank]->invert_set & pintbit)
698 pint[bank]->invert_clear = pintbit;
699 else
700 pint[bank]->invert_set = pintbit;
701 }
702
Michael Henneriche3f23002007-07-12 16:39:29 +0800703 pint[bank]->request = pintbit;
704 pint[bank]->mask_clear = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800705}
706
707static void bfin_gpio_mask_irq(unsigned int irq)
708{
Michael Hennerich8d022372008-11-18 17:48:22 +0800709 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800710
711 pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800712}
713
714static void bfin_gpio_unmask_irq(unsigned int irq)
715{
Michael Hennerich8d022372008-11-18 17:48:22 +0800716 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800717 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800718 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800719
Michael Henneriche3f23002007-07-12 16:39:29 +0800720 pint[bank]->request = pintbit;
721 pint[bank]->mask_set = pintbit;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800722}
723
724static unsigned int bfin_gpio_irq_startup(unsigned int irq)
725{
Michael Hennerich8d022372008-11-18 17:48:22 +0800726 u32 gpionr = irq_to_gpio(irq);
727 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800728
Michael Hennerich50e163c2007-07-24 16:17:28 +0800729 if (pint_val == IRQ_NOT_AVAIL) {
730 printk(KERN_ERR
731 "GPIO IRQ %d :Not in PINT Assign table "
732 "Reconfigure Interrupt to Port Assignemt\n", irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800733 return -ENODEV;
Michael Hennerich50e163c2007-07-24 16:17:28 +0800734 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800735
Michael Hennerich8d022372008-11-18 17:48:22 +0800736 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800737 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800738
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800739 bfin_gpio_unmask_irq(irq);
740
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800741 return 0;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800742}
743
744static void bfin_gpio_irq_shutdown(unsigned int irq)
745{
Michael Hennerich8d022372008-11-18 17:48:22 +0800746 u32 gpionr = irq_to_gpio(irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800747
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800748 bfin_gpio_mask_irq(irq);
Michael Hennerich8d022372008-11-18 17:48:22 +0800749 __clear_bit(gpionr, gpio_enabled);
Graf Yang9570ff42009-01-07 23:14:38 +0800750 bfin_gpio_irq_free(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800751}
752
753static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
754{
Graf Yang8eb3e3b2008-11-18 17:48:22 +0800755 int ret;
756 char buf[16];
Michael Hennerich8d022372008-11-18 17:48:22 +0800757 u32 gpionr = irq_to_gpio(irq);
758 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Henneriche3f23002007-07-12 16:39:29 +0800759 u32 pintbit = PINT_BIT(pint_val);
Michael Hennerich8d022372008-11-18 17:48:22 +0800760 u32 bank = PINT_2_BANK(pint_val);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800761
762 if (pint_val == IRQ_NOT_AVAIL)
763 return -ENODEV;
764
765 if (type == IRQ_TYPE_PROBE) {
766 /* only probe unenabled GPIO interrupt lines */
Mike Frysingerc3695342009-06-13 10:32:29 -0400767 if (test_bit(gpionr, gpio_enabled))
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800768 return 0;
769 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
770 }
771
772 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
773 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
Graf Yang9570ff42009-01-07 23:14:38 +0800774
775 snprintf(buf, 16, "gpio-irq%d", irq);
776 ret = bfin_gpio_irq_request(gpionr, buf);
777 if (ret)
778 return ret;
779
Michael Hennerich8d022372008-11-18 17:48:22 +0800780 if (__test_and_set_bit(gpionr, gpio_enabled))
Michael Hennerichaffee2b2008-04-24 08:10:10 +0800781 bfin_gpio_irq_prepare(gpionr);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800782
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800783 } else {
Michael Hennerich8d022372008-11-18 17:48:22 +0800784 __clear_bit(gpionr, gpio_enabled);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800785 return 0;
786 }
787
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800788 if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
Michael Henneriche3f23002007-07-12 16:39:29 +0800789 pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800790 else
Michael Hennerich8baf5602007-12-24 18:51:34 +0800791 pint[bank]->invert_clear = pintbit; /* high or rising edge denoted by zero */
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800792
Michael Hennerich8baf5602007-12-24 18:51:34 +0800793 if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
794 == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
Michael Hennerich8baf5602007-12-24 18:51:34 +0800795 if (gpio_get_value(gpionr))
796 pint[bank]->invert_set = pintbit;
797 else
798 pint[bank]->invert_clear = pintbit;
Michael Hennerich8baf5602007-12-24 18:51:34 +0800799 }
800
801 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
802 pint[bank]->edge_set = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800803 bfin_set_irq_handler(irq, handle_edge_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800804 } else {
805 pint[bank]->edge_clear = pintbit;
Graf Yangbfd15112008-10-08 18:02:44 +0800806 bfin_set_irq_handler(irq, handle_level_irq);
Michael Hennerich8baf5602007-12-24 18:51:34 +0800807 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800808
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800809 return 0;
810}
811
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800812#ifdef CONFIG_PM
813u32 pint_saved_masks[NR_PINT_SYS_IRQS];
814u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
815
816int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
817{
818 u32 pint_irq;
Michael Hennerich8d022372008-11-18 17:48:22 +0800819 u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
Michael Hennerichcfefe3c2008-02-09 04:12:37 +0800820 u32 bank = PINT_2_BANK(pint_val);
821 u32 pintbit = PINT_BIT(pint_val);
822
823 switch (bank) {
824 case 0:
825 pint_irq = IRQ_PINT0;
826 break;
827 case 2:
828 pint_irq = IRQ_PINT2;
829 break;
830 case 3:
831 pint_irq = IRQ_PINT3;
832 break;
833 case 1:
834 pint_irq = IRQ_PINT1;
835 break;
836 default:
837 return -EINVAL;
838 }
839
840 bfin_internal_set_wake(pint_irq, state);
841
842 if (state)
843 pint_wakeup_masks[bank] |= pintbit;
844 else
845 pint_wakeup_masks[bank] &= ~pintbit;
846
847 return 0;
848}
849
850u32 bfin_pm_setup(void)
851{
852 u32 val, i;
853
854 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
855 val = pint[i]->mask_clear;
856 pint_saved_masks[i] = val;
857 if (val ^ pint_wakeup_masks[i]) {
858 pint[i]->mask_clear = val;
859 pint[i]->mask_set = pint_wakeup_masks[i];
860 }
861 }
862
863 return 0;
864}
865
866void bfin_pm_restore(void)
867{
868 u32 i, val;
869
870 for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
871 val = pint_saved_masks[i];
872 if (val ^ pint_wakeup_masks[i]) {
873 pint[i]->mask_clear = pint[i]->mask_clear;
874 pint[i]->mask_set = val;
875 }
876 }
877}
878#endif
879
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800880static void bfin_demux_gpio_irq(unsigned int inta_irq,
881 struct irq_desc *desc)
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800882{
Michael Hennerich8d022372008-11-18 17:48:22 +0800883 u32 bank, pint_val;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800884 u32 request, irq;
885
Michael Hennerich2c4f8292008-02-09 04:11:14 +0800886 switch (inta_irq) {
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800887 case IRQ_PINT0:
888 bank = 0;
889 break;
890 case IRQ_PINT2:
891 bank = 2;
892 break;
893 case IRQ_PINT3:
894 bank = 3;
895 break;
896 case IRQ_PINT1:
897 bank = 1;
898 break;
Michael Henneriche3f23002007-07-12 16:39:29 +0800899 default:
900 return;
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800901 }
902
903 pint_val = bank * NR_PINT_BITS;
904
905 request = pint[bank]->request;
906
907 while (request) {
908 if (request & 1) {
Michael Henneriche3f23002007-07-12 16:39:29 +0800909 irq = pint2irq_lut[pint_val] + SYS_IRQS;
Yi Li6a01f232009-01-07 23:14:39 +0800910 bfin_handle_irq(irq);
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800911 }
912 pint_val++;
913 request >>= 1;
914 }
915
916}
Mike Frysingera055b2b2007-11-15 21:12:32 +0800917#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700918
Michael Hennerich8d022372008-11-18 17:48:22 +0800919static struct irq_chip bfin_gpio_irqchip = {
920 .name = "GPIO",
921 .ack = bfin_gpio_ack_irq,
922 .mask = bfin_gpio_mask_irq,
923 .mask_ack = bfin_gpio_mask_ack_irq,
924 .unmask = bfin_gpio_unmask_irq,
925 .disable = bfin_gpio_mask_irq,
926 .enable = bfin_gpio_unmask_irq,
927 .set_type = bfin_gpio_irq_type,
928 .startup = bfin_gpio_irq_startup,
929 .shutdown = bfin_gpio_irq_shutdown,
930#ifdef CONFIG_PM
931 .set_wake = bfin_gpio_set_wake,
932#endif
933};
934
Graf Yang6b3087c2009-01-07 23:14:39 +0800935void __cpuinit init_exception_vectors(void)
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800936{
Mike Frysingerf0b5d122007-08-05 17:03:59 +0800937 /* cannot program in software:
938 * evt0 - emulation (jtag)
939 * evt1 - reset
940 */
941 bfin_write_EVT2(evt_nmi);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800942 bfin_write_EVT3(trap);
943 bfin_write_EVT5(evt_ivhw);
944 bfin_write_EVT6(evt_timer);
945 bfin_write_EVT7(evt_evt7);
946 bfin_write_EVT8(evt_evt8);
947 bfin_write_EVT9(evt_evt9);
948 bfin_write_EVT10(evt_evt10);
949 bfin_write_EVT11(evt_evt11);
950 bfin_write_EVT12(evt_evt12);
951 bfin_write_EVT13(evt_evt13);
Philippe Gerum9703a732009-06-22 18:23:48 +0200952 bfin_write_EVT14(evt_evt14);
Bernd Schmidt8be80ed2007-07-25 14:44:49 +0800953 bfin_write_EVT15(evt_system_call);
954 CSYNC();
955}
956
Bryan Wu1394f032007-05-06 14:50:22 -0700957/*
958 * This function should be called during kernel startup to initialize
959 * the BFin IRQ handling routines.
960 */
Michael Hennerich8d022372008-11-18 17:48:22 +0800961
Bryan Wu1394f032007-05-06 14:50:22 -0700962int __init init_arch_irq(void)
963{
964 int irq;
965 unsigned long ilat = 0;
966 /* Disable all the peripheral intrs - page 4-29 HW Ref manual */
Bryan Wu2f6f4bc2008-11-18 17:48:21 +0800967#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
968 || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
Roy Huang24a07a12007-07-12 22:41:45 +0800969 bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
970 bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +0800971# ifdef CONFIG_BF54x
Michael Hennerich59003142007-10-21 16:54:27 +0800972 bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
Mike Frysingera055b2b2007-11-15 21:12:32 +0800973# endif
Graf Yang6b3087c2009-01-07 23:14:39 +0800974# ifdef CONFIG_SMP
975 bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);
976 bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);
977# endif
Roy Huang24a07a12007-07-12 22:41:45 +0800978#else
Bryan Wu1394f032007-05-06 14:50:22 -0700979 bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
Roy Huang24a07a12007-07-12 22:41:45 +0800980#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700981
982 local_irq_disable();
983
Mike Frysingerd70536e2008-08-25 17:37:35 +0800984#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
Mike Frysinger95a86b52008-08-14 15:05:01 +0800985 /* Clear EMAC Interrupt Status bits so we can demux it later */
986 bfin_write_EMAC_SYSTAT(-1);
987#endif
988
Mike Frysingera055b2b2007-11-15 21:12:32 +0800989#ifdef CONFIG_BF54x
990# ifdef CONFIG_PINTx_REASSIGN
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800991 pint[0]->assign = CONFIG_PINT0_ASSIGN;
992 pint[1]->assign = CONFIG_PINT1_ASSIGN;
993 pint[2]->assign = CONFIG_PINT2_ASSIGN;
994 pint[3]->assign = CONFIG_PINT3_ASSIGN;
Mike Frysingera055b2b2007-11-15 21:12:32 +0800995# endif
Michael Hennerich34e0fc82007-07-12 16:17:18 +0800996 /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
997 init_pint_lut();
998#endif
999
1000 for (irq = 0; irq <= SYS_IRQS; irq++) {
Bryan Wu1394f032007-05-06 14:50:22 -07001001 if (irq <= IRQ_CORETMR)
1002 set_irq_chip(irq, &bfin_core_irqchip);
1003 else
1004 set_irq_chip(irq, &bfin_internal_irqchip);
Bryan Wu1394f032007-05-06 14:50:22 -07001005
Michael Hennerich464abc52008-02-25 13:50:20 +08001006 switch (irq) {
Michael Hennerich59003142007-10-21 16:54:27 +08001007#if defined(CONFIG_BF53x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001008 case IRQ_PROG_INTA:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001009# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
Michael Hennerich464abc52008-02-25 13:50:20 +08001010 case IRQ_MAC_RX:
Mike Frysingera055b2b2007-11-15 21:12:32 +08001011# endif
Michael Hennerich59003142007-10-21 16:54:27 +08001012#elif defined(CONFIG_BF54x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001013 case IRQ_PINT0:
1014 case IRQ_PINT1:
1015 case IRQ_PINT2:
1016 case IRQ_PINT3:
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001017#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
Michael Hennerich464abc52008-02-25 13:50:20 +08001018 case IRQ_PORTF_INTA:
1019 case IRQ_PORTG_INTA:
1020 case IRQ_PORTH_INTA:
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001021#elif defined(CONFIG_BF561)
Michael Hennerich464abc52008-02-25 13:50:20 +08001022 case IRQ_PROG0_INTA:
1023 case IRQ_PROG1_INTA:
1024 case IRQ_PROG2_INTA:
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001025#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
1026 case IRQ_PORTF_INTA:
Michael Hennerich59003142007-10-21 16:54:27 +08001027#endif
Michael Hennerichdc26aec2008-11-18 17:48:22 +08001028
Michael Hennerich464abc52008-02-25 13:50:20 +08001029 set_irq_chained_handler(irq,
1030 bfin_demux_gpio_irq);
1031 break;
Bryan Wu1394f032007-05-06 14:50:22 -07001032#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001033 case IRQ_GENERIC_ERROR:
Yi Li6a01f232009-01-07 23:14:39 +08001034 set_irq_chained_handler(irq, bfin_demux_error_irq);
Michael Hennerich464abc52008-02-25 13:50:20 +08001035 break;
1036#endif
Graf Yang179413142009-08-18 04:29:33 +00001037
Graf Yang6b3087c2009-01-07 23:14:39 +08001038#ifdef CONFIG_SMP
Graf Yang179413142009-08-18 04:29:33 +00001039#ifdef CONFIG_TICKSOURCE_GPTMR0
1040 case IRQ_TIMER0:
1041#endif
1042#ifdef CONFIG_TICKSOURCE_CORETMR
1043 case IRQ_CORETMR:
1044#endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001045 case IRQ_SUPPLE_0:
1046 case IRQ_SUPPLE_1:
1047 set_irq_handler(irq, handle_percpu_irq);
1048 break;
1049#endif
Graf Yang179413142009-08-18 04:29:33 +00001050
Yi Li6a01f232009-01-07 23:14:39 +08001051#ifdef CONFIG_IPIPE
Philippe Geruma40494a2009-06-16 05:25:42 +02001052#ifndef CONFIG_TICKSOURCE_CORETMR
1053 case IRQ_TIMER0:
Michael Hennerich464abc52008-02-25 13:50:20 +08001054 set_irq_handler(irq, handle_simple_irq);
1055 break;
Graf Yang179413142009-08-18 04:29:33 +00001056#endif
Philippe Geruma40494a2009-06-16 05:25:42 +02001057 case IRQ_CORETMR:
1058 set_irq_handler(irq, handle_simple_irq);
1059 break;
1060 default:
1061 set_irq_handler(irq, handle_level_irq);
1062 break;
1063#else /* !CONFIG_IPIPE */
Philippe Geruma40494a2009-06-16 05:25:42 +02001064 default:
1065 set_irq_handler(irq, handle_simple_irq);
1066 break;
Graf Yang179413142009-08-18 04:29:33 +00001067#endif /* !CONFIG_IPIPE */
Bryan Wu1394f032007-05-06 14:50:22 -07001068 }
Bryan Wu1394f032007-05-06 14:50:22 -07001069 }
Michael Hennerich464abc52008-02-25 13:50:20 +08001070
Bryan Wu1394f032007-05-06 14:50:22 -07001071#ifdef BF537_GENERIC_ERROR_INT_DEMUX
Michael Hennerich464abc52008-02-25 13:50:20 +08001072 for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
1073 set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
1074 handle_level_irq);
Bryan Wu1394f032007-05-06 14:50:22 -07001075#endif
1076
Michael Hennerich464abc52008-02-25 13:50:20 +08001077 /* if configured as edge, then will be changed to do_edge_IRQ */
1078 for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
1079 set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
1080 handle_level_irq);
Michael Hennerich2c4f8292008-02-09 04:11:14 +08001081
Mike Frysingera055b2b2007-11-15 21:12:32 +08001082
Bryan Wu1394f032007-05-06 14:50:22 -07001083 bfin_write_IMASK(0);
1084 CSYNC();
1085 ilat = bfin_read_ILAT();
1086 CSYNC();
1087 bfin_write_ILAT(ilat);
1088 CSYNC();
1089
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001090 printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
Mike Frysinger40059782008-11-18 17:48:22 +08001091 /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx,
Bryan Wu1394f032007-05-06 14:50:22 -07001092 * local_irq_enable()
1093 */
1094 program_IAR();
1095 /* Therefore it's better to setup IARs before interrupts enabled */
1096 search_IAR();
1097
1098 /* Enable interrupts IVG7-15 */
Mike Frysinger40059782008-11-18 17:48:22 +08001099 bfin_irq_flags |= IMASK_IVG15 |
Bryan Wu1394f032007-05-06 14:50:22 -07001100 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001101 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
Bryan Wu1394f032007-05-06 14:50:22 -07001102
Michael Hennerich349ebbc2009-04-15 08:48:08 +00001103 /* This implicitly covers ANOMALY_05000171
1104 * Boot-ROM code modifies SICA_IWRx wakeup registers
1105 */
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001106#ifdef SIC_IWR0
Michael Hennerich56f5f592008-08-06 17:55:32 +08001107 bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001108# ifdef SIC_IWR1
Bryan Wu2f6f4bc2008-11-18 17:48:21 +08001109 /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which
Michael Hennerich55546ac2008-08-13 17:41:13 +08001110 * will screw up the bootrom as it relies on MDMA0/1 waking it
1111 * up from IDLE instructions. See this report for more info:
1112 * http://blackfin.uclinux.org/gf/tracker/4323
1113 */
Mike Frysingerb7e11292008-11-18 17:48:22 +08001114 if (ANOMALY_05000435)
1115 bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
1116 else
1117 bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
Mike Frysingerbe1d8542009-02-04 16:49:45 +08001118# endif
1119# ifdef SIC_IWR2
Michael Hennerich56f5f592008-08-06 17:55:32 +08001120 bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001121# endif
1122#else
Michael Hennerich56f5f592008-08-06 17:55:32 +08001123 bfin_write_SIC_IWR(IWR_DISABLE_ALL);
Michael Hennerichfe9ec9b2008-02-25 12:04:57 +08001124#endif
1125
Bryan Wu1394f032007-05-06 14:50:22 -07001126 return 0;
1127}
1128
1129#ifdef CONFIG_DO_IRQ_L1
Mike Frysingera055b2b2007-11-15 21:12:32 +08001130__attribute__((l1_text))
Bryan Wu1394f032007-05-06 14:50:22 -07001131#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001132void do_irq(int vec, struct pt_regs *fp)
1133{
1134 if (vec == EVT_IVTMR_P) {
1135 vec = IRQ_CORETMR;
1136 } else {
1137 struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
1138 struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
Mike Frysinger780172b2009-06-01 19:43:02 -04001139#if defined(SIC_ISR0) || defined(SICA_ISR0)
Roy Huang24a07a12007-07-12 22:41:45 +08001140 unsigned long sic_status[3];
Bryan Wu1394f032007-05-06 14:50:22 -07001141
Graf Yang6b3087c2009-01-07 23:14:39 +08001142 if (smp_processor_id()) {
Mike Frysinger780172b2009-06-01 19:43:02 -04001143# ifdef SICB_ISR0
Graf Yang6b3087c2009-01-07 23:14:39 +08001144 /* This will be optimized out in UP mode. */
1145 sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
1146 sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001147# endif
Graf Yang6b3087c2009-01-07 23:14:39 +08001148 } else {
1149 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1150 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
1151 }
Mike Frysinger780172b2009-06-01 19:43:02 -04001152# ifdef SIC_ISR2
Michael Hennerich4fb45242007-10-21 16:53:53 +08001153 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001154# endif
Mike Frysinger1f83b8f2007-07-12 22:58:21 +08001155 for (;; ivg++) {
Roy Huang24a07a12007-07-12 22:41:45 +08001156 if (ivg >= ivg_stop) {
1157 atomic_inc(&num_spurious);
1158 return;
1159 }
Michael Hennerich34e0fc82007-07-12 16:17:18 +08001160 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
Roy Huang24a07a12007-07-12 22:41:45 +08001161 break;
1162 }
1163#else
1164 unsigned long sic_status;
Michael Hennerich464abc52008-02-25 13:50:20 +08001165
Bryan Wu1394f032007-05-06 14:50:22 -07001166 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1167
1168 for (;; ivg++) {
1169 if (ivg >= ivg_stop) {
1170 atomic_inc(&num_spurious);
1171 return;
1172 } else if (sic_status & ivg->isrflag)
1173 break;
1174 }
Roy Huang24a07a12007-07-12 22:41:45 +08001175#endif
Bryan Wu1394f032007-05-06 14:50:22 -07001176 vec = ivg->irqno;
1177 }
1178 asm_do_IRQ(vec, fp);
Bryan Wu1394f032007-05-06 14:50:22 -07001179}
Yi Li6a01f232009-01-07 23:14:39 +08001180
1181#ifdef CONFIG_IPIPE
1182
1183int __ipipe_get_irq_priority(unsigned irq)
1184{
1185 int ient, prio;
1186
1187 if (irq <= IRQ_CORETMR)
1188 return irq;
1189
1190 for (ient = 0; ient < NR_PERI_INTS; ient++) {
1191 struct ivgx *ivg = ivg_table + ient;
1192 if (ivg->irqno == irq) {
1193 for (prio = 0; prio <= IVG13-IVG7; prio++) {
1194 if (ivg7_13[prio].ifirst <= ivg &&
1195 ivg7_13[prio].istop > ivg)
1196 return IVG7 + prio;
1197 }
1198 }
1199 }
1200
1201 return IVG15;
1202}
1203
Yi Li6a01f232009-01-07 23:14:39 +08001204/* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */
1205#ifdef CONFIG_DO_IRQ_L1
1206__attribute__((l1_text))
1207#endif
1208asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
1209{
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001210 struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr();
Philippe Geruma40494a2009-06-16 05:25:42 +02001211 struct ipipe_domain *this_domain = __ipipe_current_domain;
Yi Li6a01f232009-01-07 23:14:39 +08001212 struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
1213 struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001214 int irq, s;
Yi Li6a01f232009-01-07 23:14:39 +08001215
Philippe Geruma40494a2009-06-16 05:25:42 +02001216 if (likely(vec == EVT_IVTMR_P))
Yi Li6a01f232009-01-07 23:14:39 +08001217 irq = IRQ_CORETMR;
Philippe Geruma40494a2009-06-16 05:25:42 +02001218 else {
Mike Frysinger780172b2009-06-01 19:43:02 -04001219#if defined(SIC_ISR0) || defined(SICA_ISR0)
Yi Li6a01f232009-01-07 23:14:39 +08001220 unsigned long sic_status[3];
1221
1222 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1223 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
Mike Frysinger780172b2009-06-01 19:43:02 -04001224# ifdef SIC_ISR2
Yi Li6a01f232009-01-07 23:14:39 +08001225 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
Mike Frysinger780172b2009-06-01 19:43:02 -04001226# endif
Yi Li6a01f232009-01-07 23:14:39 +08001227 for (;; ivg++) {
1228 if (ivg >= ivg_stop) {
1229 atomic_inc(&num_spurious);
1230 return 0;
1231 }
1232 if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
1233 break;
1234 }
Yi Li6a01f232009-01-07 23:14:39 +08001235#else
Yi Li6a01f232009-01-07 23:14:39 +08001236 unsigned long sic_status;
1237
1238 sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
1239
1240 for (;; ivg++) {
1241 if (ivg >= ivg_stop) {
1242 atomic_inc(&num_spurious);
1243 return 0;
1244 } else if (sic_status & ivg->isrflag)
1245 break;
1246 }
Yi Li6a01f232009-01-07 23:14:39 +08001247#endif
Graf Yang1fa9be72009-05-15 11:01:59 +00001248 irq = ivg->irqno;
1249 }
Yi Li6a01f232009-01-07 23:14:39 +08001250
1251 if (irq == IRQ_SYSTMR) {
Philippe Geruma40494a2009-06-16 05:25:42 +02001252#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
Yi Li6a01f232009-01-07 23:14:39 +08001253 bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001254#endif
Yi Li6a01f232009-01-07 23:14:39 +08001255 /* This is basically what we need from the register frame. */
1256 __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend;
1257 __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001258 if (this_domain != ipipe_root_domain)
Yi Li6a01f232009-01-07 23:14:39 +08001259 __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10;
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001260 else
1261 __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
Yi Li6a01f232009-01-07 23:14:39 +08001262 }
1263
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001264 if (this_domain == ipipe_root_domain) {
1265 s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1266 barrier();
1267 }
Yi Li6a01f232009-01-07 23:14:39 +08001268
1269 ipipe_trace_irq_entry(irq);
1270 __ipipe_handle_irq(irq, regs);
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001271 ipipe_trace_irq_exit(irq);
Yi Li6a01f232009-01-07 23:14:39 +08001272
Philippe Gerum9bd50df2009-03-04 16:52:38 +08001273 if (this_domain == ipipe_root_domain) {
1274 set_thread_flag(TIF_IRQ_SYNC);
1275 if (!s) {
1276 __clear_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
1277 return !test_bit(IPIPE_STALL_FLAG, &p->status);
1278 }
1279 }
Yi Li6a01f232009-01-07 23:14:39 +08001280
Graf Yang1fa9be72009-05-15 11:01:59 +00001281 return 0;
Yi Li6a01f232009-01-07 23:14:39 +08001282}
1283
1284#endif /* CONFIG_IPIPE */