[POWERPC] Use the genirq framework
[powerpc.git] / arch / powerpc / platforms / cell / spider-pic.c
index 7c3a0b6..98425ac 100644 (file)
@@ -82,17 +82,20 @@ static void __iomem *spider_get_irq_config(int irq)
        return pic + TIR_CFGA + 8 * spider_get_nr(irq);
 }
 
-static void spider_enable_irq(unsigned int irq)
+static void spider_unmask_irq(unsigned int irq)
 {
        int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
        void __iomem *cfg = spider_get_irq_config(irq);
        irq = spider_get_nr(irq);
 
+       /* FIXME: Most of that is configuration and has nothing to do with enabling/disable,
+        * besides, it's also partially bogus.
+        */
        out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
        out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
 }
 
-static void spider_disable_irq(unsigned int irq)
+static void spider_mask_irq(unsigned int irq)
 {
        void __iomem *cfg = spider_get_irq_config(irq);
        irq = spider_get_nr(irq);
@@ -100,39 +103,21 @@ static void spider_disable_irq(unsigned int irq)
        out_be32(cfg, in_be32(cfg) & ~0x30000000u);
 }
 
-static unsigned int spider_startup_irq(unsigned int irq)
-{
-       spider_enable_irq(irq);
-       return 0;
-}
-
-static void spider_shutdown_irq(unsigned int irq)
-{
-       spider_disable_irq(irq);
-}
-
-static void spider_end_irq(unsigned int irq)
-{
-       spider_enable_irq(irq);
-}
-
 static void spider_ack_irq(unsigned int irq)
 {
-       spider_disable_irq(irq);
-       iic_local_enable();
+       /* Should reset edge detection logic but we don't configure any edge interrupt
+        * at the moment.
+        */
 }
 
-static struct hw_interrupt_type spider_pic = {
+static struct irq_chip spider_pic = {
        .typename = " SPIDER   ",
-       .startup = spider_startup_irq,
-       .shutdown = spider_shutdown_irq,
-       .enable = spider_enable_irq,
-       .disable = spider_disable_irq,
+       .unmask = spider_unmask_irq,
+       .mask = spider_mask_irq,
        .ack = spider_ack_irq,
-       .end = spider_end_irq,
 };
 
-int spider_get_irq(int node)
+static int spider_get_irq(int node)
 {
        unsigned long cs;
        void __iomem *regs = spider_pics[node];
@@ -145,95 +130,89 @@ int spider_get_irq(int node)
                return cs;
 }
 
+static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
+                              struct pt_regs *regs)
+{
+       int node = (int)(long)desc->handler_data;
+       int cascade_irq;
+
+       cascade_irq = spider_get_irq(node);
+       generic_handle_irq(cascade_irq, regs);
+       desc->chip->eoi(irq);
+}
+
 /* hardcoded part to be compatible with older firmware */
 
-void spider_init_IRQ_hardcoded(void)
+static void __init spider_init_one(int node, unsigned long addr)
 {
-       int node;
-       long spiderpic;
-       long pics[] = { 0x24000008000, 0x34000008000 };
-       int n;
-
-       pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
-
-       for (node = 0; node < num_present_cpus()/2; node++) {
-               spiderpic = pics[node];
-               printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
-               spider_pics[node] = ioremap(spiderpic, 0x800);
-               for (n = 0; n < IIC_NUM_EXT; n++) {
-                       int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->chip = &spider_pic;
-               }
-
-               /* do not mask any interrupts because of level */
-               out_be32(spider_pics[node] + TIR_MSK, 0x0);
-
-               /* disable edge detection clear */
-               /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
-
-               /* enable interrupt packets to be output */
-               out_be32(spider_pics[node] + TIR_PIEN,
-                       in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
-
-               /* Enable the interrupt detection enable bit. Do this last! */
-               out_be32(spider_pics[node] + TIR_DEN,
-                       in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+       int n, irq;
+
+       spider_pics[node] = ioremap(addr, 0x800);
+       if (spider_pics[node] == NULL)
+               panic("spider_pic: can't map registers !");
+
+       printk(KERN_INFO "spider_pic: mapped for node %d, addr: 0x%lx mapped to %p\n",
+              node, addr, spider_pics[node]);
+
+       for (n = 0; n < IIC_NUM_EXT; n++) {
+               if (n == IIC_EXT_CASCADE)
+                       continue;
+               irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
+               set_irq_chip_and_handler(irq, &spider_pic, handle_level_irq);
+               get_irq_desc(irq)->status |= IRQ_LEVEL;
        }
+
+       /* do not mask any interrupts because of level */
+       out_be32(spider_pics[node] + TIR_MSK, 0x0);
+
+       /* disable edge detection clear */
+       /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
+
+       /* enable interrupt packets to be output */
+       out_be32(spider_pics[node] + TIR_PIEN,
+                in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
+
+       /* Hook up cascade */
+       irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
+       set_irq_data(irq, (void *)(long)node);
+       set_irq_chained_handler(irq, spider_irq_cascade);
+
+       /* Enable the interrupt detection enable bit. Do this last! */
+       out_be32(spider_pics[node] + TIR_DEN,
+                in_be32(spider_pics[node] + TIR_DEN) | 0x1);
 }
 
-void spider_init_IRQ(void)
+void __init spider_init_IRQ(void)
 {
-       long spider_reg;
+       unsigned long *spider_reg;
        struct device_node *dn;
        char *compatible;
-       int n, node = 0;
-
+       int node = 0;
+
+       /* XXX node numbers are totally bogus. We _hope_ we get the device nodes in the right
+        * order here but that's definitely not guaranteed, we need to get the node from the
+        * device tree instead. There is currently no proper property for it (but our whole
+        * device-tree is bogus anyway) so all we can do is pray or maybe test the address
+        * and deduce the node-id
+        */
        for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
                compatible = (char *)get_property(dn, "compatible", NULL);
 
                if (!compatible)
                        continue;
 
-               if (strstr(compatible, "CBEA,platform-spider-pic"))
-                       spider_reg = *(long *)get_property(dn,"reg", NULL);
-               else if (strstr(compatible, "sti,platform-spider-pic")) {
-                       spider_init_IRQ_hardcoded();
-                       return;
+               if (strstr(compatible, "CBEA,platform-spider-pic"))
+                       spider_reg = (unsigned long *)get_property(dn, "reg", NULL);
+               else if (strstr(compatible, "sti,platform-spider-pic") && (node < 2)) {
+                       static long hard_coded_pics[] = { 0x24000008000, 0x34000008000 };
+                       spider_reg = &hard_coded_pics[node];
                } else
                        continue;
 
-               if (!spider_reg)
-                       printk("interrupt controller does not have reg property !\n");
-
-               n = prom_n_addr_cells(dn);
-
-               if ( n != 2)
-                       printk("reg property with invalid number of elements \n");
-
-               spider_pics[node] = ioremap(spider_reg, 0x800);
-
-               printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
-                      spider_reg, n, spider_pics[node]);
-
-               for (n = 0; n < IIC_NUM_EXT; n++) {
-                       int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->chip = &spider_pic;
-               }
-
-               /* do not mask any interrupts because of level */
-               out_be32(spider_pics[node] + TIR_MSK, 0x0);
-
-               /* disable edge detection clear */
-               /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
-
-               /* enable interrupt packets to be output */
-               out_be32(spider_pics[node] + TIR_PIEN,
-                       in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
-
-               /* Enable the interrupt detection enable bit. Do this last! */
-               out_be32(spider_pics[node] + TIR_DEN,
-                       in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+               if (spider_reg == NULL)
+                       printk(KERN_ERR "spider_pic: No address for node %d\n", node);
 
+               spider_init_one(node, *spider_reg);
                node++;
        }
 }