Add dw msi controller functions for v3.65 hw. This adds dw_v3_65_msi_chip
and dw_v3_65_msi_domain_ops so that can be used on this version of the hw.
This required since MSI irq registers reside in the application space
for v3.65 hw. The functions are used by v3.65 dw pci core functions to
support implementation of PCI controllers based on this hw version.

While at it, move the ATU hw specific variable and msi irq to a separate
struct inside a union and add another struct inside the union to hold
dw v3.65 specific variables.

Signed-off-by: Murali Karicheri <[email protected]>

CC: Santosh Shilimkar <[email protected]>
CC: Russell King <[email protected]>
CC: Grant Likely <[email protected]>
CC: Rob Herring <[email protected]>
CC: Mohit Kumar <[email protected]>
CC: Jingoo Han <[email protected]>
CC: Bjorn Helgaas <[email protected]>
CC: Pratyush Anand <[email protected]>
CC: Richard Zhu <[email protected]>
CC: Kishon Vijay Abraham I <[email protected]>
CC: Marek Vasut <[email protected]>
CC: Arnd Bergmann <[email protected]>
CC: Pawel Moll <[email protected]>
CC: Mark Rutland <[email protected]>
CC: Ian Campbell <[email protected]>
CC: Kumar Gala <[email protected]>
CC: Randy Dunlap <[email protected]>
CC: Grant Likely <[email protected]> 

---
 drivers/pci/host/Kconfig            |    5 ++
 drivers/pci/host/Makefile           |    1 +
 drivers/pci/host/pci-dw-v3_65-msi.c |  149 +++++++++++++++++++++++++++++++++++
 drivers/pci/host/pci-dw-v3_65.h     |   20 +++++
 drivers/pci/host/pcie-designware.h  |   21 +++--
 5 files changed, 191 insertions(+), 5 deletions(-)
 create mode 100644 drivers/pci/host/pci-dw-v3_65-msi.c
 create mode 100644 drivers/pci/host/pci-dw-v3_65.h

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index a6f67ec..2fcd9f9 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -9,6 +9,11 @@ config PCI_MVEBU
 config PCIE_DW
        bool
 
