MIPS: ath79: add PCI IRQ handling code for AR724X SoCs
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / mips / pci / pci-ar724x.c
index 07b7e30..04f433a 100644 (file)
@@ -8,19 +8,32 @@
  *  by the Free Software Foundation.
  */
 
+#include <linux/irq.h>
 #include <linux/pci.h>
 #include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
 #include <asm/mach-ath79/pci.h>
 
 #define AR724X_PCI_CFG_BASE    0x14000000
 #define AR724X_PCI_CFG_SIZE    0x1000
+#define AR724X_PCI_CTRL_BASE   (AR71XX_APB_BASE + 0x000f0000)
+#define AR724X_PCI_CTRL_SIZE   0x100
+
 #define AR724X_PCI_MEM_BASE    0x10000000
 #define AR724X_PCI_MEM_SIZE    0x08000000
 
+#define AR724X_PCI_REG_INT_STATUS      0x4c
+#define AR724X_PCI_REG_INT_MASK                0x50
+
+#define AR724X_PCI_INT_DEV0            BIT(14)
+
+#define AR724X_PCI_IRQ_COUNT           1
+
 #define AR7240_BAR0_WAR_VALUE  0xffff
 
 static DEFINE_SPINLOCK(ar724x_pci_lock);
 static void __iomem *ar724x_pci_devcfg_base;
+static void __iomem *ar724x_pci_ctrl_base;
 
 static u32 ar724x_pci_bar0_value;
 static bool ar724x_pci_bar0_is_cached;
@@ -164,14 +177,115 @@ static struct pci_controller ar724x_pci_controller = {
        .mem_resource   = &ar724x_mem_resource,
 };
 
-int __init ar724x_pcibios_init(void)
+static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       void __iomem *base;
+       u32 pending;
+
+       base = ar724x_pci_ctrl_base;
+
+       pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
+                 __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+
+       if (pending & AR724X_PCI_INT_DEV0)
+               generic_handle_irq(ATH79_PCI_IRQ(0));
+
+       else
+               spurious_interrupt();
+}
+
+static void ar724x_pci_irq_unmask(struct irq_data *d)
+{
+       void __iomem *base;
+       u32 t;
+
+       base = ar724x_pci_ctrl_base;
+
+       switch (d->irq) {
+       case ATH79_PCI_IRQ(0):
+               t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+               __raw_writel(t | AR724X_PCI_INT_DEV0,
+                            base + AR724X_PCI_REG_INT_MASK);
+               /* flush write */
+               __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+       }
+}
+
+static void ar724x_pci_irq_mask(struct irq_data *d)
+{
+       void __iomem *base;
+       u32 t;
+
+       base = ar724x_pci_ctrl_base;
+
+       switch (d->irq) {
+       case ATH79_PCI_IRQ(0):
+               t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+               __raw_writel(t & ~AR724X_PCI_INT_DEV0,
+                            base + AR724X_PCI_REG_INT_MASK);
+
+               /* flush write */
+               __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+
+               t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
+               __raw_writel(t | AR724X_PCI_INT_DEV0,
+                            base + AR724X_PCI_REG_INT_STATUS);
+
+               /* flush write */
+               __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
+       }
+}
+
+static struct irq_chip ar724x_pci_irq_chip = {
+       .name           = "AR724X PCI ",
+       .irq_mask       = ar724x_pci_irq_mask,
+       .irq_unmask     = ar724x_pci_irq_unmask,
+       .irq_mask_ack   = ar724x_pci_irq_mask,
+};
+
+static void __init ar724x_pci_irq_init(int irq)
+{
+       void __iomem *base;
+       int i;
+
+       base = ar724x_pci_ctrl_base;
+
+       __raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
+       __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
+
+       BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT);
+
+       for (i = ATH79_PCI_IRQ_BASE;
+            i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++)
+               irq_set_chip_and_handler(i, &ar724x_pci_irq_chip,
+                                        handle_level_irq);
+
+       irq_set_chained_handler(irq, ar724x_pci_irq_handler);
+}
+
+int __init ar724x_pcibios_init(int irq)
 {
+       int ret;
+
+       ret = -ENOMEM;
+
        ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE,
                                         AR724X_PCI_CFG_SIZE);
        if (ar724x_pci_devcfg_base == NULL)
-               return -ENOMEM;
+               goto err;
 
+       ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE,
+                                      AR724X_PCI_CTRL_SIZE);
+       if (ar724x_pci_ctrl_base == NULL)
+               goto err_unmap_devcfg;
+
+       ar724x_pci_irq_init(irq);
        register_pci_controller(&ar724x_pci_controller);
 
        return PCIBIOS_SUCCESSFUL;
+
+err_unmap_devcfg:
+       iounmap(ar724x_pci_devcfg_base);
+err:
+       return ret;
 }