]>
Commit | Line | Data |
---|---|---|
a3a0f8c8 DV |
1 | /* |
2 | * Carsten Langgaard, carstenl@mips.com | |
3 | * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. | |
4 | * Copyright (C) 2001 Ralf Baechle | |
70342287 | 5 | * Portions copyright (C) 2009 Cisco Systems, Inc. |
a3a0f8c8 DV |
6 | * |
7 | * This program is free software; you can distribute it and/or modify it | |
8 | * under the terms of the GNU General Public License (Version 2) as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along | |
17 | * with this program; if not, write to the Free Software Foundation, Inc., | |
18 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
19 | * | |
20 | * Routines for generic manipulation of the interrupts found on the PowerTV | |
21 | * platform. | |
22 | * | |
23 | * The interrupt controller is located in the South Bridge a PIIX4 device | |
24 | * with two internal 82C95 interrupt controllers. | |
25 | */ | |
26 | #include <linux/init.h> | |
27 | #include <linux/irq.h> | |
28 | #include <linux/sched.h> | |
a3a0f8c8 DV |
29 | #include <linux/interrupt.h> |
30 | #include <linux/kernel_stat.h> | |
31 | #include <linux/kernel.h> | |
32 | #include <linux/random.h> | |
33 | ||
34 | #include <asm/irq_cpu.h> | |
35 | #include <linux/io.h> | |
36 | #include <asm/irq_regs.h> | |
b81947c6 | 37 | #include <asm/setup.h> |
a3a0f8c8 DV |
38 | #include <asm/mips-boards/generic.h> |
39 | ||
40 | #include <asm/mach-powertv/asic_regs.h> | |
41 | ||
c45ef44f | 42 | static DEFINE_RAW_SPINLOCK(asic_irq_lock); |
a3a0f8c8 DV |
43 | |
44 | static inline int get_int(void) | |
45 | { | |
46 | unsigned long flags; | |
47 | int irq; | |
48 | ||
c45ef44f | 49 | raw_spin_lock_irqsave(&asic_irq_lock, flags); |
a3a0f8c8 DV |
50 | |
51 | irq = (asic_read(int_int_scan) >> 4) - 1; | |
52 | ||
53 | if (irq == 0 || irq >= NR_IRQS) | |
54 | irq = -1; | |
55 | ||
c45ef44f | 56 | raw_spin_unlock_irqrestore(&asic_irq_lock, flags); |
a3a0f8c8 DV |
57 | |
58 | return irq; | |
59 | } | |
60 | ||
61 | static void asic_irqdispatch(void) | |
62 | { | |
63 | int irq; | |
64 | ||
65 | irq = get_int(); | |
66 | if (irq < 0) | |
70342287 | 67 | return; /* interrupt has already been cleared */ |
a3a0f8c8 DV |
68 | |
69 | do_IRQ(irq); | |
70 | } | |
71 | ||
72 | static inline int clz(unsigned long x) | |
73 | { | |
74 | __asm__( | |
75 | " .set push \n" | |
76 | " .set mips32 \n" | |
77 | " clz %0, %1 \n" | |
78 | " .set pop \n" | |
79 | : "=r" (x) | |
80 | : "r" (x)); | |
81 | ||
82 | return x; | |
83 | } | |
84 | ||
85 | /* | |
86 | * Version of ffs that only looks at bits 12..15. | |
87 | */ | |
88 | static inline unsigned int irq_ffs(unsigned int pending) | |
89 | { | |
90 | return fls(pending) - 1 + CAUSEB_IP; | |
91 | } | |
92 | ||
93 | /* | |
94 | * TODO: check how it works under EIC mode. | |
95 | */ | |
96 | asmlinkage void plat_irq_dispatch(void) | |
97 | { | |
98 | unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; | |
99 | int irq; | |
100 | ||
101 | irq = irq_ffs(pending); | |
102 | ||
103 | if (irq == CAUSEF_IP3) | |
104 | asic_irqdispatch(); | |
105 | else if (irq >= 0) | |
106 | do_IRQ(irq); | |
107 | else | |
108 | spurious_interrupt(); | |
109 | } | |
110 | ||
111 | void __init arch_init_irq(void) | |
112 | { | |
113 | int i; | |
114 | ||
115 | asic_irq_init(); | |
116 | ||
117 | /* | |
118 | * Initialize interrupt exception vectors. | |
119 | */ | |
120 | if (cpu_has_veic || cpu_has_vint) { | |
121 | int nvec = cpu_has_veic ? 64 : 8; | |
122 | for (i = 0; i < nvec; i++) | |
123 | set_vi_handler(i, asic_irqdispatch); | |
124 | } | |
125 | } |