+config PCI_DW_V3_65
+       bool "Designware PCIe h/w v3.65"
+       help
+          Say Y here if the DW h/w version is 3.65
+
 config PCI_EXYNOS
        bool "Samsung Exynos PCIe controller"
        depends on SOC_EXYNOS5440
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..28af710 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
+obj-$(CONFIG_PCI_DW_V3_65) += pci-dw-v3_65-msi.o
diff --git a/drivers/pci/host/pci-dw-v3_65-msi.c 
b/drivers/pci/host/pci-dw-v3_65-msi.c
new file mode 100644
index 0000000..a26ffdd
--- /dev/null
+++ b/drivers/pci/host/pci-dw-v3_65-msi.c
@@ -0,0 +1,149 @@
+/*
+ * Designware(dw) MSI controller version 3.65
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *             http://www.ti.com
+ *
+ * Author: Murali Karicheri <[email protected]>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of_irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+
+#include "pcie-designware.h"
+
+#define MSI_IRQ                                0x054
+#define MSI0_IRQ_STATUS                        0x104
+#define MSI0_IRQ_ENABLE_SET            0x108
+#define MSI0_IRQ_ENABLE_CLR            0x10c
+#define IRQ_STATUS                     0x184
+#define IRQ_EOI                         0x050
+#define MSI_IRQ_OFFSET                 4
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+       return sys->private_data;
+}
+
+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
+                                       u32 *bit_pos)
+{
+       *reg_offset = offset % 8;
+       *bit_pos = offset >> 3;
+}
+
+inline u32 dw_v3_65_get_msi_data(struct pcie_port *pp)
+{
+       return pp->app.start + MSI_IRQ;
+}
+
+void dw_v3_65_handle_msi_irq(struct pcie_port *pp, int offset)
+{
+       u32 pending, vector;
+       int src, virq;
+
+       pending = readl(pp->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
+       /*
+        * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+        * shows 1, 9, 17, 25 and so forth
+        */
+       for (src = 0; src < 4; src++) {
+               if (BIT(src) & pending) {
+                       vector = offset + (src << 3);
+                       virq = irq_linear_revmap(pp->irq_domain, vector);
+                       dev_dbg(pp->dev,
+                               "irq: bit %d, vector %d, virq %d\n",
+                                src, vector, virq);
+                       generic_handle_irq(virq);
+               }
+       }
+}
+
+static void dw_v3_65_msi_irq_ack(struct irq_data *d)
+{
+       u32 offset, reg_offset, bit_pos;
+       unsigned int irq = d->irq;
+       struct msi_desc *msi;
+       struct pcie_port *pp;
+
+       msi = irq_get_msi_desc(irq);
+       pp = sys_to_pcie(msi->dev->bus->sysdata);
+       offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+       update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+       writel(BIT(bit_pos),
+               pp->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
+       writel(reg_offset + MSI_IRQ_OFFSET, pp->va_app_base + IRQ_EOI);
+}
+
+static void dw_v3_65_msi_irq_mask(struct irq_data *d)
+{
+       u32 offset, reg_offset, bit_pos;
+       unsigned int irq = d->irq;
+       struct msi_desc *msi;
+       struct pcie_port *pp;
+
+       msi = irq_get_msi_desc(irq);
+       pp = sys_to_pcie(msi->dev->bus->sysdata);
+       offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+       update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+       /* mask the end point if PVM implemented */
+       if (IS_ENABLED(CONFIG_PCI_MSI)) {
+               if (msi->msi_attrib.maskbit)
+                       mask_msi_irq(d);
+       }
+
+       writel(BIT(bit_pos),
+               pp->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
+}
+
+static void dw_v3_65_msi_irq_unmask(struct irq_data *d)
+{
+       u32 offset, reg_offset, bit_pos;
+       unsigned int irq = d->irq;
+       struct msi_desc *msi;
+       struct pcie_port *pp;
+
+       msi = irq_get_msi_desc(irq);
+       pp = sys_to_pcie(msi->dev->bus->sysdata);
+       offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+       update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+       /* mask the end point if PVM implemented */
+       if (IS_ENABLED(CONFIG_PCI_MSI)) {
+               if (msi->msi_attrib.maskbit)
+                       unmask_msi_irq(d);
+       }
+
+       writel(BIT(bit_pos),
+               pp->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
+}
+
+static struct irq_chip dw_v3_65_msi_chip = {
+       .name = "PCI-DW-MSI-OLD",
+       .irq_ack = dw_v3_65_msi_irq_ack,
+       .irq_mask = dw_v3_65_msi_irq_mask,
+       .irq_unmask = dw_v3_65_msi_irq_unmask,
+};
+
+static int dw_v3_65_msi_map(struct irq_domain *domain, unsigned int irq,
+                       irq_hw_number_t hwirq)
+{
+       irq_set_chip_and_handler(irq, &dw_v3_65_msi_chip, handle_level_irq);
+       irq_set_chip_data(irq, domain->host_data);
+       set_irq_flags(irq, IRQF_VALID);
+
+       return 0;
+}
+
+const struct irq_domain_ops dw_v3_65_msi_domain_ops = {
+       .map = dw_v3_65_msi_map,
+};
diff --git a/drivers/pci/host/pci-dw-v3_65.h b/drivers/pci/host/pci-dw-v3_65.h
new file mode 100644
index 0000000..689256a
--- /dev/null
+++ b/drivers/pci/host/pci-dw-v3_65.h
@@ -0,0 +1,20 @@
+/*
+ * Designware(dw) v3.65 controller common includes
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *             http://www.ti.com
+ *
+ * Author: Murali Karicheri <[email protected]>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define MAX_LEGACY_IRQS                4
+
+/* v3.65 specific MSI controller APIs/definitions */
+extern const struct irq_domain_ops dw_v3_65_msi_domain_ops;
+void dw_v3_65_handle_msi_irq(struct pcie_port *pp, int offset);
+u32 dw_v3_65_get_msi_data(struct pcie_port *pp);
diff --git a/drivers/pci/host/pcie-designware.h 
b/drivers/pci/host/pcie-designware.h
index 3a6a6eb..05bb590 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -35,16 +35,27 @@ struct pcie_port {
        struct device           *dev;
        u8                      root_bus_nr;
        void __iomem            *dbi_base;
-       u64                     cfg0_base;
-       void __iomem            *va_cfg0_base;
-       u64                     cfg1_base;
-       void __iomem            *va_cfg1_base;
        /*
         * v3.65 DW hw implements application register space for
         * MSI and has no ATU view port
         */
 #define DW_V3_65               BIT(0)
        u32                     version;
+       union {
+               /* New DW hw specific */
+               struct {
+                       u64                     cfg0_base;
+                       void __iomem            *va_cfg0_base;
+                       u64                     cfg1_base;
+                       void __iomem            *va_cfg1_base;
+                       int                     msi_irq;
+               };
+               /* v3.65 DW hw specific */
+               struct  {
+                       void __iomem            *va_app_base;
+                       struct resource         app;
+               };
+       };
        u64                     io_base;
        u64                     mem_base;
        spinlock_t              conf_lock;
@@ -55,7 +66,7 @@ struct pcie_port {
        int                     irq;
        u32                     lanes;
        struct pcie_host_ops    *ops;
-       int                     msi_irq;
+       /* msi irq domain */
        struct irq_domain       *irq_domain;
        unsigned long           msi_data;
        DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to