Commit | Line | Data |
---|---|---|
355c471f | 1 | /* |
355c471f | 2 | * Copyright (C) NEC Electronics Corporation 2004-2006 |
3 | * | |
4 | * This file is based on the arch/mips/ddb5xxx/ddb5477/irq.c | |
5 | * | |
6 | * Copyright 2001 MontaVista Software Inc. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | */ | |
355c471f | 22 | #include <linux/init.h> |
23 | #include <linux/interrupt.h> | |
24 | #include <linux/irq.h> | |
25 | #include <linux/types.h> | |
26 | #include <linux/ptrace.h> | |
27 | #include <linux/delay.h> | |
28 | ||
355c471f | 29 | #include <asm/irq_cpu.h> |
355c471f | 30 | #include <asm/mipsregs.h> |
355c471f | 31 | #include <asm/addrspace.h> |
32 | #include <asm/bootinfo.h> | |
33 | ||
d91f2cbe | 34 | #include <asm/emma/emma2rh.h> |
355c471f | 35 | |
90a568f7 | 36 | static void emma2rh_irq_enable(struct irq_data *d) |
9ae9fd79 | 37 | { |
90a568f7 TG |
38 | unsigned int irq = d->irq - EMMA2RH_IRQ_BASE; |
39 | u32 reg_value, reg_bitmask, reg_index; | |
49618d65 | 40 | |
9ae9fd79 | 41 | reg_index = EMMA2RH_BHIF_INT_EN_0 + |
49618d65 | 42 | (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32); |
9ae9fd79 | 43 | reg_value = emma2rh_in32(reg_index); |
49618d65 | 44 | reg_bitmask = 0x1 << (irq % 32); |
9ae9fd79 SK |
45 | emma2rh_out32(reg_index, reg_value | reg_bitmask); |
46 | } | |
47 | ||
90a568f7 | 48 | static void emma2rh_irq_disable(struct irq_data *d) |
9ae9fd79 | 49 | { |
90a568f7 TG |
50 | unsigned int irq = d->irq - EMMA2RH_IRQ_BASE; |
51 | u32 reg_value, reg_bitmask, reg_index; | |
49618d65 | 52 | |
9ae9fd79 | 53 | reg_index = EMMA2RH_BHIF_INT_EN_0 + |
49618d65 | 54 | (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32); |
9ae9fd79 | 55 | reg_value = emma2rh_in32(reg_index); |
49618d65 | 56 | reg_bitmask = 0x1 << (irq % 32); |
9ae9fd79 SK |
57 | emma2rh_out32(reg_index, reg_value & ~reg_bitmask); |
58 | } | |
59 | ||
9ae9fd79 SK |
60 | struct irq_chip emma2rh_irq_controller = { |
61 | .name = "emma2rh_irq", | |
90a568f7 TG |
62 | .irq_mask = emma2rh_irq_disable, |
63 | .irq_unmask = emma2rh_irq_enable, | |
9ae9fd79 SK |
64 | }; |
65 | ||
66 | void emma2rh_irq_init(void) | |
67 | { | |
68 | u32 i; | |
69 | ||
70 | for (i = 0; i < NUM_EMMA2RH_IRQ; i++) | |
e4ec7989 | 71 | irq_set_chip_and_handler_name(EMMA2RH_IRQ_BASE + i, |
ae3c1d37 SK |
72 | &emma2rh_irq_controller, |
73 | handle_level_irq, "level"); | |
9ae9fd79 SK |
74 | } |
75 | ||
90a568f7 | 76 | static void emma2rh_sw_irq_enable(struct irq_data *d) |
9ae9fd79 | 77 | { |
90a568f7 | 78 | unsigned int irq = d->irq - EMMA2RH_SW_IRQ_BASE; |
9ae9fd79 SK |
79 | u32 reg; |
80 | ||
9ae9fd79 SK |
81 | reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); |
82 | reg |= 1 << irq; | |
83 | emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); | |
84 | } | |
85 | ||
90a568f7 | 86 | static void emma2rh_sw_irq_disable(struct irq_data *d) |
9ae9fd79 | 87 | { |
90a568f7 | 88 | unsigned int irq = d->irq - EMMA2RH_SW_IRQ_BASE; |
9ae9fd79 SK |
89 | u32 reg; |
90 | ||
9ae9fd79 SK |
91 | reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); |
92 | reg &= ~(1 << irq); | |
93 | emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); | |
94 | } | |
95 | ||
9ae9fd79 SK |
96 | struct irq_chip emma2rh_sw_irq_controller = { |
97 | .name = "emma2rh_sw_irq", | |
90a568f7 TG |
98 | .irq_mask = emma2rh_sw_irq_disable, |
99 | .irq_unmask = emma2rh_sw_irq_enable, | |
9ae9fd79 SK |
100 | }; |
101 | ||
102 | void emma2rh_sw_irq_init(void) | |
103 | { | |
104 | u32 i; | |
105 | ||
106 | for (i = 0; i < NUM_EMMA2RH_IRQ_SW; i++) | |
e4ec7989 | 107 | irq_set_chip_and_handler_name(EMMA2RH_SW_IRQ_BASE + i, |
ae3c1d37 SK |
108 | &emma2rh_sw_irq_controller, |
109 | handle_level_irq, "level"); | |
9ae9fd79 SK |
110 | } |
111 | ||
90a568f7 | 112 | static void emma2rh_gpio_irq_enable(struct irq_data *d) |
9ae9fd79 | 113 | { |
90a568f7 | 114 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; |
9ae9fd79 SK |
115 | u32 reg; |
116 | ||
9ae9fd79 SK |
117 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); |
118 | reg |= 1 << irq; | |
119 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); | |
120 | } | |
121 | ||
90a568f7 | 122 | static void emma2rh_gpio_irq_disable(struct irq_data *d) |
9ae9fd79 | 123 | { |
90a568f7 | 124 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; |
9ae9fd79 SK |
125 | u32 reg; |
126 | ||
9ae9fd79 SK |
127 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); |
128 | reg &= ~(1 << irq); | |
129 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); | |
130 | } | |
131 | ||
90a568f7 | 132 | static void emma2rh_gpio_irq_ack(struct irq_data *d) |
9ae9fd79 | 133 | { |
90a568f7 TG |
134 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; |
135 | ||
9ae9fd79 | 136 | emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq)); |
9ae9fd79 SK |
137 | } |
138 | ||
90a568f7 | 139 | static void emma2rh_gpio_irq_mask_ack(struct irq_data *d) |
9ae9fd79 | 140 | { |
90a568f7 | 141 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; |
49618d65 SK |
142 | u32 reg; |
143 | ||
8da55bb2 | 144 | emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq)); |
49618d65 | 145 | |
8da55bb2 SK |
146 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); |
147 | reg &= ~(1 << irq); | |
148 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); | |
9ae9fd79 SK |
149 | } |
150 | ||
151 | struct irq_chip emma2rh_gpio_irq_controller = { | |
152 | .name = "emma2rh_gpio_irq", | |
90a568f7 TG |
153 | .irq_ack = emma2rh_gpio_irq_ack, |
154 | .irq_mask = emma2rh_gpio_irq_disable, | |
155 | .irq_mask_ack = emma2rh_gpio_irq_mask_ack, | |
156 | .irq_unmask = emma2rh_gpio_irq_enable, | |
9ae9fd79 SK |
157 | }; |
158 | ||
159 | void emma2rh_gpio_irq_init(void) | |
160 | { | |
161 | u32 i; | |
162 | ||
163 | for (i = 0; i < NUM_EMMA2RH_IRQ_GPIO; i++) | |
e4ec7989 | 164 | irq_set_chip_and_handler_name(EMMA2RH_GPIO_IRQ_BASE + i, |
8da55bb2 SK |
165 | &emma2rh_gpio_irq_controller, |
166 | handle_edge_irq, "edge"); | |
9ae9fd79 | 167 | } |
355c471f | 168 | |
169 | static struct irqaction irq_cascade = { | |
170 | .handler = no_action, | |
5a4a4ad8 | 171 | .flags = IRQF_NO_THREAD, |
355c471f | 172 | .name = "cascade", |
173 | .dev_id = NULL, | |
174 | .next = NULL, | |
175 | }; | |
176 | ||
9ae9fd79 SK |
177 | /* |
178 | * the first level int-handler will jump here if it is a emma2rh irq | |
179 | */ | |
180 | void emma2rh_irq_dispatch(void) | |
181 | { | |
182 | u32 intStatus; | |
183 | u32 bitmask; | |
184 | u32 i; | |
185 | ||
186 | intStatus = emma2rh_in32(EMMA2RH_BHIF_INT_ST_0) & | |
187 | emma2rh_in32(EMMA2RH_BHIF_INT_EN_0); | |
188 | ||
189 | #ifdef EMMA2RH_SW_CASCADE | |
fb2826b7 | 190 | if (intStatus & (1UL << EMMA2RH_SW_CASCADE)) { |
9ae9fd79 SK |
191 | u32 swIntStatus; |
192 | swIntStatus = emma2rh_in32(EMMA2RH_BHIF_SW_INT) | |
193 | & emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); | |
194 | for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { | |
195 | if (swIntStatus & bitmask) { | |
196 | do_IRQ(EMMA2RH_SW_IRQ_BASE + i); | |
197 | return; | |
198 | } | |
199 | } | |
200 | } | |
fb2826b7 SK |
201 | /* Skip S/W interrupt */ |
202 | intStatus &= ~(1UL << EMMA2RH_SW_CASCADE); | |
9ae9fd79 SK |
203 | #endif |
204 | ||
205 | for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { | |
206 | if (intStatus & bitmask) { | |
207 | do_IRQ(EMMA2RH_IRQ_BASE + i); | |
208 | return; | |
209 | } | |
210 | } | |
211 | ||
212 | intStatus = emma2rh_in32(EMMA2RH_BHIF_INT_ST_1) & | |
213 | emma2rh_in32(EMMA2RH_BHIF_INT_EN_1); | |
214 | ||
215 | #ifdef EMMA2RH_GPIO_CASCADE | |
fb2826b7 | 216 | if (intStatus & (1UL << (EMMA2RH_GPIO_CASCADE % 32))) { |
9ae9fd79 SK |
217 | u32 gpioIntStatus; |
218 | gpioIntStatus = emma2rh_in32(EMMA2RH_GPIO_INT_ST) | |
219 | & emma2rh_in32(EMMA2RH_GPIO_INT_MASK); | |
220 | for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { | |
221 | if (gpioIntStatus & bitmask) { | |
222 | do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i); | |
223 | return; | |
224 | } | |
225 | } | |
226 | } | |
fb2826b7 SK |
227 | /* Skip GPIO interrupt */ |
228 | intStatus &= ~(1UL << (EMMA2RH_GPIO_CASCADE % 32)); | |
9ae9fd79 SK |
229 | #endif |
230 | ||
231 | for (i = 32, bitmask = 1; i < 64; i++, bitmask <<= 1) { | |
232 | if (intStatus & bitmask) { | |
233 | do_IRQ(EMMA2RH_IRQ_BASE + i); | |
234 | return; | |
235 | } | |
236 | } | |
237 | ||
238 | intStatus = emma2rh_in32(EMMA2RH_BHIF_INT_ST_2) & | |
239 | emma2rh_in32(EMMA2RH_BHIF_INT_EN_2); | |
240 | ||
241 | for (i = 64, bitmask = 1; i < 96; i++, bitmask <<= 1) { | |
242 | if (intStatus & bitmask) { | |
243 | do_IRQ(EMMA2RH_IRQ_BASE + i); | |
244 | return; | |
245 | } | |
246 | } | |
247 | } | |
248 | ||
355c471f | 249 | void __init arch_init_irq(void) |
250 | { | |
251 | u32 reg; | |
252 | ||
355c471f | 253 | /* by default, interrupts are disabled. */ |
254 | emma2rh_out32(EMMA2RH_BHIF_INT_EN_0, 0); | |
255 | emma2rh_out32(EMMA2RH_BHIF_INT_EN_1, 0); | |
256 | emma2rh_out32(EMMA2RH_BHIF_INT_EN_2, 0); | |
257 | emma2rh_out32(EMMA2RH_BHIF_INT1_EN_0, 0); | |
258 | emma2rh_out32(EMMA2RH_BHIF_INT1_EN_1, 0); | |
259 | emma2rh_out32(EMMA2RH_BHIF_INT1_EN_2, 0); | |
260 | emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, 0); | |
261 | ||
262 | clear_c0_status(0xff00); | |
263 | set_c0_status(0x0400); | |
264 | ||
265 | #define GPIO_PCI (0xf<<15) | |
266 | /* setup GPIO interrupt for PCI interface */ | |
267 | /* direction input */ | |
268 | reg = emma2rh_in32(EMMA2RH_GPIO_DIR); | |
269 | emma2rh_out32(EMMA2RH_GPIO_DIR, reg & ~GPIO_PCI); | |
270 | /* disable interrupt */ | |
271 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); | |
272 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg & ~GPIO_PCI); | |
273 | /* level triggerd */ | |
274 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MODE); | |
275 | emma2rh_out32(EMMA2RH_GPIO_INT_MODE, reg | GPIO_PCI); | |
276 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_CND_A); | |
277 | emma2rh_out32(EMMA2RH_GPIO_INT_CND_A, reg & (~GPIO_PCI)); | |
278 | /* interrupt clear */ | |
279 | emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~GPIO_PCI); | |
280 | ||
281 | /* init all controllers */ | |
9b6c04bc | 282 | emma2rh_irq_init(); |
68ed1ca9 | 283 | emma2rh_sw_irq_init(); |
fcb3cfe7 | 284 | emma2rh_gpio_irq_init(); |
97dcb82d | 285 | mips_cpu_irq_init(); |
355c471f | 286 | |
287 | /* setup cascade interrupts */ | |
288 | setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade); | |
289 | setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_GPIO_CASCADE, &irq_cascade); | |
9e6f3969 | 290 | setup_irq(MIPS_CPU_IRQ_BASE + 2, &irq_cascade); |
355c471f | 291 | } |
292 | ||
937a8015 | 293 | asmlinkage void plat_irq_dispatch(void) |
355c471f | 294 | { |
70342287 | 295 | unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; |
355c471f | 296 | |
297 | if (pending & STATUSF_IP7) | |
eebacda4 | 298 | do_IRQ(MIPS_CPU_IRQ_BASE + 7); |
355c471f | 299 | else if (pending & STATUSF_IP2) |
937a8015 | 300 | emma2rh_irq_dispatch(); |
355c471f | 301 | else if (pending & STATUSF_IP1) |
eebacda4 | 302 | do_IRQ(MIPS_CPU_IRQ_BASE + 1); |
355c471f | 303 | else if (pending & STATUSF_IP0) |
eebacda4 | 304 | do_IRQ(MIPS_CPU_IRQ_BASE + 0); |
355c471f | 305 | else |
937a8015 | 306 | spurious_interrupt(); |
355c471f | 307 | } |