diff options
Diffstat (limited to 'arch/arm/mach-iop3xx/iop331-irq.c')
-rw-r--r-- | arch/arm/mach-iop3xx/iop331-irq.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/arch/arm/mach-iop3xx/iop331-irq.c b/arch/arm/mach-iop3xx/iop331-irq.c new file mode 100644 index 000000000000..f4d4321737a4 --- /dev/null +++ b/arch/arm/mach-iop3xx/iop331-irq.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-iop3xx/iop331-irq.c | ||
3 | * | ||
4 | * Generic IOP331 IRQ handling functionality | ||
5 | * | ||
6 | * Author: Dave Jiang <dave.jiang@intel.com> | ||
7 | * Copyright (C) 2003 Intel Corp. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/list.h> | ||
18 | |||
19 | #include <asm/mach/irq.h> | ||
20 | #include <asm/irq.h> | ||
21 | #include <asm/hardware.h> | ||
22 | |||
23 | #include <asm/mach-types.h> | ||
24 | |||
25 | static u32 iop331_mask0 = 0; | ||
26 | static u32 iop331_mask1 = 0; | ||
27 | |||
28 | static inline void intctl_write0(u32 val) | ||
29 | { | ||
30 | // INTCTL0 | ||
31 | asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val)); | ||
32 | } | ||
33 | |||
34 | static inline void intctl_write1(u32 val) | ||
35 | { | ||
36 | // INTCTL1 | ||
37 | asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val)); | ||
38 | } | ||
39 | |||
40 | static inline void intstr_write0(u32 val) | ||
41 | { | ||
42 | // INTSTR0 | ||
43 | asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val)); | ||
44 | } | ||
45 | |||
46 | static inline void intstr_write1(u32 val) | ||
47 | { | ||
48 | // INTSTR1 | ||
49 | asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val)); | ||
50 | } | ||
51 | |||
52 | static void | ||
53 | iop331_irq_mask1 (unsigned int irq) | ||
54 | { | ||
55 | iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS)); | ||
56 | intctl_write0(iop331_mask0); | ||
57 | } | ||
58 | |||
59 | static void | ||
60 | iop331_irq_mask2 (unsigned int irq) | ||
61 | { | ||
62 | iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32)); | ||
63 | intctl_write1(iop331_mask1); | ||
64 | } | ||
65 | |||
66 | static void | ||
67 | iop331_irq_unmask1(unsigned int irq) | ||
68 | { | ||
69 | iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS)); | ||
70 | intctl_write0(iop331_mask0); | ||
71 | } | ||
72 | |||
73 | static void | ||
74 | iop331_irq_unmask2(unsigned int irq) | ||
75 | { | ||
76 | iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32)); | ||
77 | intctl_write1(iop331_mask1); | ||
78 | } | ||
79 | |||
80 | struct irqchip iop331_irqchip1 = { | ||
81 | .ack = iop331_irq_mask1, | ||
82 | .mask = iop331_irq_mask1, | ||
83 | .unmask = iop331_irq_unmask1, | ||
84 | }; | ||
85 | |||
86 | struct irqchip iop331_irqchip2 = { | ||
87 | .ack = iop331_irq_mask2, | ||
88 | .mask = iop331_irq_mask2, | ||
89 | .unmask = iop331_irq_unmask2, | ||
90 | }; | ||
91 | |||
92 | void __init iop331_init_irq(void) | ||
93 | { | ||
94 | unsigned int i, tmp; | ||
95 | |||
96 | /* Enable access to coprocessor 6 for dealing with IRQs. | ||
97 | * From RMK: | ||
98 | * Basically, the Intel documentation here is poor. It appears that | ||
99 | * you need to set the bit to be able to access the coprocessor from | ||
100 | * SVC mode. Whether that allows access from user space or not is | ||
101 | * unclear. | ||
102 | */ | ||
103 | asm volatile ( | ||
104 | "mrc p15, 0, %0, c15, c1, 0\n\t" | ||
105 | "orr %0, %0, %1\n\t" | ||
106 | "mcr p15, 0, %0, c15, c1, 0\n\t" | ||
107 | /* The action is delayed, so we have to do this: */ | ||
108 | "mrc p15, 0, %0, c15, c1, 0\n\t" | ||
109 | "mov %0, %0\n\t" | ||
110 | "sub pc, pc, #4" | ||
111 | : "=r" (tmp) : "i" (1 << 6) ); | ||
112 | |||
113 | intctl_write0(0); // disable all interrupts | ||
114 | intctl_write1(0); | ||
115 | intstr_write0(0); // treat all as IRQ | ||
116 | intstr_write1(0); | ||
117 | if(machine_is_iq80331()) // all interrupts are inputs to chip | ||
118 | *IOP331_PCIIRSR = 0x0f; | ||
119 | |||
120 | for(i = IOP331_IRQ_OFS; i < NR_IOP331_IRQS; i++) | ||
121 | { | ||
122 | set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2); | ||
123 | set_irq_handler(i, do_level_IRQ); | ||
124 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
125 | } | ||
126 | } | ||
127 | |||