aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2009-06-06 10:15:03 -0600
committerGrant Likely <grant.likely@secretlab.ca>2009-06-06 10:15:03 -0600
commit1745fbc744a934b235c2e5ecb5380079fa54be38 (patch)
tree6db68cba9637ca11448e127a32e0c92fdd2b635c /arch
parent64f16502475ddf663169369fffff6da9b10ea9fb (diff)
powerpc/virtex: refactor intc driver and add support for i8259 cascading
This patch refactors some of the xilinx_intc interrupt controller driver and adds support for cascading an i8259 off one of the irq lines. This patch was based on the ML510 support work done by Roderick Colenbrander. Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/sysdev/xilinx_intc.c76
1 files changed, 58 insertions, 18 deletions
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index c658b413c9b..90b57724a5e 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -25,6 +25,7 @@
#include <linux/of.h>
#include <asm/io.h>
#include <asm/processor.h>
+#include <asm/i8259.h>
#include <asm/irq.h>
/*
@@ -191,20 +192,14 @@ struct irq_host * __init
xilinx_intc_init(struct device_node *np)
{
struct irq_host * irq;
- struct resource res;
void * regs;
- int rc;
/* Find and map the intc registers */
- rc = of_address_to_resource(np, 0, &res);
- if (rc) {
- printk(KERN_ERR __FILE__ ": of_address_to_resource() failed\n");
+ regs = of_iomap(np, 0);
+ if (!regs) {
+ pr_err("xilinx_intc: could not map registers\n");
return NULL;
}
- regs = ioremap(res.start, 32);
-
- printk(KERN_INFO "Xilinx intc at 0x%08llx mapped to 0x%p\n",
- (unsigned long long) res.start, regs);
/* Setup interrupt controller */
out_be32(regs + XINTC_IER, 0); /* disable all irqs */
@@ -217,6 +212,7 @@ xilinx_intc_init(struct device_node *np)
if (!irq)
panic(__FILE__ ": Cannot allocate IRQ host\n");
irq->host_data = regs;
+
return irq;
}
@@ -227,23 +223,65 @@ int xilinx_intc_get_irq(void)
return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR));
}
+#if defined(CONFIG_PPC_I8259)
+/*
+ * Support code for cascading to 8259 interrupt controllers
+ */
+static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned int cascade_irq = i8259_irq();
+ if (cascade_irq)
+ generic_handle_irq(cascade_irq);
+
+ /* Let xilinx_intc end the interrupt */
+ desc->chip->ack(irq);
+ desc->chip->unmask(irq);
+}
+
+static void __init xilinx_i8259_setup_cascade(void)
+{
+ struct device_node *cascade_node;
+ int cascade_irq;
+
+ /* Initialize i8259 controller */
+ cascade_node = of_find_compatible_node(NULL, NULL, "chrp,iic");
+ if (!cascade_node)
+ return;
+
+ cascade_irq = irq_of_parse_and_map(cascade_node, 0);
+ if (!cascade_irq) {
+ pr_err("virtex_ml510: Failed to map cascade interrupt\n");
+ goto out;
+ }
+
+ i8259_init(cascade_node, 0);
+ set_irq_chained_handler(cascade_irq, xilinx_i8259_cascade);
+
+ out:
+ of_node_put(cascade_node);
+}
+#else
+static inline void xilinx_i8259_setup_cascade(void) { return; }
+#endif /* defined(CONFIG_PPC_I8259) */
+
+static struct of_device_id xilinx_intc_match[] __initconst = {
+ { .compatible = "xlnx,opb-intc-1.00.c", },
+ { .compatible = "xlnx,xps-intc-1.00.a", },
+ {}
+};
+
+/*
+ * Initialize master Xilinx interrupt controller
+ */
void __init xilinx_intc_init_tree(void)
{
struct device_node *np;
/* find top level interrupt controller */
- for_each_compatible_node(np, NULL, "xlnx,opb-intc-1.00.c") {
+ for_each_matching_node(np, xilinx_intc_match) {
if (!of_get_property(np, "interrupts", NULL))
break;
}
- if (!np) {
- for_each_compatible_node(np, NULL, "xlnx,xps-intc-1.00.a") {
- if (!of_get_property(np, "interrupts", NULL))
- break;
- }
- }
-
- /* xilinx interrupt controller needs to be top level */
BUG_ON(!np);
master_irqhost = xilinx_intc_init(np);
@@ -251,4 +289,6 @@ void __init xilinx_intc_init_tree(void)
irq_set_default_host(master_irqhost);
of_node_put(np);
+
+ xilinx_i8259_setup_cascade();
}