[SPARC64]: SUN4U PCI-E controller support.
[pandora-kernel.git] / arch / sparc64 / kernel / prom.c
index 5e1fcd0..6625ac8 100644 (file)
@@ -386,11 +386,9 @@ static unsigned int psycho_irq_build(struct device_node *dp,
 
        /* Now build the IRQ bucket. */
        imap = controller_regs + imap_off;
-       imap += 4;
 
        iclr_off = psycho_iclr_offset(ino);
        iclr = controller_regs + iclr_off;
-       iclr += 4;
 
        if ((ino & 0x20) == 0)
                inofixup = ino & 0x03;
@@ -613,11 +611,9 @@ static unsigned int sabre_irq_build(struct device_node *dp,
 
        /* Now build the IRQ bucket. */
        imap = controller_regs + imap_off;
-       imap += 4;
 
        iclr_off = sabre_iclr_offset(ino);
        iclr = controller_regs + iclr_off;
-       iclr += 4;
 
        if ((ino & 0x20) == 0)
                inofixup = ino & 0x03;
@@ -679,13 +675,14 @@ static unsigned long schizo_iclr_offset(unsigned long ino)
 static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
                                        unsigned int ino)
 {
-       return pbm_regs + schizo_iclr_offset(ino) + 4;
+
+       return pbm_regs + schizo_iclr_offset(ino);
 }
 
 static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
                                        unsigned int ino)
 {
-       return pbm_regs + schizo_imap_offset(ino) + 4;
+       return pbm_regs + schizo_imap_offset(ino);
 }
 
 #define schizo_read(__reg) \
@@ -848,6 +845,85 @@ static void pci_sun4v_irq_trans_init(struct device_node *dp)
        dp->irq_trans->data = (void *) (unsigned long)
                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 }
+
+struct fire_irq_data {
+       unsigned long pbm_regs;
+       u32 portid;
+};
+
+#define FIRE_IMAP_BASE 0x001000
+#define FIRE_ICLR_BASE 0x001400
+
+static unsigned long fire_imap_offset(unsigned long ino)
+{
+       return FIRE_IMAP_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_iclr_offset(unsigned long ino)
+{
+       return FIRE_ICLR_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
+                                           unsigned int ino)
+{
+       return pbm_regs + fire_iclr_offset(ino);
+}
+
+static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
+                                           unsigned int ino)
+{
+       return pbm_regs + fire_imap_offset(ino);
+}
+
+static unsigned int fire_irq_build(struct device_node *dp,
+                                        unsigned int ino,
+                                        void *_data)
+{
+       struct fire_irq_data *irq_data = _data;
+       unsigned long pbm_regs = irq_data->pbm_regs;
+       unsigned long imap, iclr;
+       unsigned long int_ctrlr;
+
+       ino &= 0x3f;
+
+       /* Now build the IRQ bucket. */
+       imap = fire_ino_to_imap(pbm_regs, ino);
+       iclr = fire_ino_to_iclr(pbm_regs, ino);
+
+       /* Set the interrupt controller number.  */
+       int_ctrlr = 1 << 6;
+       upa_writeq(int_ctrlr, imap);
+
+       /* The interrupt map registers do not have an INO field
+        * like other chips do.  They return zero in the INO
+        * field, and the interrupt controller number is controlled
+        * in bits 6 thru 9.  So in order for build_irq() to get
+        * the INO right we pass it in as part of the fixup
+        * which will get added to the map register zero value
+        * read by build_irq().
+        */
+       ino |= (irq_data->portid << 6);
+       ino -= int_ctrlr;
+       return build_irq(ino, iclr, imap);
+}
+
+static void fire_irq_trans_init(struct device_node *dp)
+{
+       const struct linux_prom64_registers *regs;
+       struct fire_irq_data *irq_data;
+
+       dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+       dp->irq_trans->irq_build = fire_irq_build;
+
+       irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
+
+       regs = of_get_property(dp, "reg", NULL);
+       dp->irq_trans->data = irq_data;
+
+       irq_data->pbm_regs = regs[0].phys_addr;
+       irq_data->portid = of_getintprop_default(dp, "portid", 0);
+}
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_SBUS
@@ -1069,6 +1145,7 @@ static struct irq_trans pci_irq_trans_table[] = {
        { "SUNW,tomatillo", tomatillo_irq_trans_init },
        { "pci108e,a801", tomatillo_irq_trans_init },
        { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
+       { "pciex108e,80f0", fire_irq_trans_init },
 };
 #endif