diff options
-rw-r--r-- | arch/powerpc/sysdev/xilinx_intc.c | 76 |
1 files changed, 58 insertions, 18 deletions
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index c658b413c9b4..90b57724a5e4 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
26 | #include <asm/io.h> | 26 | #include <asm/io.h> |
27 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
28 | #include <asm/i8259.h> | ||
28 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
29 | 30 | ||
30 | /* | 31 | /* |
@@ -191,20 +192,14 @@ struct irq_host * __init | |||
191 | xilinx_intc_init(struct device_node *np) | 192 | xilinx_intc_init(struct device_node *np) |
192 | { | 193 | { |
193 | struct irq_host * irq; | 194 | struct irq_host * irq; |
194 | struct resource res; | ||
195 | void * regs; | 195 | void * regs; |
196 | int rc; | ||
197 | 196 | ||
198 | /* Find and map the intc registers */ | 197 | /* Find and map the intc registers */ |
199 | rc = of_address_to_resource(np, 0, &res); | 198 | regs = of_iomap(np, 0); |
200 | if (rc) { | 199 | if (!regs) { |
201 | printk(KERN_ERR __FILE__ ": of_address_to_resource() failed\n"); | 200 | pr_err("xilinx_intc: could not map registers\n"); |
202 | return NULL; | 201 | return NULL; |
203 | } | 202 | } |
204 | regs = ioremap(res.start, 32); | ||
205 | |||
206 | printk(KERN_INFO "Xilinx intc at 0x%08llx mapped to 0x%p\n", | ||
207 | (unsigned long long) res.start, regs); | ||
208 | 203 | ||
209 | /* Setup interrupt controller */ | 204 | /* Setup interrupt controller */ |
210 | out_be32(regs + XINTC_IER, 0); /* disable all irqs */ | 205 | out_be32(regs + XINTC_IER, 0); /* disable all irqs */ |
@@ -217,6 +212,7 @@ xilinx_intc_init(struct device_node *np) | |||
217 | if (!irq) | 212 | if (!irq) |
218 | panic(__FILE__ ": Cannot allocate IRQ host\n"); | 213 | panic(__FILE__ ": Cannot allocate IRQ host\n"); |
219 | irq->host_data = regs; | 214 | irq->host_data = regs; |
215 | |||
220 | return irq; | 216 | return irq; |
221 | } | 217 | } |
222 | 218 | ||
@@ -227,23 +223,65 @@ int xilinx_intc_get_irq(void) | |||
227 | return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR)); | 223 | return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR)); |
228 | } | 224 | } |
229 | 225 | ||
226 | #if defined(CONFIG_PPC_I8259) | ||
227 | /* | ||
228 | * Support code for cascading to 8259 interrupt controllers | ||
229 | */ | ||
230 | static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc) | ||
231 | { | ||
232 | unsigned int cascade_irq = i8259_irq(); | ||
233 | if (cascade_irq) | ||
234 | generic_handle_irq(cascade_irq); | ||
235 | |||
236 | /* Let xilinx_intc end the interrupt */ | ||
237 | desc->chip->ack(irq); | ||
238 | desc->chip->unmask(irq); | ||
239 | } | ||
240 | |||
241 | static void __init xilinx_i8259_setup_cascade(void) | ||
242 | { | ||
243 | struct device_node *cascade_node; | ||
244 | int cascade_irq; | ||
245 | |||
246 | /* Initialize i8259 controller */ | ||
247 | cascade_node = of_find_compatible_node(NULL, NULL, "chrp,iic"); | ||
248 | if (!cascade_node) | ||
249 | return; | ||
250 | |||
251 | cascade_irq = irq_of_parse_and_map(cascade_node, 0); | ||
252 | if (!cascade_irq) { | ||
253 | pr_err("virtex_ml510: Failed to map cascade interrupt\n"); | ||
254 | goto out; | ||
255 | } | ||
256 | |||
257 | i8259_init(cascade_node, 0); | ||
258 | set_irq_chained_handler(cascade_irq, xilinx_i8259_cascade); | ||
259 | |||
260 | out: | ||
261 | of_node_put(cascade_node); | ||
262 | } | ||
263 | #else | ||
264 | static inline void xilinx_i8259_setup_cascade(void) { return; } | ||
265 | #endif /* defined(CONFIG_PPC_I8259) */ | ||
266 | |||
267 | static struct of_device_id xilinx_intc_match[] __initconst = { | ||
268 | { .compatible = "xlnx,opb-intc-1.00.c", }, | ||
269 | { .compatible = "xlnx,xps-intc-1.00.a", }, | ||
270 | {} | ||
271 | }; | ||
272 | |||
273 | /* | ||
274 | * Initialize master Xilinx interrupt controller | ||
275 | */ | ||
230 | void __init xilinx_intc_init_tree(void) | 276 | void __init xilinx_intc_init_tree(void) |
231 | { | 277 | { |
232 | struct device_node *np; | 278 | struct device_node *np; |
233 | 279 | ||
234 | /* find top level interrupt controller */ | 280 | /* find top level interrupt controller */ |
235 | for_each_compatible_node(np, NULL, "xlnx,opb-intc-1.00.c") { | 281 | for_each_matching_node(np, xilinx_intc_match) { |
236 | if (!of_get_property(np, "interrupts", NULL)) | 282 | if (!of_get_property(np, "interrupts", NULL)) |
237 | break; | 283 | break; |
238 | } | 284 | } |
239 | if (!np) { | ||
240 | for_each_compatible_node(np, NULL, "xlnx,xps-intc-1.00.a") { | ||
241 | if (!of_get_property(np, "interrupts", NULL)) | ||
242 | break; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /* xilinx interrupt controller needs to be top level */ | ||
247 | BUG_ON(!np); | 285 | BUG_ON(!np); |
248 | 286 | ||
249 | master_irqhost = xilinx_intc_init(np); | 287 | master_irqhost = xilinx_intc_init(np); |
@@ -251,4 +289,6 @@ void __init xilinx_intc_init_tree(void) | |||
251 | 289 | ||
252 | irq_set_default_host(master_irqhost); | 290 | irq_set_default_host(master_irqhost); |
253 | of_node_put(np); | 291 | of_node_put(np); |
292 | |||
293 | xilinx_i8259_setup_cascade(); | ||
254 | } | 294 | } |