diff mbox

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

Message ID 1412919676-25344-5-git-send-email-richard.zhu@freescale.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Richard Zhu Oct. 10, 2014, 5:41 a.m. UTC
From: Richard Zhu <r65037@freescale.com>

- 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.
- disp_axi clock is required by pcie inbound axi port actually.
Add one more clock named pcie_inbound_axi for imx6sx pcie.

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

Comments

Fabio Estevam Oct. 10, 2014, 2:55 p.m. UTC | #1
On Fri, Oct 10, 2014 at 2:41 AM, Richard Zhu <richard.zhu@freescale.com> wrote:

>  static void imx6_pcie_init_phy(struct pcie_port *pp)
>  {
>         struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
> +       int ret;
> +
> +       /* Power up the separate domain available on i.MX6SX */
> +       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, GPC_CNTR,
> +                               GPC_CNTR_PCIE_PHY_PUP_REQ,
> +                               GPC_CNTR_PCIE_PHY_PUP_REQ);
> +               regulator_set_voltage(imx6_pcie->pcie_phy_regulator,
> +                               1100000, 1100000);
> +               ret = regulator_enable(imx6_pcie->pcie_phy_regulator);
> +               if (ret)
> +                       dev_info(pp->dev, "failed to enable pcie regulator.\n");

You should 'return ret' in the case of error.
--
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 Oct. 11, 2014, 8:32 a.m. UTC | #2
> -----Original Message-----

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

> Sent: Friday, October 10, 2014 10:55 PM

> To: Richard Zhu

> Cc: linux-pci@vger.kernel.org; Guo Shawn-R65073; Lucas Stach; Tim Harvey; Zhu

> Richard-R65037

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

> 

> On Fri, Oct 10, 2014 at 2:41 AM, Richard Zhu <richard.zhu@freescale.com> wrote:

> 

> >  static void imx6_pcie_init_phy(struct pcie_port *pp)  {

> >         struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);

> > +       int ret;

> > +

> > +       /* Power up the separate domain available on i.MX6SX */

> > +       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, GPC_CNTR,

> > +                               GPC_CNTR_PCIE_PHY_PUP_REQ,

> > +                               GPC_CNTR_PCIE_PHY_PUP_REQ);

> > +               regulator_set_voltage(imx6_pcie->pcie_phy_regulator,

> > +                               1100000, 1100000);

> > +               ret = regulator_enable(imx6_pcie->pcie_phy_regulator);

> > +               if (ret)

