diff options
Diffstat (limited to 'arch/mips/vr41xx/common/icu.c')
-rw-r--r-- | arch/mips/vr41xx/common/icu.c | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c new file mode 100644 index 000000000..9240bcdbe --- /dev/null +++ b/arch/mips/vr41xx/common/icu.c | |||
@@ -0,0 +1,714 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * icu.c, Interrupt Control Unit routines for the NEC VR4100 series. | ||
4 | * | ||
5 | * Copyright (C) 2001-2002 MontaVista Software Inc. | ||
6 | * Author: Yoichi Yuasa <source@mvista.com> | ||
7 | * Copyright (C) 2003-2006 Yoichi Yuasa <yuasa@linux-mips.org> | ||
8 | */ | ||
9 | /* | ||
10 | * Changes: | ||
11 | * MontaVista Software Inc. <source@mvista.com> | ||
12 | * - New creation, NEC VR4122 and VR4131 are supported. | ||
13 | * - Added support for NEC VR4111 and VR4121. | ||
14 | * | ||
15 | * Yoichi Yuasa <yuasa@linux-mips.org> | ||
16 | * - Coped with INTASSIGN of NEC VR4133. | ||
17 | */ | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/export.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/smp.h> | ||
24 | #include <linux/types.h> | ||
25 | |||
26 | #include <asm/cpu.h> | ||
27 | #include <asm/io.h> | ||
28 | #include <asm/vr41xx/irq.h> | ||
29 | #include <asm/vr41xx/vr41xx.h> | ||
30 | |||
31 | static void __iomem *icu1_base; | ||
32 | static void __iomem *icu2_base; | ||
33 | |||
34 | static unsigned char sysint1_assign[16] = { | ||
35 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
36 | static unsigned char sysint2_assign[16] = { | ||
37 | 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
38 | |||
39 | #define ICU1_TYPE1_BASE 0x0b000080UL | ||
40 | #define ICU2_TYPE1_BASE 0x0b000200UL | ||
41 | |||
42 | #define ICU1_TYPE2_BASE 0x0f000080UL | ||
43 | #define ICU2_TYPE2_BASE 0x0f0000a0UL | ||
44 | |||
45 | #define ICU1_SIZE 0x20 | ||
46 | #define ICU2_SIZE 0x1c | ||
47 | |||
48 | #define SYSINT1REG 0x00 | ||
49 | #define PIUINTREG 0x02 | ||
50 | #define INTASSIGN0 0x04 | ||
51 | #define INTASSIGN1 0x06 | ||
52 | #define GIUINTLREG 0x08 | ||
53 | #define DSIUINTREG 0x0a | ||
54 | #define MSYSINT1REG 0x0c | ||
55 | #define MPIUINTREG 0x0e | ||
56 | #define MAIUINTREG 0x10 | ||
57 | #define MKIUINTREG 0x12 | ||
58 | #define MMACINTREG 0x12 | ||
59 | #define MGIUINTLREG 0x14 | ||
60 | #define MDSIUINTREG 0x16 | ||
61 | #define NMIREG 0x18 | ||
62 | #define SOFTREG 0x1a | ||
63 | #define INTASSIGN2 0x1c | ||
64 | #define INTASSIGN3 0x1e | ||
65 | |||
66 | #define SYSINT2REG 0x00 | ||
67 | #define GIUINTHREG 0x02 | ||
68 | #define FIRINTREG 0x04 | ||
69 | #define MSYSINT2REG 0x06 | ||
70 | #define MGIUINTHREG 0x08 | ||
71 | #define MFIRINTREG 0x0a | ||
72 | #define PCIINTREG 0x0c | ||
73 | #define PCIINT0 0x0001 | ||
74 | #define SCUINTREG 0x0e | ||
75 | #define SCUINT0 0x0001 | ||
76 | #define CSIINTREG 0x10 | ||
77 | #define MPCIINTREG 0x12 | ||
78 | #define MSCUINTREG 0x14 | ||
79 | #define MCSIINTREG 0x16 | ||
80 | #define BCUINTREG 0x18 | ||
81 | #define BCUINTR 0x0001 | ||
82 | #define MBCUINTREG 0x1a | ||
83 | |||
84 | #define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */ | ||
85 | #define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */ | ||
86 | |||
87 | #define INT_TO_IRQ(x) ((x) + 2) /* Int0-4 -> IRQ2-6 */ | ||
88 | |||
89 | #define icu1_read(offset) readw(icu1_base + (offset)) | ||
90 | #define icu1_write(offset, value) writew((value), icu1_base + (offset)) | ||
91 | |||
92 | #define icu2_read(offset) readw(icu2_base + (offset)) | ||
93 | #define icu2_write(offset, value) writew((value), icu2_base + (offset)) | ||
94 | |||
95 | #define INTASSIGN_MAX 4 | ||
96 | #define INTASSIGN_MASK 0x0007 | ||
97 | |||
98 | static inline uint16_t icu1_set(uint8_t offset, uint16_t set) | ||
99 | { | ||
100 | uint16_t data; | ||
101 | |||
102 | data = icu1_read(offset); | ||
103 | data |= set; | ||
104 | icu1_write(offset, data); | ||
105 | |||
106 | return data; | ||
107 | } | ||
108 | |||
109 | static inline uint16_t icu1_clear(uint8_t offset, uint16_t clear) | ||
110 | { | ||
111 | uint16_t data; | ||
112 | |||
113 | data = icu1_read(offset); | ||
114 | data &= ~clear; | ||
115 | icu1_write(offset, data); | ||
116 | |||
117 | return data; | ||
118 | } | ||
119 | |||
120 | static inline uint16_t icu2_set(uint8_t offset, uint16_t set) | ||
121 | { | ||
122 | uint16_t data; | ||
123 | |||
124 | data = icu2_read(offset); | ||
125 | data |= set; | ||
126 | icu2_write(offset, data); | ||
127 | |||
128 | return data; | ||
129 | } | ||
130 | |||
131 | static inline uint16_t icu2_clear(uint8_t offset, uint16_t clear) | ||
132 | { | ||
133 | uint16_t data; | ||
134 | |||
135 | data = icu2_read(offset); | ||
136 | data &= ~clear; | ||
137 | icu2_write(offset, data); | ||
138 | |||
139 | return data; | ||
140 | } | ||
141 | |||
142 | void vr41xx_enable_piuint(uint16_t mask) | ||
143 | { | ||
144 | struct irq_desc *desc = irq_to_desc(PIU_IRQ); | ||
145 | unsigned long flags; | ||
146 | |||
147 | if (current_cpu_type() == CPU_VR4111 || | ||
148 | current_cpu_type() == CPU_VR4121) { | ||
149 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
150 | icu1_set(MPIUINTREG, mask); | ||
151 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | EXPORT_SYMBOL(vr41xx_enable_piuint); | ||
156 | |||
157 | void vr41xx_disable_piuint(uint16_t mask) | ||
158 | { | ||
159 | struct irq_desc *desc = irq_to_desc(PIU_IRQ); | ||
160 | unsigned long flags; | ||
161 | |||
162 | if (current_cpu_type() == CPU_VR4111 || | ||
163 | current_cpu_type() == CPU_VR4121) { | ||
164 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
165 | icu1_clear(MPIUINTREG, mask); | ||
166 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | EXPORT_SYMBOL(vr41xx_disable_piuint); | ||
171 | |||
172 | void vr41xx_enable_aiuint(uint16_t mask) | ||
173 | { | ||
174 | struct irq_desc *desc = irq_to_desc(AIU_IRQ); | ||
175 | unsigned long flags; | ||
176 | |||
177 | if (current_cpu_type() == CPU_VR4111 || | ||
178 | current_cpu_type() == CPU_VR4121) { | ||
179 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
180 | icu1_set(MAIUINTREG, mask); | ||
181 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | EXPORT_SYMBOL(vr41xx_enable_aiuint); | ||
186 | |||
187 | void vr41xx_disable_aiuint(uint16_t mask) | ||
188 | { | ||
189 | struct irq_desc *desc = irq_to_desc(AIU_IRQ); | ||
190 | unsigned long flags; | ||
191 | |||
192 | if (current_cpu_type() == CPU_VR4111 || | ||
193 | current_cpu_type() == CPU_VR4121) { | ||
194 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
195 | icu1_clear(MAIUINTREG, mask); | ||
196 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | EXPORT_SYMBOL(vr41xx_disable_aiuint); | ||
201 | |||
202 | void vr41xx_enable_kiuint(uint16_t mask) | ||
203 | { | ||
204 | struct irq_desc *desc = irq_to_desc(KIU_IRQ); | ||
205 | unsigned long flags; | ||
206 | |||
207 | if (current_cpu_type() == CPU_VR4111 || | ||
208 | current_cpu_type() == CPU_VR4121) { | ||
209 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
210 | icu1_set(MKIUINTREG, mask); | ||
211 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | EXPORT_SYMBOL(vr41xx_enable_kiuint); | ||
216 | |||
217 | void vr41xx_disable_kiuint(uint16_t mask) | ||
218 | { | ||
219 | struct irq_desc *desc = irq_to_desc(KIU_IRQ); | ||
220 | unsigned long flags; | ||
221 | |||
222 | if (current_cpu_type() == CPU_VR4111 || | ||
223 | current_cpu_type() == CPU_VR4121) { | ||
224 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
225 | icu1_clear(MKIUINTREG, mask); | ||
226 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | EXPORT_SYMBOL(vr41xx_disable_kiuint); | ||
231 | |||
232 | void vr41xx_enable_macint(uint16_t mask) | ||
233 | { | ||
234 | struct irq_desc *desc = irq_to_desc(ETHERNET_IRQ); | ||
235 | unsigned long flags; | ||
236 | |||
237 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
238 | icu1_set(MMACINTREG, mask); | ||
239 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
240 | } | ||
241 | |||
242 | EXPORT_SYMBOL(vr41xx_enable_macint); | ||
243 | |||
244 | void vr41xx_disable_macint(uint16_t mask) | ||
245 | { | ||
246 | struct irq_desc *desc = irq_to_desc(ETHERNET_IRQ); | ||
247 | unsigned long flags; | ||
248 | |||
249 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
250 | icu1_clear(MMACINTREG, mask); | ||
251 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
252 | } | ||
253 | |||
254 | EXPORT_SYMBOL(vr41xx_disable_macint); | ||
255 | |||
256 | void vr41xx_enable_dsiuint(uint16_t mask) | ||
257 | { | ||
258 | struct irq_desc *desc = irq_to_desc(DSIU_IRQ); | ||
259 | unsigned long flags; | ||
260 | |||
261 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
262 | icu1_set(MDSIUINTREG, mask); | ||
263 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
264 | } | ||
265 | |||
266 | EXPORT_SYMBOL(vr41xx_enable_dsiuint); | ||
267 | |||
268 | void vr41xx_disable_dsiuint(uint16_t mask) | ||
269 | { | ||
270 | struct irq_desc *desc = irq_to_desc(DSIU_IRQ); | ||
271 | unsigned long flags; | ||
272 | |||
273 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
274 | icu1_clear(MDSIUINTREG, mask); | ||
275 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
276 | } | ||
277 | |||
278 | EXPORT_SYMBOL(vr41xx_disable_dsiuint); | ||
279 | |||
280 | void vr41xx_enable_firint(uint16_t mask) | ||
281 | { | ||
282 | struct irq_desc *desc = irq_to_desc(FIR_IRQ); | ||
283 | unsigned long flags; | ||
284 | |||
285 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
286 | icu2_set(MFIRINTREG, mask); | ||
287 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
288 | } | ||
289 | |||
290 | EXPORT_SYMBOL(vr41xx_enable_firint); | ||
291 | |||
292 | void vr41xx_disable_firint(uint16_t mask) | ||
293 | { | ||
294 | struct irq_desc *desc = irq_to_desc(FIR_IRQ); | ||
295 | unsigned long flags; | ||
296 | |||
297 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
298 | icu2_clear(MFIRINTREG, mask); | ||
299 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
300 | } | ||
301 | |||
302 | EXPORT_SYMBOL(vr41xx_disable_firint); | ||
303 | |||
304 | void vr41xx_enable_pciint(void) | ||
305 | { | ||
306 | struct irq_desc *desc = irq_to_desc(PCI_IRQ); | ||
307 | unsigned long flags; | ||
308 | |||
309 | if (current_cpu_type() == CPU_VR4122 || | ||
310 | current_cpu_type() == CPU_VR4131 || | ||
311 | current_cpu_type() == CPU_VR4133) { | ||
312 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
313 | icu2_write(MPCIINTREG, PCIINT0); | ||
314 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | EXPORT_SYMBOL(vr41xx_enable_pciint); | ||
319 | |||
320 | void vr41xx_disable_pciint(void) | ||
321 | { | ||
322 | struct irq_desc *desc = irq_to_desc(PCI_IRQ); | ||
323 | unsigned long flags; | ||
324 | |||
325 | if (current_cpu_type() == CPU_VR4122 || | ||
326 | current_cpu_type() == CPU_VR4131 || | ||
327 | current_cpu_type() == CPU_VR4133) { | ||
328 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
329 | icu2_write(MPCIINTREG, 0); | ||
330 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | EXPORT_SYMBOL(vr41xx_disable_pciint); | ||
335 | |||
336 | void vr41xx_enable_scuint(void) | ||
337 | { | ||
338 | struct irq_desc *desc = irq_to_desc(SCU_IRQ); | ||
339 | unsigned long flags; | ||
340 | |||
341 | if (current_cpu_type() == CPU_VR4122 || | ||
342 | current_cpu_type() == CPU_VR4131 || | ||
343 | current_cpu_type() == CPU_VR4133) { | ||
344 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
345 | icu2_write(MSCUINTREG, SCUINT0); | ||
346 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | EXPORT_SYMBOL(vr41xx_enable_scuint); | ||
351 | |||
352 | void vr41xx_disable_scuint(void) | ||
353 | { | ||
354 | struct irq_desc *desc = irq_to_desc(SCU_IRQ); | ||
355 | unsigned long flags; | ||
356 | |||
357 | if (current_cpu_type() == CPU_VR4122 || | ||
358 | current_cpu_type() == CPU_VR4131 || | ||
359 | current_cpu_type() == CPU_VR4133) { | ||
360 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
361 | icu2_write(MSCUINTREG, 0); | ||
362 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | EXPORT_SYMBOL(vr41xx_disable_scuint); | ||
367 | |||
368 | void vr41xx_enable_csiint(uint16_t mask) | ||
369 | { | ||
370 | struct irq_desc *desc = irq_to_desc(CSI_IRQ); | ||
371 | unsigned long flags; | ||
372 | |||
373 | if (current_cpu_type() == CPU_VR4122 || | ||
374 | current_cpu_type() == CPU_VR4131 || | ||
375 | current_cpu_type() == CPU_VR4133) { | ||
376 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
377 | icu2_set(MCSIINTREG, mask); | ||
378 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | EXPORT_SYMBOL(vr41xx_enable_csiint); | ||
383 | |||
384 | void vr41xx_disable_csiint(uint16_t mask) | ||
385 | { | ||
386 | struct irq_desc *desc = irq_to_desc(CSI_IRQ); | ||
387 | unsigned long flags; | ||
388 | |||
389 | if (current_cpu_type() == CPU_VR4122 || | ||
390 | current_cpu_type() == CPU_VR4131 || | ||
391 | current_cpu_type() == CPU_VR4133) { | ||
392 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
393 | icu2_clear(MCSIINTREG, mask); | ||
394 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | EXPORT_SYMBOL(vr41xx_disable_csiint); | ||
399 | |||
400 | void vr41xx_enable_bcuint(void) | ||
401 | { | ||
402 | struct irq_desc *desc = irq_to_desc(BCU_IRQ); | ||
403 | unsigned long flags; | ||
404 | |||
405 | if (current_cpu_type() == CPU_VR4122 || | ||
406 | current_cpu_type() == CPU_VR4131 || | ||
407 | current_cpu_type() == CPU_VR4133) { | ||
408 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
409 | icu2_write(MBCUINTREG, BCUINTR); | ||
410 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | EXPORT_SYMBOL(vr41xx_enable_bcuint); | ||
415 | |||
416 | void vr41xx_disable_bcuint(void) | ||
417 | { | ||
418 | struct irq_desc *desc = irq_to_desc(BCU_IRQ); | ||
419 | unsigned long flags; | ||
420 | |||
421 | if (current_cpu_type() == CPU_VR4122 || | ||
422 | current_cpu_type() == CPU_VR4131 || | ||
423 | current_cpu_type() == CPU_VR4133) { | ||
424 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
425 | icu2_write(MBCUINTREG, 0); | ||
426 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | EXPORT_SYMBOL(vr41xx_disable_bcuint); | ||
431 | |||
432 | static void disable_sysint1_irq(struct irq_data *d) | ||
433 | { | ||
434 | icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(d->irq)); | ||
435 | } | ||
436 | |||
437 | static void enable_sysint1_irq(struct irq_data *d) | ||
438 | { | ||
439 | icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(d->irq)); | ||
440 | } | ||
441 | |||
442 | static struct irq_chip sysint1_irq_type = { | ||
443 | .name = "SYSINT1", | ||
444 | .irq_mask = disable_sysint1_irq, | ||
445 | .irq_unmask = enable_sysint1_irq, | ||
446 | }; | ||
447 | |||
448 | static void disable_sysint2_irq(struct irq_data *d) | ||
449 | { | ||
450 | icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(d->irq)); | ||
451 | } | ||
452 | |||
453 | static void enable_sysint2_irq(struct irq_data *d) | ||
454 | { | ||
455 | icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(d->irq)); | ||
456 | } | ||
457 | |||
458 | static struct irq_chip sysint2_irq_type = { | ||
459 | .name = "SYSINT2", | ||
460 | .irq_mask = disable_sysint2_irq, | ||
461 | .irq_unmask = enable_sysint2_irq, | ||
462 | }; | ||
463 | |||
464 | static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) | ||
465 | { | ||
466 | struct irq_desc *desc = irq_to_desc(irq); | ||
467 | uint16_t intassign0, intassign1; | ||
468 | unsigned int pin; | ||
469 | |||
470 | pin = SYSINT1_IRQ_TO_PIN(irq); | ||
471 | |||
472 | raw_spin_lock_irq(&desc->lock); | ||
473 | |||
474 | intassign0 = icu1_read(INTASSIGN0); | ||
475 | intassign1 = icu1_read(INTASSIGN1); | ||
476 | |||
477 | switch (pin) { | ||
478 | case 0: | ||
479 | intassign0 &= ~INTASSIGN_MASK; | ||
480 | intassign0 |= (uint16_t)assign; | ||
481 | break; | ||
482 | case 1: | ||
483 | intassign0 &= ~(INTASSIGN_MASK << 3); | ||
484 | intassign0 |= (uint16_t)assign << 3; | ||
485 | break; | ||
486 | case 2: | ||
487 | intassign0 &= ~(INTASSIGN_MASK << 6); | ||
488 | intassign0 |= (uint16_t)assign << 6; | ||
489 | break; | ||
490 | case 3: | ||
491 | intassign0 &= ~(INTASSIGN_MASK << 9); | ||
492 | intassign0 |= (uint16_t)assign << 9; | ||
493 | break; | ||
494 | case 8: | ||
495 | intassign0 &= ~(INTASSIGN_MASK << 12); | ||
496 | intassign0 |= (uint16_t)assign << 12; | ||
497 | break; | ||
498 | case 9: | ||
499 | intassign1 &= ~INTASSIGN_MASK; | ||
500 | intassign1 |= (uint16_t)assign; | ||
501 | break; | ||
502 | case 11: | ||
503 | intassign1 &= ~(INTASSIGN_MASK << 6); | ||
504 | intassign1 |= (uint16_t)assign << 6; | ||
505 | break; | ||
506 | case 12: | ||
507 | intassign1 &= ~(INTASSIGN_MASK << 9); | ||
508 | intassign1 |= (uint16_t)assign << 9; | ||
509 | break; | ||
510 | default: | ||
511 | raw_spin_unlock_irq(&desc->lock); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | sysint1_assign[pin] = assign; | ||
516 | icu1_write(INTASSIGN0, intassign0); | ||
517 | icu1_write(INTASSIGN1, intassign1); | ||
518 | |||
519 | raw_spin_unlock_irq(&desc->lock); | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) | ||
525 | { | ||
526 | struct irq_desc *desc = irq_to_desc(irq); | ||
527 | uint16_t intassign2, intassign3; | ||
528 | unsigned int pin; | ||
529 | |||
530 | pin = SYSINT2_IRQ_TO_PIN(irq); | ||
531 | |||
532 | raw_spin_lock_irq(&desc->lock); | ||
533 | |||
534 | intassign2 = icu1_read(INTASSIGN2); | ||
535 | intassign3 = icu1_read(INTASSIGN3); | ||
536 | |||
537 | switch (pin) { | ||
538 | case 0: | ||
539 | intassign2 &= ~INTASSIGN_MASK; | ||
540 | intassign2 |= (uint16_t)assign; | ||
541 | break; | ||
542 | case 1: | ||
543 | intassign2 &= ~(INTASSIGN_MASK << 3); | ||
544 | intassign2 |= (uint16_t)assign << 3; | ||
545 | break; | ||
546 | case 3: | ||
547 | intassign2 &= ~(INTASSIGN_MASK << 6); | ||
548 | intassign2 |= (uint16_t)assign << 6; | ||
549 | break; | ||
550 | case 4: | ||
551 | intassign2 &= ~(INTASSIGN_MASK << 9); | ||
552 | intassign2 |= (uint16_t)assign << 9; | ||
553 | break; | ||
554 | case 5: | ||
555 | intassign2 &= ~(INTASSIGN_MASK << 12); | ||
556 | intassign2 |= (uint16_t)assign << 12; | ||
557 | break; | ||
558 | case 6: | ||
559 | intassign3 &= ~INTASSIGN_MASK; | ||
560 | intassign3 |= (uint16_t)assign; | ||
561 | break; | ||
562 | case 7: | ||
563 | intassign3 &= ~(INTASSIGN_MASK << 3); | ||
564 | intassign3 |= (uint16_t)assign << 3; | ||
565 | break; | ||
566 | case 8: | ||
567 | intassign3 &= ~(INTASSIGN_MASK << 6); | ||
568 | intassign3 |= (uint16_t)assign << 6; | ||
569 | break; | ||
570 | case 9: | ||
571 | intassign3 &= ~(INTASSIGN_MASK << 9); | ||
572 | intassign3 |= (uint16_t)assign << 9; | ||
573 | break; | ||
574 | case 10: | ||
575 | intassign3 &= ~(INTASSIGN_MASK << 12); | ||
576 | intassign3 |= (uint16_t)assign << 12; | ||
577 | break; | ||
578 | default: | ||
579 | raw_spin_unlock_irq(&desc->lock); | ||
580 | return -EINVAL; | ||
581 | } | ||
582 | |||
583 | sysint2_assign[pin] = assign; | ||
584 | icu1_write(INTASSIGN2, intassign2); | ||
585 | icu1_write(INTASSIGN3, intassign3); | ||
586 | |||
587 | raw_spin_unlock_irq(&desc->lock); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) | ||
593 | { | ||
594 | int retval = -EINVAL; | ||
595 | |||
596 | if (current_cpu_type() != CPU_VR4133) | ||
597 | return -EINVAL; | ||
598 | |||
599 | if (intassign > INTASSIGN_MAX) | ||
600 | return -EINVAL; | ||
601 | |||
602 | if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST) | ||
603 | retval = set_sysint1_assign(irq, intassign); | ||
604 | else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST) | ||
605 | retval = set_sysint2_assign(irq, intassign); | ||
606 | |||
607 | return retval; | ||
608 | } | ||
609 | |||
610 | EXPORT_SYMBOL(vr41xx_set_intassign); | ||
611 | |||
612 | static int icu_get_irq(unsigned int irq) | ||
613 | { | ||
614 | uint16_t pend1, pend2; | ||
615 | uint16_t mask1, mask2; | ||
616 | int i; | ||
617 | |||
618 | pend1 = icu1_read(SYSINT1REG); | ||
619 | mask1 = icu1_read(MSYSINT1REG); | ||
620 | |||
621 | pend2 = icu2_read(SYSINT2REG); | ||
622 | mask2 = icu2_read(MSYSINT2REG); | ||
623 | |||
624 | mask1 &= pend1; | ||
625 | mask2 &= pend2; | ||
626 | |||
627 | if (mask1) { | ||
628 | for (i = 0; i < 16; i++) { | ||
629 | if (irq == INT_TO_IRQ(sysint1_assign[i]) && (mask1 & (1 << i))) | ||
630 | return SYSINT1_IRQ(i); | ||
631 | } | ||
632 | } | ||
633 | |||
634 | if (mask2) { | ||
635 | for (i = 0; i < 16; i++) { | ||
636 | if (irq == INT_TO_IRQ(sysint2_assign[i]) && (mask2 & (1 << i))) | ||
637 | return SYSINT2_IRQ(i); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2); | ||
642 | |||
643 | return -1; | ||
644 | } | ||
645 | |||
646 | static int __init vr41xx_icu_init(void) | ||
647 | { | ||
648 | unsigned long icu1_start, icu2_start; | ||
649 | int i; | ||
650 | |||
651 | switch (current_cpu_type()) { | ||
652 | case CPU_VR4111: | ||
653 | case CPU_VR4121: | ||
654 | icu1_start = ICU1_TYPE1_BASE; | ||
655 | icu2_start = ICU2_TYPE1_BASE; | ||
656 | break; | ||
657 | case CPU_VR4122: | ||
658 | case CPU_VR4131: | ||
659 | case CPU_VR4133: | ||
660 | icu1_start = ICU1_TYPE2_BASE; | ||
661 | icu2_start = ICU2_TYPE2_BASE; | ||
662 | break; | ||
663 | default: | ||
664 | printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n"); | ||
665 | return -ENODEV; | ||
666 | } | ||
667 | |||
668 | if (request_mem_region(icu1_start, ICU1_SIZE, "ICU") == NULL) | ||
669 | return -EBUSY; | ||
670 | |||
671 | if (request_mem_region(icu2_start, ICU2_SIZE, "ICU") == NULL) { | ||
672 | release_mem_region(icu1_start, ICU1_SIZE); | ||
673 | return -EBUSY; | ||
674 | } | ||
675 | |||
676 | icu1_base = ioremap(icu1_start, ICU1_SIZE); | ||
677 | if (icu1_base == NULL) { | ||
678 | release_mem_region(icu1_start, ICU1_SIZE); | ||
679 | release_mem_region(icu2_start, ICU2_SIZE); | ||
680 | return -ENOMEM; | ||
681 | } | ||
682 | |||
683 | icu2_base = ioremap(icu2_start, ICU2_SIZE); | ||
684 | if (icu2_base == NULL) { | ||
685 | iounmap(icu1_base); | ||
686 | release_mem_region(icu1_start, ICU1_SIZE); | ||
687 | release_mem_region(icu2_start, ICU2_SIZE); | ||
688 | return -ENOMEM; | ||
689 | } | ||
690 | |||
691 | icu1_write(MSYSINT1REG, 0); | ||
692 | icu1_write(MGIUINTLREG, 0xffff); | ||
693 | |||
694 | icu2_write(MSYSINT2REG, 0); | ||
695 | icu2_write(MGIUINTHREG, 0xffff); | ||
696 | |||
697 | for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++) | ||
698 | irq_set_chip_and_handler(i, &sysint1_irq_type, | ||
699 | handle_level_irq); | ||
700 | |||
701 | for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++) | ||
702 | irq_set_chip_and_handler(i, &sysint2_irq_type, | ||
703 | handle_level_irq); | ||
704 | |||
705 | cascade_irq(INT0_IRQ, icu_get_irq); | ||
706 | cascade_irq(INT1_IRQ, icu_get_irq); | ||
707 | cascade_irq(INT2_IRQ, icu_get_irq); | ||
708 | cascade_irq(INT3_IRQ, icu_get_irq); | ||
709 | cascade_irq(INT4_IRQ, icu_get_irq); | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | core_initcall(vr41xx_icu_init); | ||