diff mbox

[v1,4/4] PCI: imx6: add imx6sx pcie support

Message ID 1411382705-15301-5-git-send-email-r65037@freescale.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Richard Zhu Sept. 22, 2014, 10:45 a.m. UTC
- imx6sx pcie has its own standalone pcie power supply.
In order to turn on the imx6sx pcie power during
initialization. Add the pcie regulator and the gpc regmap
into the imx6sx pcie structure.
- imx6sx pcie has the new added reset mechanism, add the
reset operations into the initialization.
- Register one PM call-back, enter/exit L2 state of the ASPM
during system suspend/resume.

Signed-off-by: Richard Zhu <r65037@freescale.com>
---
 drivers/pci/host/pci-imx6.c | 166 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 148 insertions(+), 18 deletions(-)

Comments

Fabio Estevam Sept. 22, 2014, 2:27 p.m. UTC | #1
Hi Richard,

On Mon, Sep 22, 2014 at 7:45 AM, Richard Zhu <r65037@freescale.com> wrote:

> +#ifdef CONFIG_PM_SLEEP
> +static int pci_imx_suspend(void)
> +{
> +       int rc = 0;
> +
> +       if (is_imx6sx_pcie(imx6_pcie)) {
> +               /* PM_TURN_OFF */
> +               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
> +                               BIT(16), 1 << 16);
> +               udelay(10);
> +               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
> +                               BIT(16), 0 << 16);
> +       }
> +
> +       return rc;

You could get rid of this 'rc' variable and just return 0.

> +}
> +
> +static void pci_imx_resume(void)
> +{
> +       struct pcie_port *pp = &imx6_pcie->pp;
> +
> +       if (is_imx6sx_pcie(imx6_pcie)) {
> +               /* reset iMX6SX PCIe */
> +               regmap_update_bits(imx6_pcie->iomuxc_gpr,
> +                               IOMUXC_GPR5, BIT(18), 1 << 18);
> +
> +               regmap_update_bits(imx6_pcie->iomuxc_gpr,
> +                               IOMUXC_GPR5, BIT(18), 0 << 18);
> +
> +               /*
> +                * controller maybe turn off, re-configure again
> +                * Set the CLASS_REV of RC CFG header to
> +                * PCI_CLASS_BRIDGE_PCI
> +                */
> +               writel(readl(pp->dbi_base + PCI_CLASS_REVISION)
> +                       | (PCI_CLASS_BRIDGE_PCI << 16),
> +                       pp->dbi_base + PCI_CLASS_REVISION);
> +
> +               dw_pcie_setup_rc(pp);
> +       }
> +}

Not related to this patch, but on mx6q/dl  we still get kernel hang
after doing suspend/resume when a PCI card is inserted.

Is this fixed on mx6solox?

Any idea as to how to fix it for mx6q?
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Richard Zhu Sept. 23, 2014, 3:09 a.m. UTC | #2
Hi Fabio:
Thanks for your comments.


> -----Original Message-----

> From: Fabio Estevam [mailto:festevam@gmail.com]

> Sent: Monday, September 22, 2014 10:27 PM

> To: Zhu Richard-R65037

> Cc: linux-pci-owner@vger.kernel.org; linux-pci@vger.kernel.org; Guo Shawn-

> R65073; Lucas Stach

> Subject: Re: [PATCH v1 4/4] PCI: imx6: add imx6sx pcie support

> 

> Hi Richard,

> 

> On Mon, Sep 22, 2014 at 7:45 AM, Richard Zhu <r65037@freescale.com> wrote:

> 

> > +#ifdef CONFIG_PM_SLEEP

> > +static int pci_imx_suspend(void)

> > +{

> > +       int rc = 0;

> > +

> > +       if (is_imx6sx_pcie(imx6_pcie)) {

> > +               /* PM_TURN_OFF */

> > +               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,

> > +                               BIT(16), 1 << 16);

> > +               udelay(10);

> > +               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,

> > +                               BIT(16), 0 << 16);