> > +                       dev_info(pp->dev, "failed to enable pcie

> > + regulator.\n");

> 

> You should 'return ret' in the case of error.

[Richard] Ok.

Best Regards
Richard Zhu
Lucas Stach Oct. 12, 2014, 2:27 p.m. UTC | #3
Am Freitag, den 10.10.2014, 13:41 +0800 schrieb Richard Zhu:
> From: Richard Zhu <r65037@freescale.com>
> 
> - 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.
> - disp_axi clock is required by pcie inbound axi port actually.
> Add one more clock named pcie_inbound_axi for imx6sx pcie.

> Signed-off-by: Richard Zhu <richard.zhu@freescale.com>

In addition to Fabios comment I have one additional nitpick below and
also you didn't include all the feedback from the last round.

> ---
>  drivers/pci/host/pci-imx6.c | 161 +++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 143 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
> index eac96fb..5ece4e1 100644
> --- a/drivers/pci/host/pci-imx6.c
> +++ b/drivers/pci/host/pci-imx6.c
> @@ -22,8 +22,10 @@
>  #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>
>  
> @@ -35,11 +37,15 @@ struct imx6_pcie {
>  	int			reset_gpio;
>  	struct clk		*pcie_bus;
>  	struct clk		*pcie_phy;
> +	struct clk		*pcie_inbound_axi;
>  	struct clk		*pcie;
>  	struct pcie_port	pp;
>  	struct regmap		*iomuxc_gpr;
> +	struct regmap		*gpc_ips_reg;
> +	struct regulator	*pcie_phy_regulator;
>  	void __iomem		*mem_base;
>  };
> +static struct imx6_pcie *imx6_pcie;

Remove this static struct. I've already said on the last version that
this is completely backwards.

>  
>  /* PCIe Root Complex registers (memory-mapped) */
>  #define PCIE_RC_LCR				0x7c
> @@ -77,6 +83,18 @@ 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)
>  
> +/* GPC PCIE PHY bit definitions */
> +#define GPC_CNTR			0
> +#define GPC_CNTR_PCIE_PHY_PUP_REQ	BIT(7)
> +
> +static inline bool is_imx6sx_pcie(struct imx6_pcie *imx6_pcie)
> +{
> +	struct pcie_port *pp = &imx6_pcie->pp;
> +	struct device_node *np = pp->dev->of_node;
> +
> +	return of_device_is_compatible(np, "fsl,imx6sx-pcie");
> +}
> +
>  static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
>  {
>  	u32 val;
> @@ -275,18 +293,29 @@ 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);
> -	/*
> -	 * the async reset input need ref clock to sync internally,
> -	 * when the ref clock comes after reset, internal synced
> -	 * reset time is too short , cannot meet the requirement.
> -	 * add one ~10us delay here.
> -	 */
> -	udelay(10);
> -	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
> -			IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
> +	if (is_imx6sx_pcie(imx6_pcie)) {
> +		ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
> +		if (ret) {
> +			dev_err(pp->dev, "unable to enable pcie clock\n");
> +			goto err_inbound_axi;
> +		}
> +
> +		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
> +				IMX6SX_GPR12_PCIE_TEST_PD, 0);
> +	} else {
> +		/* power up core phy and enable ref clock */
> +		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
> +				IMX6Q_GPR1_PCIE_TEST_PD, 0);
> +		/*
> +		 * the async reset input need ref clock to sync internally,
> +		 * when the ref clock comes after reset, internal synced
> +		 * reset time is too short , cannot meet the requirement.
> +		 * add one ~10us delay here.
> +		 */
> +		udelay(10);
> +		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
> +				IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);

[...]

Please use IMX6Q_GPR1_PCIE_REF_CLK_EN instead of 1 << 16 here. I know
this is only moved code, but as you are touching it anyway this cleanup
should be folded in.


--
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 Oct. 13, 2014, 2:30 a.m. UTC | #4
Hi Lucas:

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

> From: linux-pci-owner@vger.kernel.org [mailto:linux-pci-owner@vger.kernel.org]

> On Behalf Of Lucas Stach

> Sent: Sunday, October 12, 2014 10:28 PM

> To: Richard Zhu

> Cc: linux-pci@vger.kernel.org; Guo Shawn-R65073; festevam@gmail.com;

> tharvey@gateworks.com; Zhu Richard-R65037

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

> 

> Am Freitag, den 10.10.2014, 13:41 +0800 schrieb Richard Zhu:

> > From: Richard Zhu <r65037@freescale.com>

> >

> > - 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.

> > - disp_axi clock is required by pcie inbound axi port actually.

> > Add one more clock named pcie_inbound_axi for imx6sx pcie.

> 

> > Signed-off-by: Richard Zhu <richard.zhu@freescale.com>

> 

> In addition to Fabios comment I have one additional nitpick below and also you

> didn't include all the feedback from the last round.

> 

> > ---

> >  drivers/pci/host/pci-imx6.c | 161

> > +++++++++++++++++++++++++++++++++++++++-----

> >  1 file changed, 143 insertions(+), 18 deletions(-)

> >

> > diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c

> > index eac96fb..5ece4e1 100644

> > --- a/drivers/pci/host/pci-imx6.c

> > +++ b/drivers/pci/host/pci-imx6.c

> > @@ -22,8 +22,10 @@

> >  #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>

> >

> > @@ -35,11 +37,15 @@ struct imx6_pcie {

> >  	int			reset_gpio;

> >  	struct clk		*pcie_bus;

> >  	struct clk		*pcie_phy;

> > +	struct clk		*pcie_inbound_axi;

> >  	struct clk		*pcie;

> >  	struct pcie_port	pp;

> >  	struct regmap		*iomuxc_gpr;

> > +	struct regmap		*gpc_ips_reg;

> > +	struct regulator	*pcie_phy_regulator;

> >  	void __iomem		*mem_base;

> >  };

