summaryrefslogtreecommitdiffstats
path: root/drivers/pci/host/pci-exynos.c
diff options
context:
space:
mode:
authorJingoo Han <jg1.han@samsung.com>2013-09-06 08:54:59 +0200
committerBjorn Helgaas <bhelgaas@google.com>2013-09-26 00:31:27 +0200
commitf342d940ee0e3a2b5197fd4fbade1cb6bbc960b7 (patch)
tree04152ee8ca07e664560a370bec2c535fb20ccdb0 /drivers/pci/host/pci-exynos.c
parentMAINTAINERS: Add Jingoo Han as Samsung Exynos PCIe driver maintainer (diff)
downloadlinux-f342d940ee0e3a2b5197fd4fbade1cb6bbc960b7.tar.xz
linux-f342d940ee0e3a2b5197fd4fbade1cb6bbc960b7.zip
PCI: exynos: Add support for MSI
This patch adds support for Message Signaled Interrupt in the Exynos PCIe driver using Synopsys designware PCIe core IP. Signed-off-by: Siva Reddy Kallam <siva.kallam@samsung.com> Signed-off-by: Srikanth T Shivanand <ts.srikanth@samsung.com> Signed-off-by: Jingoo Han <jg1.han@samsung.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: Pratyush Anand <pratyush.anand@st.com> Cc: Mohit KUMAR <Mohit.KUMAR@st.com>
Diffstat (limited to 'drivers/pci/host/pci-exynos.c')
-rw-r--r--drivers/pci/host/pci-exynos.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index 94e096bb2d0a..f062acaf052a 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -48,6 +48,7 @@ struct exynos_pcie {
#define PCIE_IRQ_SPECIAL 0x008
#define PCIE_IRQ_EN_PULSE 0x00c
#define PCIE_IRQ_EN_LEVEL 0x010
+#define IRQ_MSI_ENABLE (0x1 << 2)
#define PCIE_IRQ_EN_SPECIAL 0x014
#define PCIE_PWR_RESET 0x018
#define PCIE_CORE_RESET 0x01c
@@ -342,9 +343,36 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
+static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg)
+{
+ struct pcie_port *pp = arg;
+
+ dw_handle_msi_irq(pp);
+
+ return IRQ_HANDLED;
+}
+
+static void exynos_pcie_msi_init(struct pcie_port *pp)
+{
+ u32 val;
+ struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+ dw_pcie_msi_init(pp);
+
+ /* enable MSI interrupt */
+ val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_EN_LEVEL);
+ val |= IRQ_MSI_ENABLE;
+ exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL);
+ return;
+}
+
static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
{
exynos_pcie_enable_irq_pulse(pp);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ exynos_pcie_msi_init(pp);
+
return;
}
@@ -430,6 +458,22 @@ static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
return ret;
}
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ pp->msi_irq = platform_get_irq(pdev, 0);
+ if (!pp->msi_irq) {
+ dev_err(&pdev->dev, "failed to get msi irq\n");
+ return -ENODEV;
+ }
+
+ ret = devm_request_irq(&pdev->dev, pp->msi_irq,
+ exynos_pcie_msi_irq_handler,
+ IRQF_SHARED, "exynos-pcie", pp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request msi irq\n");
+ return ret;
+ }
+ }
+
pp->root_bus_nr = -1;
pp->ops = &exynos_pcie_host_ops;