> > +       }

> > +

> > +       return rc;

> 

> You could get rid of this 'rc' variable and just return 0.

> 

[Richard] OK. Accepted.
> > +}

> > +

> > +static void pci_imx_resume(void)

> > +{

> > +       struct pcie_port *pp = &imx6_pcie->pp;

> > +

> > +       if (is_imx6sx_pcie(imx6_pcie)) {

> > +               /* reset iMX6SX PCIe */

> > +               regmap_update_bits(imx6_pcie->iomuxc_gpr,

> > +                               IOMUXC_GPR5, BIT(18), 1 << 18);

> > +

> > +               regmap_update_bits(imx6_pcie->iomuxc_gpr,

> > +                               IOMUXC_GPR5, BIT(18), 0 << 18);

> > +

> > +               /*

> > +                * controller maybe turn off, re-configure again

> > +                * Set the CLASS_REV of RC CFG header to

> > +                * PCI_CLASS_BRIDGE_PCI

> > +                */

> > +               writel(readl(pp->dbi_base + PCI_CLASS_REVISION)

> > +                       | (PCI_CLASS_BRIDGE_PCI << 16),

> > +                       pp->dbi_base + PCI_CLASS_REVISION);

> > +

> > +               dw_pcie_setup_rc(pp);

> > +       }

> > +}

> 

> Not related to this patch, but on mx6q/dl  we still get kernel hang after

> doing suspend/resume when a PCI card is inserted.

> 

> Is this fixed on mx6solox?

[Richard] this is a part of the fix on imx6solox.
As I know that, there is one similar fix on the next mx6q to.
> 

> Any idea as to how to fix it for mx6q?


Best Regards
Richard Zhu
Fabio Estevam Sept. 23, 2014, 10:18 p.m. UTC | #3
On Tue, Sep 23, 2014 at 12:09 AM, Hong-Xing.Zhu@freescale.com
<Hong-Xing.Zhu@freescale.com> wrote:

> As I know that, there is one similar fix on the next mx6q to.

What about the existing mx6q silicon version? How can we fix the hang?
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Richard Zhu Sept. 24, 2014, 2:55 a.m. UTC | #4
DQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IEZhYmlvIEVzdGV2YW0gW21h
aWx0bzpmZXN0ZXZhbUBnbWFpbC5jb21dDQo+IFNlbnQ6IFdlZG5lc2RheSwgU2VwdGVtYmVyIDI0
LCAyMDE0IDY6MTkgQU0NCj4gVG86IFpodSBSaWNoYXJkLVI2NTAzNw0KPiBDYzogbGludXgtcGNp
LW93bmVyQHZnZXIua2VybmVsLm9yZzsgbGludXgtcGNpQHZnZXIua2VybmVsLm9yZzsgR3VvIFNo
YXduLQ0KPiBSNjUwNzM7IEx1Y2FzIFN0YWNoDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggdjEgNC80
XSBQQ0k6IGlteDY6IGFkZCBpbXg2c3ggcGNpZSBzdXBwb3J0DQo+IA0KPiBPbiBUdWUsIFNlcCAy
MywgMjAxNCBhdCAxMjowOSBBTSwgSG9uZy1YaW5nLlpodUBmcmVlc2NhbGUuY29tIDxIb25nLQ0K
PiBYaW5nLlpodUBmcmVlc2NhbGUuY29tPiB3cm90ZToNCj4gDQo+ID4gQXMgSSBrbm93IHRoYXQs
IHRoZXJlIGlzIG9uZSBzaW1pbGFyIGZpeCBvbiB0aGUgbmV4dCBteDZxIHRvLg0KPiANCj4gV2hh
dCBhYm91dCB0aGUgZXhpc3RpbmcgbXg2cSBzaWxpY29uIHZlcnNpb24/IEhvdyBjYW4gd2UgZml4
IHRoZSBoYW5nPw0KW1JpY2hhcmRdIFRoZXJlIGlzIGFscmVhZHkgb25lIFNXIHdvcmthcm91bmQo
dG9nZ2xlIHRoZSBURVNUX1BEIGJpdCBpbiBhcmNoL2FybS9tYWNoLWlteC9wbS5jKSBmb3IgdGhp
cyBpc3N1ZS4NCkl0IGNhbiB3b3JrYXJvdW5kIHRoaXMgaXNzdWUsIGFsdGhvdWdoIHdlIGRvbid0
IGdldCBndWFyYW50ZWUgZnJvbSBkZXNpZ24gdGVhbS4NCg0KQmVzdCBSZWdhcmRzDQpSaWNoYXJk
IFpodQ0K
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Fabio Estevam Sept. 24, 2014, 9:12 p.m. UTC | #5
On Tue, Sep 23, 2014 at 11:55 PM, Hong-Xing.Zhu@freescale.com
<Hong-Xing.Zhu@freescale.com> wrote:

>> What about the existing mx6q silicon version? How can we fix the hang?
> [Richard] There is already one SW workaround(toggle the TEST_PD bit in arch/arm/mach-imx/pm.c) for this issue.
> It can workaround this issue, although we don't get guarantee from design team.

This workaround is available in the FSL kernel. However, I am
interested in a solution for the mainline kernel.
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Richard Zhu Sept. 25, 2014, 1:23 a.m. UTC | #6
> -----Original Message-----

> From: Fabio Estevam [mailto:festevam@gmail.com]

> Sent: Thursday, September 25, 2014 5:13 AM

> To: Zhu Richard-R65037

> Cc: linux-pci-owner@vger.kernel.org; linux-pci@vger.kernel.org; Guo Shawn-

> R65073; Lucas Stach

> Subject: Re: [PATCH v1 4/4] PCI: imx6: add imx6sx pcie support

> 

> On Tue, Sep 23, 2014 at 11:55 PM, Hong-Xing.Zhu@freescale.com <Hong-

> Xing.Zhu@freescale.com> wrote:

> 

> >> What about the existing mx6q silicon version? How can we fix the hang?

> > [Richard] There is already one SW workaround(toggle the TEST_PD bit in

> arch/arm/mach-imx/pm.c) for this issue.

> > It can workaround this issue, although we don't get guarantee from design

> team.

> 

> This workaround is available in the FSL kernel. However, I am interested in a

> solution for the mainline kernel.

[Richard] IMHO, I don't know either.
The SW workaround used in the FSL kernel can works, but it still can't get guarantee
That it can fix this problem for sure from design team yet.

Best Regards
Richard Zhu
diff mbox

Patch

diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index bc4222b..070f43a 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -18,12 +18,16 @@ 
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 #include <linux/resource.h>
 #include <linux/signal.h>
+#include <linux/syscore_ops.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
 
@@ -31,15 +35,30 @@ 
 
 #define to_imx6_pcie(x)	container_of(x, struct imx6_pcie, pp)
 
+/* The pcie who have standalone power domain */
+#define PCIE_PHY_HAS_PWR_DOMAIN		BIT(0)
+
+struct imx_pcie_data {
+	unsigned int flags;
+};
+
+static const struct imx_pcie_data imx6sx_pcie_data = {
+	.flags = PCIE_PHY_HAS_PWR_DOMAIN,
+};
+
 struct imx6_pcie {
 	int			reset_gpio;
+	const struct		imx_pcie_data *data;
 	struct clk		*pcie_bus;
 	struct clk		*pcie_phy;
 	struct clk		*pcie;
 	struct pcie_port	pp;
 	struct regmap		*iomuxc_gpr;
+	struct regmap		*gpc_ips_reg;
+	struct regulator	*pcie_regulator;
 	void __iomem		*mem_base;
 };
+static struct imx6_pcie *imx6_pcie;
 
 /* PCIe Root Complex registers (memory-mapped) */
 #define PCIE_RC_LCR				0x7c