> > +static struct imx6_pcie *imx6_pcie;

> 

> Remove this static struct. I've already said on the last version that this is

> completely backwards.

> 

[Richard] I added my comments in the last round.
 Can't use imx6_pcie struct syscore suspend/resume, if the imx6_pcie is not a static type structure.
"
Hi Lucas:
Regarding to the definitions(pasted below) of the struct syscore_ops, both suspend and resume of the syscore_ops is void type functions.
If there is no the static global struct imx6_pcie, I don't know how it can be used in suspend/resume of pci_imx_syscore_ops.
struct syscore_ops {
        struct list_head node;
        int (*suspend)(void);
        void (*resume)(void);
        void (*shutdown)(void);
};
"

> >

> >  /* PCIe Root Complex registers (memory-mapped) */

> >  #define PCIE_RC_LCR				0x7c

> > @@ -77,6 +83,18 @@ 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)

> >

> > +/* GPC PCIE PHY bit definitions */

> > +#define GPC_CNTR			0

> > +#define GPC_CNTR_PCIE_PHY_PUP_REQ	BIT(7)

> > +

> > +static inline bool is_imx6sx_pcie(struct imx6_pcie *imx6_pcie) {

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

> > +	struct device_node *np = pp->dev->of_node;

> > +

> > +	return of_device_is_compatible(np, "fsl,imx6sx-pcie"); }

> > +

> >  static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)  {

> >  	u32 val;

> > @@ -275,18 +293,29 @@ 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);

> > -	/*

> > -	 * the async reset input need ref clock to sync internally,

> > -	 * when the ref clock comes after reset, internal synced

> > -	 * reset time is too short , cannot meet the requirement.

> > -	 * add one ~10us delay here.

> > -	 */

> > -	udelay(10);

> > -	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,

> > -			IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);

> > +	if (is_imx6sx_pcie(imx6_pcie)) {

> > +		ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);

> > +		if (ret) {

> > +			dev_err(pp->dev, "unable to enable pcie clock\n");

> > +			goto err_inbound_axi;

> > +		}

> > +

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

> > +				IMX6SX_GPR12_PCIE_TEST_PD, 0);

> > +	} else {

> > +		/* power up core phy and enable ref clock */

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

> > +				IMX6Q_GPR1_PCIE_TEST_PD, 0);

> > +		/*

> > +		 * the async reset input need ref clock to sync internally,

> > +		 * when the ref clock comes after reset, internal synced

> > +		 * reset time is too short , cannot meet the requirement.

> > +		 * add one ~10us delay here.

> > +		 */

> > +		udelay(10);

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

> > +				IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);

> 

> [...]

> 

> Please use IMX6Q_GPR1_PCIE_REF_CLK_EN instead of 1 << 16 here. I know this is

> only moved code, but as you are touching it anyway this cleanup should be

> folded in.

[Richard] Ok.
> 

> 

> --

> 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



Best Regards
Richard Zhu
Lucas Stach Oct. 14, 2014, 10:12 p.m. UTC | #5
Hi Richard,

