diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/spider-pic.c')
-rw-r--r-- | arch/powerpc/platforms/cell/spider-pic.c | 173 |
1 files changed, 76 insertions, 97 deletions
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 7c3a0b6d34f..98425acb6cd 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -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++; } } |