@@ -77,6 +96,11 @@  struct imx6_pcie {
 #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
 #define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
 
+static inline bool is_imx6sx_pcie(struct imx6_pcie *imx6_pcie)
+{
+	return imx6_pcie->data == &imx6sx_pcie_data;
+}
+
 static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
 {
 	u32 val;
@@ -275,11 +299,17 @@  static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
 		goto err_pcie;
 	}
 
-	/* power up core phy and enable ref clock */
-	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
-			IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
-	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
-			IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+				IMX6SX_GPR12_PCIE_TEST_PD,
+				IMX6SX_GPR12_PCIE_TEST_PD_CLR);
+	} else {
+		/* power up core phy and enable ref clock */
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+				IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+				IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+	}
 
 	/* allow the clocks to stabilize */
 	usleep_range(200, 500);
@@ -290,6 +320,18 @@  static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
 		msleep(100);
 		gpio_set_value(imx6_pcie->reset_gpio, 1);
 	}
+
+	/*
+	 * iMX6SX PCIe has the stand-alone power domain.
+	 * refer to the initialization for iMX6SX PCIe,
+	 * release the PCIe PHY reset here,
+	 * before LTSSM enable is set.
+	 */
+	if (is_imx6sx_pcie(imx6_pcie))
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+				IMX6SX_GPR5_PCIE_BTNRST,
+				IMX6SX_GPR5_PCIE_BTNRST_CLR);
+
 	return 0;
 
 err_pcie:
@@ -304,15 +346,38 @@  err_pcie_phy:
 static void imx6_pcie_init_phy(struct pcie_port *pp)
 {
 	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+	int ret;
+
+	/*
+	 * iMX6SX PCIe has the stand-alone power domain
+	 * add the initialization here for iMX6SX PCIe.
+	 */
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		/* Force PCIe PHY reset */
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+				IMX6SX_GPR5_PCIE_BTNRST,
+				IMX6SX_GPR5_PCIE_BTNRST);
+
+		regmap_update_bits(imx6_pcie->gpc_ips_reg, 0, 1 << 7, 1 << 7);
+		/* Power up PCIe PHY, ANATOP_REG_CORE offset 0x140, bit13-9 */
+		regulator_set_voltage(imx6_pcie->pcie_regulator,
+				1100000, 1100000);
+		ret = regulator_enable(imx6_pcie->pcie_regulator);
+		if (ret)
+			dev_info(pp->dev, "failed to enable pcie regulator.\n");
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+				IMX6SX_GPR12_RX_EQ_MASK, IMX6SX_GPR12_RX_EQ_2);
+	}
 
 	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
-			IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
+			IMX6Q_GPR12_PCIE_CTL_2,
+			IMX6Q_GPR12_PCIE_CTL_2_CLR);
 
 	/* configure constant input signal to the pcie ctrl and phy */
 	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
 			IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
 	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
-			IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
+			IMX6Q_GPR12_LOS_LEVEL, IMX6Q_GPR12_LOS_LEVEL_9);
 
 	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
 			IMX6Q_GPR8_TX_DEEMPH_GEN1, 0 << 0);
@@ -370,7 +435,8 @@  static int imx6_pcie_start_link(struct pcie_port *pp)
 
 	/* Start LTSSM. */
 	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
-			IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+			IMX6Q_GPR12_PCIE_CTL_2,
+			IMX6Q_GPR12_PCIE_CTL_2);
 
 	ret = imx6_pcie_wait_for_link(pp);
 	if (ret)
@@ -546,10 +612,66 @@  static int __init imx6_add_pcie_port(struct pcie_port *pp,
 	return 0;
 }
 
+static const struct of_device_id imx6_pcie_of_match[] = {
+	{ .compatible = "fsl,imx6q-pcie", },
+	{ .compatible = "fsl,imx6sx-pcie", .data = &imx6sx_pcie_data},
+	{},
+};
+MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
+
+#ifdef CONFIG_PM_SLEEP
+static int pci_imx_suspend(void)
+{
+	int rc = 0;
+
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		/* PM_TURN_OFF */
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+				BIT(16), 1 << 16);
+		udelay(10);
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+				BIT(16), 0 << 16);
+	}
+
+	return rc;
+}
+
+static void pci_imx_resume(void)
+{
+	struct pcie_port *pp = &imx6_pcie->pp;
+
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		/* reset iMX6SX PCIe */
+		regmap_update_bits(imx6_pcie->iomuxc_gpr,
+				IOMUXC_GPR5, BIT(18), 1 << 18);
+
+		regmap_update_bits(imx6_pcie->iomuxc_gpr,
+				IOMUXC_GPR5, BIT(18), 0 << 18);
+
+		/*
+		 * controller maybe turn off, re-configure again
+		 * Set the CLASS_REV of RC CFG header to
+		 * PCI_CLASS_BRIDGE_PCI
+		 */
+		writel(readl(pp->dbi_base + PCI_CLASS_REVISION)
+			| (PCI_CLASS_BRIDGE_PCI << 16),
+			pp->dbi_base + PCI_CLASS_REVISION);
+
+		dw_pcie_setup_rc(pp);
+	}
+}
+
+static struct syscore_ops pci_imx_syscore_ops = {
+	.suspend = pci_imx_suspend,
+	.resume = pci_imx_resume,
+};
+#endif
+
 static int __init imx6_pcie_probe(struct platform_device *pdev)
 {
-	struct imx6_pcie *imx6_pcie;
 	struct pcie_port *pp;
+	const struct of_device_id *of_id =
+			of_match_device(imx6_pcie_of_match, &pdev->dev);
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *dbi_base;
 	int ret;
@@ -560,6 +682,7 @@  static int __init imx6_pcie_probe(struct platform_device *pdev)
 
 	pp = &imx6_pcie->pp;
 	pp->dev = &pdev->dev;
+	imx6_pcie->data = of_id->data;
 
 	/* Added for PCI abort handling */
 	hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
@@ -603,9 +726,19 @@  static int __init imx6_pcie_probe(struct platform_device *pdev)
 		return PTR_ERR(imx6_pcie->pcie);
 	}
 
-	/* Grab GPR config register range */
-	imx6_pcie->iomuxc_gpr =
-		 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		imx6_pcie->pcie_regulator = devm_regulator_get(pp->dev, "pcie");
+
+		imx6_pcie->iomuxc_gpr =
+			 syscon_regmap_lookup_by_compatible
+			 ("fsl,imx6sx-iomuxc-gpr");
+		imx6_pcie->gpc_ips_reg =
+			 syscon_regmap_lookup_by_compatible("fsl,imx6sx-gpc");
+	} else {
+		imx6_pcie->iomuxc_gpr =
+			syscon_regmap_lookup_by_compatible
+			("fsl,imx6q-iomuxc-gpr");
+	}
 	if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
 		dev_err(&pdev->dev, "unable to find iomuxc registers\n");
 		return PTR_ERR(imx6_pcie->iomuxc_gpr);
@@ -616,6 +749,9 @@  static int __init imx6_pcie_probe(struct platform_device *pdev)
 		return ret;
 
 	platform_set_drvdata(pdev, imx6_pcie);
+#ifdef CONFIG_PM_SLEEP
+	register_syscore_ops(&pci_imx_syscore_ops);
+#endif
 	return 0;
 }
 
@@ -627,12 +763,6 @@  static void imx6_pcie_shutdown(struct platform_device *pdev)
 	imx6_pcie_assert_core_reset(&imx6_pcie->pp);
 }
 
-static const struct of_device_id imx6_pcie_of_match[] = {
-	{ .compatible = "fsl,imx6q-pcie", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
-
 static struct platform_driver imx6_pcie_driver = {
 	.driver = {
 		.name	= "imx6q-pcie",