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