Am Montag, den 13.10.2014, 02:30 +0000 schrieb
Hong-Xing.Zhu@freescale.com:
> Hi Lucas:
> 
> > -----Original Message-----
> > From: linux-pci-owner@vger.kernel.org [mailto:linux-pci-owner@vger.kernel.org]
> > On Behalf Of Lucas Stach
> > Sent: Sunday, October 12, 2014 10:28 PM
> > To: Richard Zhu
> > Cc: linux-pci@vger.kernel.org; Guo Shawn-R65073; festevam@gmail.com;
> > tharvey@gateworks.com; Zhu Richard-R65037
> > Subject: Re: [PATCH v5 4/9] PCI: imx6: add imx6sx pcie support
> > 
> > Am Freitag, den 10.10.2014, 13:41 +0800 schrieb Richard Zhu:
> > > From: Richard Zhu <r65037@freescale.com>
> > >
> > > - 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.
> > > - disp_axi clock is required by pcie inbound axi port actually.
> > > Add one more clock named pcie_inbound_axi for imx6sx pcie.
> > 
> > > Signed-off-by: Richard Zhu <richard.zhu@freescale.com>
> > 
> > In addition to Fabios comment I have one additional nitpick below and also you
> > didn't include all the feedback from the last round.
> > 
> > > ---
> > >  drivers/pci/host/pci-imx6.c | 161
> > > +++++++++++++++++++++++++++++++++++++++-----
> > >  1 file changed, 143 insertions(+), 18 deletions(-)
> > >
> > > diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
> > > index eac96fb..5ece4e1 100644
> > > --- a/drivers/pci/host/pci-imx6.c
> > > +++ b/drivers/pci/host/pci-imx6.c
> > > @@ -22,8 +22,10 @@
> > >  #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>
> > >
> > > @@ -35,11 +37,15 @@ struct imx6_pcie {
> > >  	int			reset_gpio;
> > >  	struct clk		*pcie_bus;
> > >  	struct clk		*pcie_phy;
> > > +	struct clk		*pcie_inbound_axi;
> > >  	struct clk		*pcie;
> > >  	struct pcie_port	pp;
> > >  	struct regmap		*iomuxc_gpr;
> > > +	struct regmap		*gpc_ips_reg;
> > > +	struct regulator	*pcie_phy_regulator;
> > >  	void __iomem		*mem_base;
> > >  };
> > > +static struct imx6_pcie *imx6_pcie;
> > 
> > Remove this static struct. I've already said on the last version that this is
> > completely backwards.
> > 
> [Richard] I added my comments in the last round.
>  Can't use imx6_pcie struct syscore suspend/resume, if the imx6_pcie is not a static type structure.
> "
> Hi Lucas:
> Regarding to the definitions(pasted below) of the struct syscore_ops, both suspend and resume of the syscore_ops is void type functions.
> If there is no the static global struct imx6_pcie, I don't know how it can be used in suspend/resume of pci_imx_syscore_ops.
> struct syscore_ops {
>         struct list_head node;
>         int (*suspend)(void);
>         void (*resume)(void);
>         void (*shutdown)(void);
> };
> "
This only means syscore ops is not the right interface to use here.
Introducing global static vars to hold driver instance state is a
receipt to create trouble later on. Don't ever do this.

I think it should be possible to move those calls to normal dev_pm_ops,
maybe use suspend/resume_noirq or even poweroff/restore_noirq.

Regards,
Lucas

--
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
diff mbox

Patch

diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index eac96fb..5ece4e1 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -22,8 +22,10 @@ 
 #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>
 
@@ -35,11 +37,15 @@  struct imx6_pcie {
 	int			reset_gpio;
 	struct clk		*pcie_bus;
 	struct clk		*pcie_phy;
+	struct clk		*pcie_inbound_axi;
 	struct clk		*pcie;
 	struct pcie_port	pp;
 	struct regmap		*iomuxc_gpr;
+	struct regmap		*gpc_ips_reg;
+	struct regulator	*pcie_phy_regulator;
 	void __iomem		*mem_base;
 };
+static struct imx6_pcie *imx6_pcie;
 
 /* PCIe Root Complex registers (memory-mapped) */
 #define PCIE_RC_LCR				0x7c
@@ -77,6 +83,18 @@  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)
 
