[PATCH] pci: imx: enable pcie msi support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Richard Zhu <r65037@xxxxxxxxxxxxx>

eanble pcie msi support on imx6 platforms
* add check_device api in the msi chip.
* add the quirks into pcie_port struct for the deviation
from standard routines.

Signed-off-by: Richard Zhu <richard.zhuhongxing@xxxxxxxxx>
---
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi |    6 +++
 arch/arm/mach-imx/Kconfig              |    1 +
 drivers/pci/host/pci-imx6.c            |   34 +++++++++++++++++-
 drivers/pci/host/pcie-designware.c     |   60 +++++++++++++++++++++++---------
 drivers/pci/host/pcie-designware.h     |    5 +++
 5 files changed, 88 insertions(+), 18 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index e75e11b..b821f87 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -212,6 +212,12 @@
 	};
 };
 
+&pcie {
+	power-on-gpio = <&gpio3 19 0>;
+	reset-gpio = <&gpio7 12 0>;
+	status = "okay";
+};
+
 &pwm1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm0_1>;
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 7a6e6f7..3083c5b 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -796,6 +796,7 @@ config SOC_IMX6Q
 	select MFD_SYSCON
 	select MIGHT_HAVE_PCI
 	select PCI_DOMAINS if PCI
+	select ARCH_SUPPORTS_MSI
 	select PINCTRL
 	select PINCTRL_IMX6Q
 	select PL310_ERRATA_588369 if CACHE_PL310
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index bd70af8..fbd75bf 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@@ -299,6 +300,15 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
 			IMX6Q_GPR8_TX_SWING_LOW, 127 << 25);
 }
 
+static irqreturn_t imx_pcie_msi_irq_handler(int irq, void *arg)
+{
+	struct pcie_port *pp = arg;
+
+	dw_handle_msi_irq(pp);
+
+	return IRQ_HANDLED;
+}
+
 static void imx6_pcie_host_init(struct pcie_port *pp)
 {
 	int count = 0;
@@ -324,10 +334,16 @@ static void imx6_pcie_host_init(struct pcie_port *pp)
 				"DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
 				readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
 				readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
-			break;
+			return;
 		}
 	}
 
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		pp->quirks |= DW_PCIE_QUIRK_NO_MSI_VEC;
+		pp->quirks |= DW_PCIE_QUIRK_MSI_SELF_EN;
+		dw_pcie_msi_init(pp);
+	}
+
 	return;
 }
 
@@ -393,6 +409,22 @@ static int imx6_add_pcie_port(struct pcie_port *pp,
 		return -ENODEV;
 	}
 
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		pp->msi_irq = pp->irq - 3;
+		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,
+					imx_pcie_msi_irq_handler,
+					IRQF_SHARED, "imx6q-pcie", pp);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to request msi irq\n");
+			return ret;
+		}
+	}
+
 	pp->root_bus_nr = -1;
 	pp->ops = &imx6_pcie_host_ops;
 
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index e33b68b..96d2b78 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -308,23 +308,28 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
 		return -EINVAL;
 	}
 
-	pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
-				&msg_ctr);
-	msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
-	if (msgvec == 0)
-		msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
-	if (msgvec > 5)
-		msgvec = 0;
-
-	irq = assign_irq((1 << msgvec), desc, &pos);
-	if (irq < 0)
-		return irq;
-
-	msg_ctr &= ~PCI_MSI_FLAGS_QSIZE;
-	msg_ctr |= msgvec << 4;
-	pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
-				msg_ctr);
-	desc->msi_attrib.multiple = msgvec;
+	if (pp->quirks & DW_PCIE_QUIRK_NO_MSI_VEC) {
+		irq = assign_irq(1, desc, &pos);
+		set_irq_flags(irq, IRQF_VALID);
+	} else {
+		pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
+					&msg_ctr);
+		msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
+		if (msgvec == 0)
+			msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
+		if (msgvec > 5)
+			msgvec = 0;
+
+		irq = assign_irq((1 << msgvec), desc, &pos);
+		if (irq < 0)
+			return irq;
+
+		msg_ctr &= ~PCI_MSI_FLAGS_QSIZE;
+		msg_ctr |= msgvec << 4;
+		pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
+					msg_ctr);
+		desc->msi_attrib.multiple = msgvec;
+	}
 
 	msg.address_lo = virt_to_phys((void *)pp->msi_data);
 	msg.address_hi = 0x0;
@@ -339,9 +344,30 @@ static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
 	clear_irq(irq);
 }
 
+static int dw_msi_check_device(struct msi_chip *chip, struct pci_dev *pdev,
+		int nvec, int type)
+{
+	struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
+	u32 val;
+
+	if (pp->quirks & DW_PCIE_QUIRK_MSI_SELF_EN) {
+		if ((type == PCI_CAP_ID_MSI) || (type == PCI_CAP_ID_MSIX)) {
+			/* Set MSI enable of RC here */
+			val = readl(pp->dbi_base + 0x50);
+			if ((val & (PCI_MSI_FLAGS_ENABLE << 16)) == 0) {
+				val |= PCI_MSI_FLAGS_ENABLE << 16;
+				writel(val, pp->dbi_base + 0x50);
+			}
+		}
+	}
+
+	return 0;
+}
+
 static struct msi_chip dw_pcie_msi_chip = {
 	.setup_irq = dw_msi_setup_irq,
 	.teardown_irq = dw_msi_teardown_irq,
+	.check_device = dw_msi_check_device,
 };
 
 int dw_pcie_link_up(struct pcie_port *pp)
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index c15379b..79111fe 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -49,6 +49,11 @@ struct pcie_port {
 	int			irq;
 	u32			lanes;
 	struct pcie_host_ops	*ops;
+	u32			quirks;		/* Deviations from spec. */
+/* Controller doesn't support MSI VEC */
+#define DW_PCIE_QUIRK_NO_MSI_VEC	(1<<0)
+/* MSI EN of Controller should be configured when MSI is enabled */
+#define DW_PCIE_QUIRK_MSI_SELF_EN	(1<<1)
 	int			msi_irq;
 	struct irq_domain	*irq_domain;
 	unsigned long		msi_data;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux