diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-19 10:32:15 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-02-19 06:11:33 -0500 |
commit | c41b16f8c9d9dc74ed5669d4a3e3d42374c9e609 (patch) | |
tree | 0e7ee2bef09e6c752cda71087795bd40f0f35177 /arch/arm | |
parent | dc37c31bbfaf87118d6c827be0a38a512a40b741 (diff) |
ARM: integrator/versatile: consolidate FPGA IRQ handling code
Consolidate the FPGA IRQ handling code. Integrator/AP and Versatile
have one FPGA-based IRQ handler each. Integrator/CP has three.
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_ap.c | 41 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_cp.c | 142 | ||||
-rw-r--r-- | arch/arm/mach-versatile/core.c | 57 | ||||
-rw-r--r-- | arch/arm/mach-versatile/include/mach/hardware.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-versatile/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/plat-versatile/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-versatile/fpga-irq.c | 72 | ||||
-rw-r--r-- | arch/arm/plat-versatile/include/plat/fpga-irq.h | 12 |
9 files changed, 140 insertions, 192 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fe8d6fa12fe7..a6ccef6d9d72 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -229,6 +229,7 @@ config ARCH_INTEGRATOR | |||
229 | select ICST | 229 | select ICST |
230 | select GENERIC_CLOCKEVENTS | 230 | select GENERIC_CLOCKEVENTS |
231 | select PLAT_VERSATILE | 231 | select PLAT_VERSATILE |
232 | select PLAT_VERSATILE_FPGA_IRQ | ||
232 | help | 233 | help |
233 | Support for ARM's Integrator platform. | 234 | Support for ARM's Integrator platform. |
234 | 235 | ||
@@ -256,6 +257,7 @@ config ARCH_VERSATILE | |||
256 | select ARCH_WANT_OPTIONAL_GPIOLIB | 257 | select ARCH_WANT_OPTIONAL_GPIOLIB |
257 | select PLAT_VERSATILE | 258 | select PLAT_VERSATILE |
258 | select PLAT_VERSATILE_CLCD | 259 | select PLAT_VERSATILE_CLCD |
260 | select PLAT_VERSATILE_FPGA_IRQ | ||
259 | select ARM_TIMER_SP804 | 261 | select ARM_TIMER_SP804 |
260 | help | 262 | help |
261 | This enables support for ARM Ltd Versatile board. | 263 | This enables support for ARM Ltd Versatile board. |
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 4f06b5d72489..980803ff348c 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c | |||
@@ -48,6 +48,8 @@ | |||
48 | #include <asm/mach/map.h> | 48 | #include <asm/mach/map.h> |
49 | #include <asm/mach/time.h> | 49 | #include <asm/mach/time.h> |
50 | 50 | ||
51 | #include <plat/fpga-irq.h> | ||
52 | |||
51 | #include "common.h" | 53 | #include "common.h" |
52 | 54 | ||
53 | /* | 55 | /* |
@@ -57,10 +59,10 @@ | |||
57 | * Setup a VA for the Integrator interrupt controller (for header #0, | 59 | * Setup a VA for the Integrator interrupt controller (for header #0, |
58 | * just for now). | 60 | * just for now). |
59 | */ | 61 | */ |
60 | #define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) | 62 | #define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE) |
61 | #define VA_SC_BASE IO_ADDRESS(INTEGRATOR_SC_BASE) | 63 | #define VA_SC_BASE __io_address(INTEGRATOR_SC_BASE) |
62 | #define VA_EBI_BASE IO_ADDRESS(INTEGRATOR_EBI_BASE) | 64 | #define VA_EBI_BASE __io_address(INTEGRATOR_EBI_BASE) |
63 | #define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_IC) | 65 | #define VA_CMIC_BASE __io_address(INTEGRATOR_HDR_IC) |
64 | 66 | ||
65 | /* | 67 | /* |
66 | * Logical Physical | 68 | * Logical Physical |
@@ -156,27 +158,14 @@ static void __init ap_map_io(void) | |||
156 | 158 | ||
157 | #define INTEGRATOR_SC_VALID_INT 0x003fffff | 159 | #define INTEGRATOR_SC_VALID_INT 0x003fffff |
158 | 160 | ||
159 | static void sc_mask_irq(struct irq_data *d) | 161 | static struct fpga_irq_data sc_irq_data = { |
160 | { | 162 | .base = VA_IC_BASE, |
161 | writel(1 << d->irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); | 163 | .irq_start = 0, |
162 | } | 164 | .chip.name = "SC", |
163 | |||
164 | static void sc_unmask_irq(struct irq_data *d) | ||
165 | { | ||
166 | writel(1 << d->irq, VA_IC_BASE + IRQ_ENABLE_SET); | ||
167 | } | ||
168 | |||
169 | static struct irq_chip sc_chip = { | ||
170 | .name = "SC", | ||
171 | .irq_ack = sc_mask_irq, | ||
172 | .irq_mask = sc_mask_irq, | ||
173 | .irq_unmask = sc_unmask_irq, | ||
174 | }; | 165 | }; |
175 | 166 | ||
176 | static void __init ap_init_irq(void) | 167 | static void __init ap_init_irq(void) |
177 | { | 168 | { |
178 | unsigned int i; | ||
179 | |||
180 | /* Disable all interrupts initially. */ | 169 | /* Disable all interrupts initially. */ |
181 | /* Do the core module ones */ | 170 | /* Do the core module ones */ |
182 | writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); | 171 | writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); |
@@ -185,13 +174,7 @@ static void __init ap_init_irq(void) | |||
185 | writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); | 174 | writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); |
186 | writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); | 175 | writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); |
187 | 176 | ||
188 | for (i = 0; i < NR_IRQS; i++) { | 177 | fpga_irq_init(-1, INTEGRATOR_SC_VALID_INT, &sc_irq_data); |
189 | if (((1 << i) & INTEGRATOR_SC_VALID_INT) != 0) { | ||
190 | set_irq_chip(i, &sc_chip); | ||
191 | set_irq_handler(i, handle_level_irq); | ||
192 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
193 | } | ||
194 | } | ||
195 | } | 178 | } |
196 | 179 | ||
197 | #ifdef CONFIG_PM | 180 | #ifdef CONFIG_PM |
@@ -282,7 +265,7 @@ static void ap_flash_exit(void) | |||
282 | 265 | ||
283 | static void ap_flash_set_vpp(int on) | 266 | static void ap_flash_set_vpp(int on) |
284 | { | 267 | { |
285 | unsigned long reg = on ? SC_CTRLS : SC_CTRLC; | 268 | void __iomem *reg = on ? SC_CTRLS : SC_CTRLC; |
286 | 269 | ||
287 | writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg); | 270 | writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg); |
288 | } | 271 | } |
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index e6700aab849a..05da36f754dd 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/hardware/timer-sp.h> | 43 | #include <asm/hardware/timer-sp.h> |
44 | 44 | ||
45 | #include <plat/clcd.h> | 45 | #include <plat/clcd.h> |
46 | #include <plat/fpga-irq.h> | ||
46 | 47 | ||
47 | #include "common.h" | 48 | #include "common.h" |
48 | 49 | ||
@@ -51,9 +52,9 @@ | |||
51 | 52 | ||
52 | #define INTCP_PA_CLCD_BASE 0xc0000000 | 53 | #define INTCP_PA_CLCD_BASE 0xc0000000 |
53 | 54 | ||
54 | #define INTCP_VA_CIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE + 0x40) | 55 | #define INTCP_VA_CIC_BASE __io_address(INTEGRATOR_HDR_BASE + 0x40) |
55 | #define INTCP_VA_PIC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) | 56 | #define INTCP_VA_PIC_BASE __io_address(INTEGRATOR_IC_BASE) |
56 | #define INTCP_VA_SIC_BASE IO_ADDRESS(INTEGRATOR_CP_SIC_BASE) | 57 | #define INTCP_VA_SIC_BASE __io_address(INTEGRATOR_CP_SIC_BASE) |
57 | 58 | ||
58 | #define INTCP_ETH_SIZE 0x10 | 59 | #define INTCP_ETH_SIZE 0x10 |
59 | 60 | ||
@@ -141,129 +142,48 @@ static void __init intcp_map_io(void) | |||
141 | iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); | 142 | iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); |
142 | } | 143 | } |
143 | 144 | ||
144 | #define cic_writel __raw_writel | 145 | static struct fpga_irq_data cic_irq_data = { |
145 | #define cic_readl __raw_readl | 146 | .base = INTCP_VA_CIC_BASE, |
146 | #define pic_writel __raw_writel | 147 | .irq_start = IRQ_CIC_START, |
147 | #define pic_readl __raw_readl | 148 | .chip.name = "CIC", |
148 | #define sic_writel __raw_writel | ||
149 | #define sic_readl __raw_readl | ||
150 | |||
151 | static void cic_mask_irq(struct irq_data *d) | ||
152 | { | ||
153 | unsigned int irq = d->irq - IRQ_CIC_START; | ||
154 | cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); | ||
155 | } | ||
156 | |||
157 | static void cic_unmask_irq(struct irq_data *d) | ||
158 | { | ||
159 | unsigned int irq = d->irq - IRQ_CIC_START; | ||
160 | cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET); | ||
161 | } | ||
162 | |||
163 | static struct irq_chip cic_chip = { | ||
164 | .name = "CIC", | ||
165 | .irq_ack = cic_mask_irq, | ||
166 | .irq_mask = cic_mask_irq, | ||
167 | .irq_unmask = cic_unmask_irq, | ||
168 | }; | 149 | }; |
169 | 150 | ||
170 | static void pic_mask_irq(struct irq_data *d) | 151 | static struct fpga_irq_data pic_irq_data = { |
171 | { | 152 | .base = INTCP_VA_PIC_BASE, |
172 | unsigned int irq = d->irq - IRQ_PIC_START; | 153 | .irq_start = IRQ_PIC_START, |
173 | pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); | 154 | .chip.name = "PIC", |
174 | } | ||
175 | |||
176 | static void pic_unmask_irq(struct irq_data *d) | ||
177 | { | ||
178 | unsigned int irq = d->irq - IRQ_PIC_START; | ||
179 | pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET); | ||
180 | } | ||
181 | |||
182 | static struct irq_chip pic_chip = { | ||
183 | .name = "PIC", | ||
184 | .irq_ack = pic_mask_irq, | ||
185 | .irq_mask = pic_mask_irq, | ||
186 | .irq_unmask = pic_unmask_irq, | ||
187 | }; | 155 | }; |
188 | 156 | ||
189 | static void sic_mask_irq(struct irq_data *d) | 157 | static struct fpga_irq_data sic_irq_data = { |
190 | { | 158 | .base = INTCP_VA_SIC_BASE, |
191 | unsigned int irq = d->irq - IRQ_SIC_START; | 159 | .irq_start = IRQ_SIC_START, |
192 | sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); | 160 | .chip.name = "SIC", |
193 | } | ||
194 | |||
195 | static void sic_unmask_irq(struct irq_data *d) | ||
196 | { | ||
197 | unsigned int irq = d->irq - IRQ_SIC_START; | ||
198 | sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET); | ||
199 | } | ||
200 | |||
201 | static struct irq_chip sic_chip = { | ||
202 | .name = "SIC", | ||
203 | .irq_ack = sic_mask_irq, | ||
204 | .irq_mask = sic_mask_irq, | ||
205 | .irq_unmask = sic_unmask_irq, | ||
206 | }; | 161 | }; |
207 | 162 | ||
208 | static void | ||
209 | sic_handle_irq(unsigned int irq, struct irq_desc *desc) | ||
210 | { | ||
211 | unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS); | ||
212 | |||
213 | if (status == 0) { | ||
214 | do_bad_IRQ(irq, desc); | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | do { | ||
219 | irq = ffs(status) - 1; | ||
220 | status &= ~(1 << irq); | ||
221 | |||
222 | irq += IRQ_SIC_START; | ||
223 | |||
224 | generic_handle_irq(irq); | ||
225 | } while (status); | ||
226 | } | ||
227 | |||
228 | static void __init intcp_init_irq(void) | 163 | static void __init intcp_init_irq(void) |
229 | { | 164 | { |
230 | unsigned int i; | 165 | u32 pic_mask, sic_mask; |
166 | |||
167 | pic_mask = ~((~0u) << (11 - IRQ_PIC_START)); | ||
168 | pic_mask |= (~((~0u) << (29 - 22))) << 22; | ||
169 | sic_mask = ~((~0u) << (1 + IRQ_SIC_END - IRQ_SIC_START)); | ||
231 | 170 | ||
232 | /* | 171 | /* |
233 | * Disable all interrupt sources | 172 | * Disable all interrupt sources |
234 | */ | 173 | */ |
235 | pic_writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); | 174 | writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); |
236 | pic_writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR); | 175 | writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR); |
237 | 176 | writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); | |
238 | for (i = IRQ_PIC_START; i <= IRQ_PIC_END; i++) { | 177 | writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR); |
239 | if (i == 11) | 178 | writel(sic_mask, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); |
240 | i = 22; | 179 | writel(sic_mask, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); |
241 | if (i == 29) | ||
242 | break; | ||
243 | set_irq_chip(i, &pic_chip); | ||
244 | set_irq_handler(i, handle_level_irq); | ||
245 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
246 | } | ||
247 | 180 | ||
248 | cic_writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); | 181 | fpga_irq_init(-1, pic_mask, &pic_irq_data); |
249 | cic_writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR); | ||
250 | 182 | ||
251 | for (i = IRQ_CIC_START; i <= IRQ_CIC_END; i++) { | 183 | fpga_irq_init(-1, ~((~0u) << (1 + IRQ_CIC_END - IRQ_CIC_START)), |
252 | set_irq_chip(i, &cic_chip); | 184 | &cic_irq_data); |
253 | set_irq_handler(i, handle_level_irq); | ||
254 | set_irq_flags(i, IRQF_VALID); | ||
255 | } | ||
256 | |||
257 | sic_writel(0x00000fff, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); | ||
258 | sic_writel(0x00000fff, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); | ||
259 | |||
260 | for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { | ||
261 | set_irq_chip(i, &sic_chip); | ||
262 | set_irq_handler(i, handle_level_irq); | ||
263 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
264 | } | ||
265 | 185 | ||
266 | set_irq_chained_handler(IRQ_CP_CPPLDINT, sic_handle_irq); | 186 | fpga_irq_init(IRQ_CP_CPPLDINT, sic_mask, &sic_irq_data); |
267 | } | 187 | } |
268 | 188 | ||
269 | /* | 189 | /* |
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 630a1c96f90b..eb7ffa0ee8b5 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <asm/hardware/timer-sp.h> | 51 | #include <asm/hardware/timer-sp.h> |
52 | 52 | ||
53 | #include <plat/clcd.h> | 53 | #include <plat/clcd.h> |
54 | #include <plat/fpga-irq.h> | ||
54 | #include <plat/sched_clock.h> | 55 | #include <plat/sched_clock.h> |
55 | 56 | ||
56 | #include "core.h" | 57 | #include "core.h" |
@@ -64,47 +65,12 @@ | |||
64 | #define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE) | 65 | #define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE) |
65 | #define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE) | 66 | #define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE) |
66 | 67 | ||
67 | static void sic_mask_irq(struct irq_data *d) | 68 | static struct fpga_irq_data sic_irq = { |
68 | { | 69 | .base = VA_SIC_BASE, |
69 | unsigned int irq = d->irq - IRQ_SIC_START; | 70 | .irq_start = IRQ_SIC_START, |
70 | 71 | .chip.name = "SIC", | |
71 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); | ||
72 | } | ||
73 | |||
74 | static void sic_unmask_irq(struct irq_data *d) | ||
75 | { | ||
76 | unsigned int irq = d->irq - IRQ_SIC_START; | ||
77 | |||
78 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET); | ||
79 | } | ||
80 | |||
81 | static struct irq_chip sic_chip = { | ||
82 | .name = "SIC", | ||
83 | .irq_ack = sic_mask_irq, | ||
84 | .irq_mask = sic_mask_irq, | ||
85 | .irq_unmask = sic_unmask_irq, | ||
86 | }; | 72 | }; |
87 | 73 | ||
88 | static void | ||
89 | sic_handle_irq(unsigned int irq, struct irq_desc *desc) | ||
90 | { | ||
91 | unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS); | ||
92 | |||
93 | if (status == 0) { | ||
94 | do_bad_IRQ(irq, desc); | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | do { | ||
99 | irq = ffs(status) - 1; | ||
100 | status &= ~(1 << irq); | ||
101 | |||
102 | irq += IRQ_SIC_START; | ||
103 | |||
104 | generic_handle_irq(irq); | ||
105 | } while (status); | ||
106 | } | ||
107 | |||
108 | #if 1 | 74 | #if 1 |
109 | #define IRQ_MMCI0A IRQ_VICSOURCE22 | 75 | #define IRQ_MMCI0A IRQ_VICSOURCE22 |
110 | #define IRQ_AACI IRQ_VICSOURCE24 | 76 | #define IRQ_AACI IRQ_VICSOURCE24 |
@@ -119,22 +85,11 @@ sic_handle_irq(unsigned int irq, struct irq_desc *desc) | |||
119 | 85 | ||
120 | void __init versatile_init_irq(void) | 86 | void __init versatile_init_irq(void) |
121 | { | 87 | { |
122 | unsigned int i; | ||
123 | |||
124 | vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0); | 88 | vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0); |
125 | 89 | ||
126 | set_irq_chained_handler(IRQ_VICSOURCE31, sic_handle_irq); | ||
127 | |||
128 | /* Do second interrupt controller */ | ||
129 | writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); | 90 | writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); |
130 | 91 | ||
131 | for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { | 92 | fpga_irq_init(IRQ_VICSOURCE31, ~PIC_MASK, &sic_irq); |
132 | if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) { | ||
133 | set_irq_chip(i, &sic_chip); | ||
134 | set_irq_handler(i, handle_level_irq); | ||
135 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
136 | } | ||
137 | } | ||
138 | 93 | ||
139 | /* | 94 | /* |
140 | * Interrupts on secondary controller from 0 to 8 are routed to | 95 | * Interrupts on secondary controller from 0 to 8 are routed to |
diff --git a/arch/arm/mach-versatile/include/mach/hardware.h b/arch/arm/mach-versatile/include/mach/hardware.h index b5e75bb44965..6911e1f5f156 100644 --- a/arch/arm/mach-versatile/include/mach/hardware.h +++ b/arch/arm/mach-versatile/include/mach/hardware.h | |||
@@ -39,6 +39,6 @@ | |||
39 | /* macro to get at IO space when running virtually */ | 39 | /* macro to get at IO space when running virtually */ |
40 | #define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) | 40 | #define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) |
41 | 41 | ||
42 | #define __io_address(n) __io(IO_ADDRESS(n)) | 42 | #define __io_address(n) ((void __iomem __force *)IO_ADDRESS(n)) |
43 | 43 | ||
44 | #endif | 44 | #endif |
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig index c5e2cd014c61..0b275008d3e0 100644 --- a/arch/arm/plat-versatile/Kconfig +++ b/arch/arm/plat-versatile/Kconfig | |||
@@ -3,6 +3,9 @@ if PLAT_VERSATILE | |||
3 | config PLAT_VERSATILE_CLCD | 3 | config PLAT_VERSATILE_CLCD |
4 | bool | 4 | bool |
5 | 5 | ||
6 | config PLAT_VERSATILE_FPGA_IRQ | ||
7 | bool | ||
8 | |||
6 | config PLAT_VERSATILE_LEDS | 9 | config PLAT_VERSATILE_LEDS |
7 | def_bool y if LEDS_CLASS | 10 | def_bool y if LEDS_CLASS |
8 | depends on ARCH_REALVIEW || ARCH_VERSATILE | 11 | depends on ARCH_REALVIEW || ARCH_VERSATILE |
diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile index de6f42f003b3..41f57f4b9038 100644 --- a/arch/arm/plat-versatile/Makefile +++ b/arch/arm/plat-versatile/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-y := clock.o | 1 | obj-y := clock.o |
2 | obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o | 2 | obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o |
3 | obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o | ||
3 | obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o | 4 | obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o |
4 | obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o | 5 | obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o |
5 | 6 | ||
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c new file mode 100644 index 000000000000..31d945d37e4f --- /dev/null +++ b/arch/arm/plat-versatile/fpga-irq.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Support for Versatile FPGA-based IRQ controllers | ||
3 | */ | ||
4 | #include <linux/irq.h> | ||
5 | #include <linux/io.h> | ||
6 | |||
7 | #include <asm/mach/irq.h> | ||
8 | #include <plat/fpga-irq.h> | ||
9 | |||
10 | #define IRQ_STATUS 0x00 | ||
11 | #define IRQ_RAW_STATUS 0x04 | ||
12 | #define IRQ_ENABLE_SET 0x08 | ||
13 | #define IRQ_ENABLE_CLEAR 0x0c | ||
14 | |||
15 | static void fpga_irq_mask(struct irq_data *d) | ||
16 | { | ||
17 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | ||
18 | u32 mask = 1 << (d->irq - f->irq_start); | ||
19 | |||
20 | writel(mask, f->base + IRQ_ENABLE_CLEAR); | ||
21 | } | ||
22 | |||
23 | static void fpga_irq_unmask(struct irq_data *d) | ||
24 | { | ||
25 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | ||
26 | u32 mask = 1 << (d->irq - f->irq_start); | ||
27 | |||
28 | writel(mask, f->base + IRQ_ENABLE_SET); | ||
29 | } | ||
30 | |||
31 | static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc) | ||
32 | { | ||
33 | struct fpga_irq_data *f = get_irq_desc_data(desc); | ||
34 | u32 status = readl(f->base + IRQ_STATUS); | ||
35 | |||
36 | if (status == 0) { | ||
37 | do_bad_IRQ(irq, desc); | ||
38 | return; | ||
39 | } | ||
40 | |||
41 | do { | ||
42 | irq = ffs(status) - 1; | ||
43 | status &= ~(1 << irq); | ||
44 | |||
45 | generic_handle_irq(irq + f->irq_start); | ||
46 | } while (status); | ||
47 | } | ||
48 | |||
49 | void __init fpga_irq_init(int parent_irq, u32 valid, struct fpga_irq_data *f) | ||
50 | { | ||
51 | unsigned int i; | ||
52 | |||
53 | f->chip.irq_ack = fpga_irq_mask; | ||
54 | f->chip.irq_mask = fpga_irq_mask; | ||
55 | f->chip.irq_unmask = fpga_irq_unmask; | ||
56 | |||
57 | if (parent_irq != -1) { | ||
58 | set_irq_data(parent_irq, f); | ||
59 | set_irq_chained_handler(parent_irq, fpga_irq_handle); | ||
60 | } | ||
61 | |||
62 | for (i = 0; i < 32; i++) { | ||
63 | if (valid & (1 << i)) { | ||
64 | unsigned int irq = f->irq_start + i; | ||
65 | |||
66 | set_irq_chip_data(irq, f); | ||
67 | set_irq_chip(irq, &f->chip); | ||
68 | set_irq_handler(irq, handle_level_irq); | ||
69 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
70 | } | ||
71 | } | ||
72 | } | ||
diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h new file mode 100644 index 000000000000..627fafd1e595 --- /dev/null +++ b/arch/arm/plat-versatile/include/plat/fpga-irq.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef PLAT_FPGA_IRQ_H | ||
2 | #define PLAT_FPGA_IRQ_H | ||
3 | |||
4 | struct fpga_irq_data { | ||
5 | void __iomem *base; | ||
6 | unsigned int irq_start; | ||
7 | struct irq_chip chip; | ||
8 | }; | ||
9 | |||
10 | void fpga_irq_init(int, u32, struct fpga_irq_data *); | ||
11 | |||
12 | #endif | ||