+/* GPC PCIE PHY bit definitions */
+#define GPC_CNTR			0
+#define GPC_CNTR_PCIE_PHY_PUP_REQ	BIT(7)
+
+static inline bool is_imx6sx_pcie(struct imx6_pcie *imx6_pcie)
+{
+	struct pcie_port *pp = &imx6_pcie->pp;
+	struct device_node *np = pp->dev->of_node;
+
+	return of_device_is_compatible(np, "fsl,imx6sx-pcie");
+}
+
 static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
 {
 	u32 val;
@@ -275,18 +293,29 @@  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);
-	/*
-	 * the async reset input need ref clock to sync internally,
-	 * when the ref clock comes after reset, internal synced
-	 * reset time is too short , cannot meet the requirement.
-	 * add one ~10us delay here.
-	 */
-	udelay(10);
-	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
-			IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
+		if (ret) {
+			dev_err(pp->dev, "unable to enable pcie clock\n");
+			goto err_inbound_axi;
+		}
+
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+				IMX6SX_GPR12_PCIE_TEST_PD, 0);
+	} else {
+		/* power up core phy and enable ref clock */
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+				IMX6Q_GPR1_PCIE_TEST_PD, 0);
+		/*
+		 * the async reset input need ref clock to sync internally,
+		 * when the ref clock comes after reset, internal synced
+		 * reset time is too short , cannot meet the requirement.
+		 * add one ~10us delay here.
+		 */
+		udelay(10);
+		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);
@@ -297,8 +326,19 @@  static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
 		msleep(100);
 		gpio_set_value(imx6_pcie->reset_gpio, 1);
 	}
+
+	/*
+	 * Release the PCIe PHY reset here, that we have set in
+	 * imx6_pcie_init_phy() now
+	 */
+	if (is_imx6sx_pcie(imx6_pcie))
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+				IMX6SX_GPR5_PCIE_BTNRST, 0);
+
 	return 0;
 
+err_inbound_axi:
+	clk_disable_unprepare(imx6_pcie->pcie);
 err_pcie:
 	clk_disable_unprepare(imx6_pcie->pcie_bus);
 err_pcie_bus:
@@ -311,6 +351,26 @@  err_pcie_phy:
 static void imx6_pcie_init_phy(struct pcie_port *pp)
 {
 	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+	int ret;
+
+	/* Power up the separate domain available on i.MX6SX */
+	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, GPC_CNTR,
+				GPC_CNTR_PCIE_PHY_PUP_REQ,
+				GPC_CNTR_PCIE_PHY_PUP_REQ);
+		regulator_set_voltage(imx6_pcie->pcie_phy_regulator,
+				1100000, 1100000);
+		ret = regulator_enable(imx6_pcie->pcie_phy_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);
@@ -319,7 +379,7 @@  static void imx6_pcie_init_phy(struct pcie_port *pp)
 	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);
@@ -377,7 +437,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)
@@ -553,9 +614,50 @@  static int __init imx6_add_pcie_port(struct pcie_port *pp,
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pci_imx_suspend(void)
+{
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		/* PM_TURN_OFF */
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+				IMX6SX_GPR12_PCIE_PM_TURN_OFF,
+				IMX6SX_GPR12_PCIE_PM_TURN_OFF);
+		udelay(10);
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+				IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0);
+	}
+
+	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,
+				IMX6SX_GPR5_PCIE_PERST, IMX6SX_GPR5_PCIE_PERST);
+		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+				IMX6SX_GPR5_PCIE_PERST, 0);
+		/*
+		 * controller maybe turn off, re-configure again
+		 */
+		dw_pcie_setup_rc(pp);
+
+		if (IS_ENABLED(CONFIG_PCI_MSI))
+			dw_pcie_msi_cfg_restore(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;
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *dbi_base;
@@ -610,9 +712,28 @@  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_inbound_axi = devm_clk_get(&pdev->dev,
+				"pcie_inbound_axi");
+		if (IS_ERR(imx6_pcie->pcie_inbound_axi)) {
+			dev_err(&pdev->dev,
+				"pcie clock source missing or invalid\n");
+			return PTR_ERR(imx6_pcie->pcie_inbound_axi);
+		}
+
+		imx6_pcie->pcie_phy_regulator = devm_regulator_get(pp->dev,
+				"pcie-phy");
+
+		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);
@@ -623,6 +744,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;
 }
 
@@ -636,6 +760,7 @@  static void imx6_pcie_shutdown(struct platform_device *pdev)
 
 static const struct of_device_id imx6_pcie_of_match[] = {
 	{ .compatible = "fsl,imx6q-pcie", },
+	{ .compatible = "fsl,imx6sx-pcie", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);