diff mbox

[RFC,2/2] PCI: imx6: add imx6sx pcie support

Message ID 1411376498-14653-3-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, 9:01 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.
- another dis_axi clk is mandatory required by imx6sx pcie.
Add one new clk named pcie_sec into imx6_pcie structure.
- pcie_ref_125m is not used as pcie_phy clk anymore on imx6sx.
The parent clk (pcie_ref) of the pcie_bus(lvds1_gate)
is used as pcie_phy clk.
- Register one PM call-back, enter/exit L2 state of the ASPM
during system suspend/resume.
- wait the clocks to stabilize after the pcie_ref_en
(IMX6Q_GPR1_PCIE_REF_CLK_EN) is set.

Signed-off-by: Richard Zhu <r65037@freescale.com>
---
 arch/arm/boot/dts/imx6sx-sdb.dts            |  15 ++
 arch/arm/boot/dts/imx6sx.dtsi               |  33 ++--
 arch/arm/mach-imx/Kconfig                   |   1 +
 drivers/pci/host/pci-imx6.c                 | 228 ++++++++++++++++++++++++----
 include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |  14 ++
 5 files changed, 249 insertions(+), 42 deletions(-)

Comments

Lucas Stach Sept. 22, 2014, 10:02 a.m. UTC | #1
Hi Richard,

This commit smashes lots of things together. It would be much easier to
review this if the changes were broken out appropriately.

Also why are you sending RFC patches to stable?

A few quick comments below, this isn't a full review yet.

Am Montag, den 22.09.2014, 17:01 +0800 schrieb Richard Zhu:
> - 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.
> - another dis_axi clk is mandatory required by imx6sx pcie.
> Add one new clk named pcie_sec into imx6_pcie structure.
> - pcie_ref_125m is not used as pcie_phy clk anymore on imx6sx.
> The parent clk (pcie_ref) of the pcie_bus(lvds1_gate)
> is used as pcie_phy clk.

You remove this clock from the binding. I don't see a reason why, just
fill in pcie_ref for both pcie_bus and pcie_phy. No need to implement
different code paths for this.

> - Register one PM call-back, enter/exit L2 state of the ASPM
> during system suspend/resume.
> - wait the clocks to stabilize after the pcie_ref_en
> (IMX6Q_GPR1_PCIE_REF_CLK_EN) is set.


> Signed-off-by: Richard Zhu <r65037@freescale.com>
> ---
>  arch/arm/boot/dts/imx6sx-sdb.dts            |  15 ++
>  arch/arm/boot/dts/imx6sx.dtsi               |  33 ++--
>  arch/arm/mach-imx/Kconfig                   |   1 +
>  drivers/pci/host/pci-imx6.c                 | 228 ++++++++++++++++++++++++----
>  include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |  14 ++
>  5 files changed, 249 insertions(+), 42 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts
> index a3980d9..83d0892 100644
> --- a/arch/arm/boot/dts/imx6sx-sdb.dts
> +++ b/arch/arm/boot/dts/imx6sx-sdb.dts
> @@ -251,6 +251,14 @@
>  	};
>  };
>  
> +&pcie {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_pcie>;
> +	power-on-gpio = <&gpio2 1 0>;

No such GPIO in the binding.

> +	reset-gpio = <&gpio2 0 0>;
> +	status = "okay";
> +};
> +
>  &ssi2 {
>  	status = "okay";
>  };
> @@ -365,6 +373,13 @@
>  			>;
>  		};
>  
> +		pinctrl_pcie: pciegrp {
> +			fsl,pins = <
> +				MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x17059
> +				MX6SX_PAD_ENET1_CRS__GPIO2_IO_1	0x17059
> +			>;
> +		};
> +
>  		pinctrl_vcc_sd3: vccsd3grp {
>  			fsl,pins = <
>  				MX6SX_PAD_KEY_COL1__GPIO2_IO_11		0x17059
> diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
> index f4b9da6..ec34698 100644
> --- a/arch/arm/boot/dts/imx6sx.dtsi
> +++ b/arch/arm/boot/dts/imx6sx.dtsi
> @@ -689,9 +689,11 @@
>  			};
>  
>  			gpc: gpc@020dc000 {
> -				compatible = "fsl,imx6sx-gpc", "fsl,imx6q-gpc";
> +				compatible = "fsl,imx6sx-gpc",
> +					     "fsl,imx6q-gpc", "syscon";
>  				reg = <0x020dc000 0x4000>;
>  				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
> +				pcie-supply = <&reg_pcie>;
>  			};
>  
>  			iomuxc: iomuxc@020e0000 {
> @@ -1188,20 +1190,23 @@
>  			#address-cells = <3>;
>  			#size-cells = <2>;
>  			device_type = "pci";
> -				  /* configuration space */
> -			ranges = <0x00000800 0 0x08f00000 0x08f00000 0 0x00080000
> -				  /* downstream I/O */
> -				  0x81000000 0 0          0x08f80000 0 0x00010000
> -				  /* non-prefetchable memory */
> -				  0x82000000 0 0x08000000 0x08000000 0 0x00f00000>;
> +			ranges = <0x00000800 0 0x01f00000 0x08f00000 0 0x00080000 /* configuration space */
> +				  0x81000000 0 0          0x08f80000 0 0x00010000 /* downstream I/O */
> +				  0x82000000 0 0x01000000 0x08000000 0 0x00f00000>; /* non-prefetchable memory */
>  			num-lanes = <1>;
> -			interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
> -			clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>,
> -				 <&clks IMX6SX_CLK_PCIE_AXI>,
> -				 <&clks IMX6SX_CLK_LVDS1_OUT>,
> -				 <&clks IMX6SX_CLK_DISPLAY_AXI>;
> -			clock-names = "pcie_ref_125m", "pcie_axi",
> -				      "lvds_gate", "display_axi";
> +			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "msi";
> +			#interrupt-cells = <1>;
> +			interrupt-map-mask = <0 0 0 0x7>;
> +			interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> +			                <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
> +			                <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
> +			                <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&clks IMX6SX_CLK_PCIE_AXI>,
> +				 <&clks IMX6SX_CLK_DISPLAY_AXI>,
> +				 <&clks IMX6SX_CLK_LVDS1_OUT>;
> +			clock-names = "pcie", "pcie_sec", "pcie_bus";
> +			pcie-supply = <&reg_pcie>;
>  			status = "disabled";
>  		};
>  	};
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index be9a51a..0a055f0 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -718,6 +718,7 @@ config SOC_IMX6SL
>  
>  config SOC_IMX6SX
>  	bool "i.MX6 SoloX support"
> +	select PCI_DOMAINS if PCI
>  	select PINCTRL_IMX6SX
>  	select SOC_IMX6
>  
> diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
> index 233fe8a..c9b2f69 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,32 @@
>  
>  #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;
> +	int			power_on_gpio;
> +	const struct		imx_pcie_data *data;
>  	struct clk		*pcie_bus;
>  	struct clk		*pcie_phy;
> +	struct clk		*pcie_sec;
>  	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 +98,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;
> @@ -257,10 +283,21 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
>  	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
>  	int ret;
>  
> -	ret = clk_prepare_enable(imx6_pcie->pcie_phy);
> -	if (ret) {
> -		dev_err(pp->dev, "unable to enable pcie_phy clock\n");
> -		goto err_pcie_phy;
> +	if (gpio_is_valid(imx6_pcie->power_on_gpio))
> +		gpio_set_value(imx6_pcie->power_on_gpio, 1);
> +

I won't allow this to creep in again. This needs to be a proper
regulator, not some kind of gpio.

> +	if (is_imx6sx_pcie(imx6_pcie)) {
> +		ret = clk_prepare_enable(imx6_pcie->pcie_sec);
> +		if (ret) {
> +			dev_err(pp->dev, "unable to enable pcie_sec clk.\n");
> +			goto err_pcie_sec;
> +		}
> +	} else {
> +		ret = clk_prepare_enable(imx6_pcie->pcie_phy);
> +		if (ret) {
> +			dev_err(pp->dev, "unable to enable pcie_phy clock\n");
> +			goto err_pcie_phy;
> +		}
>  	}
>  
>  	ret = clk_prepare_enable(imx6_pcie->pcie_bus);
> @@ -275,28 +312,50 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
>  		goto err_pcie;
>  	}
>  
> +	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);
>  
> -	/* 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);
> -
>  	/* Some boards don't have PCIe reset GPIO. */
>  	if (gpio_is_valid(imx6_pcie->reset_gpio)) {
>  		gpio_set_value(imx6_pcie->reset_gpio, 0);
>  		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:
>  	clk_disable_unprepare(imx6_pcie->pcie_bus);
>  err_pcie_bus:
> -	clk_disable_unprepare(imx6_pcie->pcie_phy);
> +	if (!is_imx6sx_pcie(imx6_pcie))
> +		clk_disable_unprepare(imx6_pcie->pcie_phy);
>  err_pcie_phy:
> +	if (is_imx6sx_pcie(imx6_pcie))
> +		clk_disable_unprepare(imx6_pcie->pcie_sec);
> +err_pcie_sec:
>  	return ret;
>  
>  }
> @@ -304,15 +363,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);

What is this? Is this a regulator? If so, why isn't it abstracted as a
proper regulator?

> +		/* 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");

This regulator gets enabled here, but I don't see any path were we would
disable it. Is this a always-on regulator or are you simply missing the
calls to disable it in the runtime-pm hooks?

> +		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 +452,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 +629,73 @@ 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);

Why are there no defines for those bits? I can't really tell what's
going on here. Is this some kind of power gating the SoC partition? In
that case it should really be implemented as a power-domain and not as
some kind of ad-hoc GPR register bashing.

> +	}
> +
> +	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);
> +
> +		/* 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);

Why the double reset?

> +	}
> +}
> +
> +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 +706,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,
> @@ -581,12 +728,26 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
>  		}
>  	}
>  
> +	imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
> +	if (gpio_is_valid(imx6_pcie->power_on_gpio)) {
> +		ret = devm_gpio_request_one(&pdev->dev,
> +					imx6_pcie->power_on_gpio,
> +					GPIOF_OUT_INIT_LOW,
> +					"PCIe power enable");
> +		if (ret) {
> +			dev_err(&pdev->dev, "unable to get power-on gpio\n");
> +			return ret;
> +		}
> +	}
> +
>  	/* Fetch clocks */
> -	imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");
> -	if (IS_ERR(imx6_pcie->pcie_phy)) {
> -		dev_err(&pdev->dev,
> -			"pcie_phy clock source missing or invalid\n");
> -		return PTR_ERR(imx6_pcie->pcie_phy);
> +	if (!is_imx6sx_pcie(imx6_pcie)) {
> +		imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");
> +		if (IS_ERR(imx6_pcie->pcie_phy)) {
> +			dev_err(&pdev->dev,
> +				"pcie_phy clock source missing or invalid\n");
> +			return PTR_ERR(imx6_pcie->pcie_phy);
> +		}
>  	}
>  

Missing binding update for the changed clock handling. Also what is this
clock pcie_sec? Is it really a second AXI clock? I highly doubt that the
register interface of the core is clocked by two different clocks. What
blocks of the dw_pci core does this clock feed?

>  	imx6_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_bus");
> @@ -604,8 +765,22 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
>  	}
>  
>  	/* Grab GPR config register range */
> -	imx6_pcie->iomuxc_gpr =
> -		 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
> +	if (is_imx6sx_pcie(imx6_pcie)) {
> +		/* Get pcie regulator */
> +		imx6_pcie->pcie_regulator = devm_regulator_get(pp->dev, "pcie");

Uh, this has nothing to do with the GPR range, so the comment above is
confusing. Also missing binding update for this regulator.

> +
> +		/* Grab GPR config register range */
> +		imx6_pcie->iomuxc_gpr =
> +			 syscon_regmap_lookup_by_compatible
> +			 ("fsl,imx6sx-iomuxc-gpr");
> +		/* Grab GPC IPS register range */
> +		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 +791,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 +805,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",
> diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
> index ff44374..f02875e 100644
> --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
> +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
> @@ -113,10 +113,12 @@
>  #define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET		0x0
>  #define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX		BIT(19)
>  #define IMX6Q_GPR1_PCIE_TEST_PD			BIT(18)
> +#define IMX6Q_GPR1_PCIE_TEST_PD_CLR		0x0
>  #define IMX6Q_GPR1_IPU_VPU_MUX_MASK		BIT(17)
>  #define IMX6Q_GPR1_IPU_VPU_MUX_IPU1		0x0
>  #define IMX6Q_GPR1_IPU_VPU_MUX_IPU2		BIT(17)
>  #define IMX6Q_GPR1_PCIE_REF_CLK_EN		BIT(16)
> +#define IMX6Q_GPR1_PCIE_REF_CLK_CLR		0x0
>  #define IMX6Q_GPR1_USB_EXP_MODE			BIT(15)
>  #define IMX6Q_GPR1_PCIE_INT			BIT(14)
>  #define IMX6Q_GPR1_USB_OTG_ID_SEL_MASK		BIT(13)
> @@ -300,7 +302,9 @@
>  #define IMX6Q_GPR12_ARMP_APB_CLK_EN		BIT(24)
>  #define IMX6Q_GPR12_DEVICE_TYPE			(0xf << 12)
>  #define IMX6Q_GPR12_PCIE_CTL_2			BIT(10)
> +#define IMX6Q_GPR12_PCIE_CTL_2_CLR		0x0
>  #define IMX6Q_GPR12_LOS_LEVEL			(0x1f << 4)
> +#define IMX6Q_GPR12_LOS_LEVEL_9			(0x9 << 4)
>  
>  #define IMX6Q_GPR13_SDMA_STOP_REQ		BIT(30)
>  #define IMX6Q_GPR13_CAN2_STOP_REQ		BIT(29)
> @@ -395,4 +399,14 @@
>  #define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK    (0x3 << 17)
>  #define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK    (0x1 << 14)
>  
> +/* For imx6sx iomux gpr register field define */
> +#define IMX6SX_GPR5_PCIE_BTNRST			BIT(19)
> +#define IMX6SX_GPR5_PCIE_BTNRST_CLR		0x0
> +#define IMX6SX_GPR5_PCIE_PERST			BIT(18)
> +#define IMX6SX_GPR5_PCIE_PERST_CLR		0x0
> +
> +#define IMX6SX_GPR12_PCIE_TEST_PD		BIT(30)
> +#define IMX6SX_GPR12_PCIE_TEST_PD_CLR		0x0
> +#define IMX6SX_GPR12_RX_EQ_MASK			(0x7 << 0)
> +#define IMX6SX_GPR12_RX_EQ_2			(0x2 << 0)
>  #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */
Richard Zhu Sept. 22, 2014, 10:31 a.m. UTC | #2
Hi Lucas:
Thanks for your quick review comments.


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

> From: Lucas Stach [mailto:l.stach@pengutronix.de]

> Sent: Monday, September 22, 2014 6:02 PM

> To: Zhu Richard-R65037

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

> pci@vger.kernel.org

> Subject: Re: [PATCH RFC 2/2] PCI: imx6: add imx6sx pcie support

> 

> Hi Richard,

> 

> This commit smashes lots of things together. It would be much easier to review

> this if the changes were broken out appropriately.

> 

> Also why are you sending RFC patches to stable?

> 

> A few quick comments below, this isn't a full review yet.

> 

> Am Montag, den 22.09.2014, 17:01 +0800 schrieb Richard Zhu:

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

> > - another dis_axi clk is mandatory required by imx6sx pcie.

> > Add one new clk named pcie_sec into imx6_pcie structure.

> > - pcie_ref_125m is not used as pcie_phy clk anymore on imx6sx.

> > The parent clk (pcie_ref) of the pcie_bus(lvds1_gate) is used as

> > pcie_phy clk.

> 

> You remove this clock from the binding. I don't see a reason why, just fill in

> pcie_ref for both pcie_bus and pcie_phy. No need to implement different code

> paths for this.

[Richard] pcie_ref is not only used as pcie_phy, but also as the parent of the pcie_bus.
Pcie_phy would be enabled automatically, when pcie_bus is enabled on imx6sx.

> 

> > - Register one PM call-back, enter/exit L2 state of the ASPM during

> > system suspend/resume.

> > - wait the clocks to stabilize after the pcie_ref_en

> > (IMX6Q_GPR1_PCIE_REF_CLK_EN) is set.

> 

> 

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

> > ---

> >  arch/arm/boot/dts/imx6sx-sdb.dts            |  15 ++

> >  arch/arm/boot/dts/imx6sx.dtsi               |  33 ++--

> >  arch/arm/mach-imx/Kconfig                   |   1 +

> >  drivers/pci/host/pci-imx6.c                 | 228 ++++++++++++++++++++++++-

> ---

> >  include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |  14 ++

> >  5 files changed, 249 insertions(+), 42 deletions(-)

> >

> > diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts

> > b/arch/arm/boot/dts/imx6sx-sdb.dts

> > index a3980d9..83d0892 100644

> > --- a/arch/arm/boot/dts/imx6sx-sdb.dts

> > +++ b/arch/arm/boot/dts/imx6sx-sdb.dts

> > @@ -251,6 +251,14 @@

> >  	};

> >  };

> >

> > +&pcie {

> > +	pinctrl-names = "default";

> > +	pinctrl-0 = <&pinctrl_pcie>;

> > +	power-on-gpio = <&gpio2 1 0>;

> 

> No such GPIO in the binding.

[Richard] power-on-gpio would be removed.
> 

> > +	reset-gpio = <&gpio2 0 0>;

> > +	status = "okay";

> > +};

> > +

> >  &ssi2 {

> >  	status = "okay";

> >  };

> > @@ -365,6 +373,13 @@

> >  			>;

> >  		};

> >

> > +		pinctrl_pcie: pciegrp {

> > +			fsl,pins = <

> > +				MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x17059

> > +				MX6SX_PAD_ENET1_CRS__GPIO2_IO_1	0x17059

> > +			>;

> > +		};

> > +

> >  		pinctrl_vcc_sd3: vccsd3grp {

> >  			fsl,pins = <

> >  				MX6SX_PAD_KEY_COL1__GPIO2_IO_11		0x17059

> > diff --git a/arch/arm/boot/dts/imx6sx.dtsi

> > b/arch/arm/boot/dts/imx6sx.dtsi index f4b9da6..ec34698 100644

> > --- a/arch/arm/boot/dts/imx6sx.dtsi

> > +++ b/arch/arm/boot/dts/imx6sx.dtsi

> > @@ -689,9 +689,11 @@

> >  			};

> >

> >  			gpc: gpc@020dc000 {

> > -				compatible = "fsl,imx6sx-gpc", "fsl,imx6q-gpc";

> > +				compatible = "fsl,imx6sx-gpc",

> > +					     "fsl,imx6q-gpc", "syscon";

> >  				reg = <0x020dc000 0x4000>;

> >  				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;

> > +				pcie-supply = <&reg_pcie>;

> >  			};

> >

> >  			iomuxc: iomuxc@020e0000 {

> > @@ -1188,20 +1190,23 @@

> >  			#address-cells = <3>;

> >  			#size-cells = <2>;

> >  			device_type = "pci";

> > -				  /* configuration space */

> > -			ranges = <0x00000800 0 0x08f00000 0x08f00000 0 0x00080000

> > -				  /* downstream I/O */

> > -				  0x81000000 0 0          0x08f80000 0 0x00010000

> > -				  /* non-prefetchable memory */

> > -				  0x82000000 0 0x08000000 0x08000000 0 0x00f00000>;

> > +			ranges = <0x00000800 0 0x01f00000 0x08f00000 0 0x00080000 /*

> configuration space */

> > +				  0x81000000 0 0          0x08f80000 0 0x00010000 /*

> downstream I/O */

> > +				  0x82000000 0 0x01000000 0x08000000 0 0x00f00000>; /*

> > +non-prefetchable memory */

> >  			num-lanes = <1>;

> > -			interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;

> > -			clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>,

> > -				 <&clks IMX6SX_CLK_PCIE_AXI>,

> > -				 <&clks IMX6SX_CLK_LVDS1_OUT>,

> > -				 <&clks IMX6SX_CLK_DISPLAY_AXI>;

> > -			clock-names = "pcie_ref_125m", "pcie_axi",

> > -				      "lvds_gate", "display_axi";

> > +			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;

> > +			interrupt-names = "msi";

> > +			#interrupt-cells = <1>;

> > +			interrupt-map-mask = <0 0 0 0x7>;

> > +			interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,

> > +			                <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,

> > +			                <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,

> > +			                <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;

> > +			clocks = <&clks IMX6SX_CLK_PCIE_AXI>,

> > +				 <&clks IMX6SX_CLK_DISPLAY_AXI>,

> > +				 <&clks IMX6SX_CLK_LVDS1_OUT>;

> > +			clock-names = "pcie", "pcie_sec", "pcie_bus";

> > +			pcie-supply = <&reg_pcie>;

> >  			status = "disabled";

> >  		};

> >  	};

> > diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig

> > index be9a51a..0a055f0 100644

> > --- a/arch/arm/mach-imx/Kconfig

> > +++ b/arch/arm/mach-imx/Kconfig

> > @@ -718,6 +718,7 @@ config SOC_IMX6SL

> >

> >  config SOC_IMX6SX

> >  	bool "i.MX6 SoloX support"

> > +	select PCI_DOMAINS if PCI

> >  	select PINCTRL_IMX6SX

> >  	select SOC_IMX6

> >

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

> > index 233fe8a..c9b2f69 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,32 @@

> >

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

> > +	int			power_on_gpio;

> > +	const struct		imx_pcie_data *data;

> >  	struct clk		*pcie_bus;

> >  	struct clk		*pcie_phy;

> > +	struct clk		*pcie_sec;

> >  	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 +98,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;

> > @@ -257,10 +283,21 @@ static int imx6_pcie_deassert_core_reset(struct

> pcie_port *pp)

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

> >  	int ret;

> >

> > -	ret = clk_prepare_enable(imx6_pcie->pcie_phy);

> > -	if (ret) {

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

> > -		goto err_pcie_phy;

> > +	if (gpio_is_valid(imx6_pcie->power_on_gpio))

> > +		gpio_set_value(imx6_pcie->power_on_gpio, 1);

> > +

> 

> I won't allow this to creep in again. This needs to be a proper regulator, not

> some kind of gpio.

[Richard] would be removed. Thanks.
> 

> > +	if (is_imx6sx_pcie(imx6_pcie)) {

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

> > +		if (ret) {

> > +			dev_err(pp->dev, "unable to enable pcie_sec clk.\n");

> > +			goto err_pcie_sec;

> > +		}

> > +	} else {

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

> > +		if (ret) {

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

> > +			goto err_pcie_phy;

> > +		}

> >  	}

> >

> >  	ret = clk_prepare_enable(imx6_pcie->pcie_bus);

> > @@ -275,28 +312,50 @@ static int imx6_pcie_deassert_core_reset(struct

> pcie_port *pp)

> >  		goto err_pcie;

> >  	}

> >

> > +	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);

> >

> > -	/* 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);

> > -

> >  	/* Some boards don't have PCIe reset GPIO. */

> >  	if (gpio_is_valid(imx6_pcie->reset_gpio)) {

> >  		gpio_set_value(imx6_pcie->reset_gpio, 0);

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

> >  	clk_disable_unprepare(imx6_pcie->pcie_bus);

> >  err_pcie_bus:

> > -	clk_disable_unprepare(imx6_pcie->pcie_phy);

> > +	if (!is_imx6sx_pcie(imx6_pcie))

> > +		clk_disable_unprepare(imx6_pcie->pcie_phy);

> >  err_pcie_phy:

> > +	if (is_imx6sx_pcie(imx6_pcie))

> > +		clk_disable_unprepare(imx6_pcie->pcie_sec);

> > +err_pcie_sec:

> >  	return ret;

> >

> >  }

> > @@ -304,15 +363,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);

> 

> What is this? Is this a regulator? If so, why isn't it abstracted as a proper

> regulator?

> 

[Richard]No, it's a pre-condition before enable the pcie regulator.

> > +		/* 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");

> 

> This regulator gets enabled here, but I don't see any path were we would

> disable it. Is this a always-on regulator or are you simply missing the calls

> to disable it in the runtime-pm hooks?

[Richard]This regulator is enabled-once during pcie initialization.
imx pcie has to be re-initialized completely if this regulator is disabled once.
It's a always on regulator after the imx pcie is initialized.
> 

> > +		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 +452,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 +629,73 @@ 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);

> 

> Why are there no defines for those bits? I can't really tell what's going on

> here. Is this some kind of power gating the SoC partition? In that case it

> should really be implemented as a power-domain and not as some kind of ad-hoc

> GPR register bashing.

[Richard] Not a power-domain. This bit is just used as RC to kick-off the PM_TURN_OFF message to EP.
It's is used to indicated to EP that the RC is ready to ENTER into L2 state of ASPM.
> 

> > +	}

> > +

> > +	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);

> > +

> > +		/* 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);

> 

> Why the double reset?

[Richard] The second one would be removed. Thanks.
> 

> > +	}

> > +}

> > +

> > +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 +706,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, @@

> > -581,12 +728,26 @@ static int __init imx6_pcie_probe(struct platform_device

> *pdev)

> >  		}

> >  	}

> >

> > +	imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);

> > +	if (gpio_is_valid(imx6_pcie->power_on_gpio)) {

> > +		ret = devm_gpio_request_one(&pdev->dev,

> > +					imx6_pcie->power_on_gpio,

> > +					GPIOF_OUT_INIT_LOW,

> > +					"PCIe power enable");

> > +		if (ret) {

> > +			dev_err(&pdev->dev, "unable to get power-on gpio\n");

> > +			return ret;

> > +		}

> > +	}

> > +

> >  	/* Fetch clocks */

> > -	imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");

> > -	if (IS_ERR(imx6_pcie->pcie_phy)) {

> > -		dev_err(&pdev->dev,

> > -			"pcie_phy clock source missing or invalid\n");

> > -		return PTR_ERR(imx6_pcie->pcie_phy);

> > +	if (!is_imx6sx_pcie(imx6_pcie)) {

> > +		imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");

> > +		if (IS_ERR(imx6_pcie->pcie_phy)) {

> > +			dev_err(&pdev->dev,

> > +				"pcie_phy clock source missing or invalid\n");

> > +			return PTR_ERR(imx6_pcie->pcie_phy);

> > +		}

> >  	}

> >

> 

> Missing binding update for the changed clock handling. Also what is this clock

> pcie_sec? Is it really a second AXI clock? I highly doubt that the register

> interface of the core is clocked by two different clocks. What blocks of the

> dw_pci core does this clock feed?

[Richard] As I know that imx6sx pcie axi clock is contained in the dis_axi domain.
Dis_axi should be turned-on, if pcie is enabled.
How about use the pcie_bus binding dis_axi on imx6sx?
Since the pcie_ref is not only used as pcie_ref but also as the parent of the pcie_phy on imx6sx.
In this case, we can keep alignment the clocks binding with other imx6 pcie.

> 

> >  	imx6_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_bus"); @@

> > -604,8 +765,22 @@ static int __init imx6_pcie_probe(struct platform_device

> *pdev)

> >  	}

> >

> >  	/* Grab GPR config register range */

> > -	imx6_pcie->iomuxc_gpr =

> > -		 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");

> > +	if (is_imx6sx_pcie(imx6_pcie)) {

> > +		/* Get pcie regulator */

> > +		imx6_pcie->pcie_regulator = devm_regulator_get(pp->dev, "pcie");

> 

> Uh, this has nothing to do with the GPR range, so the comment above is

> confusing. Also missing binding update for this regulator.

[Richard] The comment would be removed. Binding update for this regulator would be added later.
> 

> > +

> > +		/* Grab GPR config register range */

> > +		imx6_pcie->iomuxc_gpr =

> > +			 syscon_regmap_lookup_by_compatible

> > +			 ("fsl,imx6sx-iomuxc-gpr");

> > +		/* Grab GPC IPS register range */

> > +		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 +791,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 +805,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",

> > diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h

> > b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h

> > index ff44374..f02875e 100644

> > --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h

> > +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h

> > @@ -113,10 +113,12 @@

> >  #define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET		0x0

> >  #define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX		BIT(19)

> >  #define IMX6Q_GPR1_PCIE_TEST_PD			BIT(18)

> > +#define IMX6Q_GPR1_PCIE_TEST_PD_CLR		0x0

> >  #define IMX6Q_GPR1_IPU_VPU_MUX_MASK		BIT(17)

> >  #define IMX6Q_GPR1_IPU_VPU_MUX_IPU1		0x0

> >  #define IMX6Q_GPR1_IPU_VPU_MUX_IPU2		BIT(17)

> >  #define IMX6Q_GPR1_PCIE_REF_CLK_EN		BIT(16)

> > +#define IMX6Q_GPR1_PCIE_REF_CLK_CLR		0x0

> >  #define IMX6Q_GPR1_USB_EXP_MODE			BIT(15)

> >  #define IMX6Q_GPR1_PCIE_INT			BIT(14)

> >  #define IMX6Q_GPR1_USB_OTG_ID_SEL_MASK		BIT(13)

> > @@ -300,7 +302,9 @@

> >  #define IMX6Q_GPR12_ARMP_APB_CLK_EN		BIT(24)

> >  #define IMX6Q_GPR12_DEVICE_TYPE			(0xf << 12)

> >  #define IMX6Q_GPR12_PCIE_CTL_2			BIT(10)

> > +#define IMX6Q_GPR12_PCIE_CTL_2_CLR		0x0

> >  #define IMX6Q_GPR12_LOS_LEVEL			(0x1f << 4)

> > +#define IMX6Q_GPR12_LOS_LEVEL_9			(0x9 << 4)

> >

> >  #define IMX6Q_GPR13_SDMA_STOP_REQ		BIT(30)

> >  #define IMX6Q_GPR13_CAN2_STOP_REQ		BIT(29)

> > @@ -395,4 +399,14 @@

> >  #define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK    (0x3 << 17)

> >  #define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK    (0x1 << 14)

> >

> > +/* For imx6sx iomux gpr register field define */

> > +#define IMX6SX_GPR5_PCIE_BTNRST			BIT(19)

> > +#define IMX6SX_GPR5_PCIE_BTNRST_CLR		0x0

> > +#define IMX6SX_GPR5_PCIE_PERST			BIT(18)

> > +#define IMX6SX_GPR5_PCIE_PERST_CLR		0x0

> > +

> > +#define IMX6SX_GPR12_PCIE_TEST_PD		BIT(30)

> > +#define IMX6SX_GPR12_PCIE_TEST_PD_CLR		0x0

> > +#define IMX6SX_GPR12_RX_EQ_MASK			(0x7 << 0)

> > +#define IMX6SX_GPR12_RX_EQ_2			(0x2 << 0)

> >  #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */

> 

> --

> Pengutronix e.K.             | Lucas Stach                 |

> Industrial Linux Solutions   | http://www.pengutronix.de/  |


Best Regards
Richard Zhu
Richard Zhu Sept. 22, 2014, 10:48 a.m. UTC | #3
PiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiBGcm9tOiBMdWNhcyBTdGFjaCBbbWFpbHRv
Omwuc3RhY2hAcGVuZ3V0cm9uaXguZGVdDQo+IFNlbnQ6IE1vbmRheSwgU2VwdGVtYmVyIDIyLCAy
MDE0IDY6MDIgUE0NCj4gVG86IFpodSBSaWNoYXJkLVI2NTAzNw0KPiBDYzogbGludXgtcGNpLW93
bmVyQHZnZXIua2VybmVsLm9yZzsgc3RhYmxlQHZnZXIua2VybmVsLm9yZzsgbGludXgtDQo+IHBj
aUB2Z2VyLmtlcm5lbC5vcmcNCj4gU3ViamVjdDogUmU6IFtQQVRDSCBSRkMgMi8yXSBQQ0k6IGlt
eDY6IGFkZCBpbXg2c3ggcGNpZSBzdXBwb3J0DQo+IA0KPiBIaSBSaWNoYXJkLA0KPiANCj4gVGhp
cyBjb21taXQgc21hc2hlcyBsb3RzIG9mIHRoaW5ncyB0b2dldGhlci4gSXQgd291bGQgYmUgbXVj
aCBlYXNpZXIgdG8gcmV2aWV3DQo+IHRoaXMgaWYgdGhlIGNoYW5nZXMgd2VyZSBicm9rZW4gb3V0
IGFwcHJvcHJpYXRlbHkuDQo+IA0KPiBBbHNvIHdoeSBhcmUgeW91IHNlbmRpbmcgUkZDIHBhdGNo
ZXMgdG8gc3RhYmxlPw0KPiANCj4gQSBmZXcgcXVpY2sgY29tbWVudHMgYmVsb3csIHRoaXMgaXNu
J3QgYSBmdWxsIHJldmlldyB5ZXQuDQo+IA0KW1JpY2hhcmRdIFRoaXMgY29tbWVudCBpcyBtaXNz
aW5nIGluIGxhc3QgcmVwbHkuIA0KT2ssIGNvbW1pdCB3b3VsZCBiZSBzZXBhcmF0ZWQgaW4gdGhl
IG5leHQgcmV2aWV3LWFyb3VuZC4gDQpTdGFibGUgaXMgb25lIG1pc3Rha2Ugd2hlbiBJIGNvcHkv
cGFzdCB0aGUgLS1jYyBtYWlsIGxpc3QuIEl0IHdvdWxkIGJlIHJlbW92ZWQgbGF0ZXIuDQoNCkJl
c3QgUmVnYXJkcw0KUmljaGFyZCBaaHUNCg0KPiBBbSBNb250YWcsIGRlbiAyMi4wOS4yMDE0LCAx
NzowMSArMDgwMCBzY2hyaWViIFJpY2hhcmQgWmh1Og0KPiA+IC0gaW14NnN4IHBjaWUgaGFzIGl0
cyBvd24gc3RhbmRhbG9uZSBwY2llIHBvd2VyIHN1cHBseS4NCj4gPiBJbiBvcmRlciB0byB0dXJu
IG9uIHRoZSBpbXg2c3ggcGNpZSBwb3dlciBkdXJpbmcgaW5pdGlhbGl6YXRpb24uIEFkZA0KPiA+
IHRoZSBwY2llIHJlZ3VsYXRvciBhbmQgdGhlIGdwYyByZWdtYXAgaW50byB0aGUgaW14NnN4IHBj
aWUgc3RydWN0dXJlLg0KPiA+IC0gaW14NnN4IHBjaWUgaGFzIHRoZSBuZXcgYWRkZWQgcmVzZXQg
bWVjaGFuaXNtLCBhZGQgdGhlIHJlc2V0DQo+ID4gb3BlcmF0aW9ucyBpbnRvIHRoZSBpbml0aWFs
aXphdGlvbi4NCj4gPiAtIGFub3RoZXIgZGlzX2F4aSBjbGsgaXMgbWFuZGF0b3J5IHJlcXVpcmVk
IGJ5IGlteDZzeCBwY2llLg0KPiA+IEFkZCBvbmUgbmV3IGNsayBuYW1lZCBwY2llX3NlYyBpbnRv
IGlteDZfcGNpZSBzdHJ1Y3R1cmUuDQo+ID4gLSBwY2llX3JlZl8xMjVtIGlzIG5vdCB1c2VkIGFz
IHBjaWVfcGh5IGNsayBhbnltb3JlIG9uIGlteDZzeC4NCj4gPiBUaGUgcGFyZW50IGNsayAocGNp
ZV9yZWYpIG9mIHRoZSBwY2llX2J1cyhsdmRzMV9nYXRlKSBpcyB1c2VkIGFzDQo+ID4gcGNpZV9w
aHkgY2xrLg0KPiANCj4gWW91IHJlbW92ZSB0aGlzIGNsb2NrIGZyb20gdGhlIGJpbmRpbmcuIEkg
ZG9uJ3Qgc2VlIGEgcmVhc29uIHdoeSwganVzdCBmaWxsIGluDQo+IHBjaWVfcmVmIGZvciBib3Ro
IHBjaWVfYnVzIGFuZCBwY2llX3BoeS4gTm8gbmVlZCB0byBpbXBsZW1lbnQgZGlmZmVyZW50IGNv
ZGUNCj4gcGF0aHMgZm9yIHRoaXMuDQo+IA0KPiA+IC0gUmVnaXN0ZXIgb25lIFBNIGNhbGwtYmFj
aywgZW50ZXIvZXhpdCBMMiBzdGF0ZSBvZiB0aGUgQVNQTSBkdXJpbmcNCj4gPiBzeXN0ZW0gc3Vz
cGVuZC9yZXN1bWUuDQo+ID4gLSB3YWl0IHRoZSBjbG9ja3MgdG8gc3RhYmlsaXplIGFmdGVyIHRo
ZSBwY2llX3JlZl9lbg0KPiA+IChJTVg2UV9HUFIxX1BDSUVfUkVGX0NMS19FTikgaXMgc2V0Lg0K
PiANCj4gDQo+ID4gU2lnbmVkLW9mZi1ieTogUmljaGFyZCBaaHUgPHI2NTAzN0BmcmVlc2NhbGUu
Y29tPg0KPiA+IC0tLQ0KPiA+ICBhcmNoL2FybS9ib290L2R0cy9pbXg2c3gtc2RiLmR0cyAgICAg
ICAgICAgIHwgIDE1ICsrDQo+ID4gIGFyY2gvYXJtL2Jvb3QvZHRzL2lteDZzeC5kdHNpICAgICAg
ICAgICAgICAgfCAgMzMgKystLQ0KPiA+ICBhcmNoL2FybS9tYWNoLWlteC9LY29uZmlnICAgICAg
ICAgICAgICAgICAgIHwgICAxICsNCj4gPiAgZHJpdmVycy9wY2kvaG9zdC9wY2ktaW14Ni5jICAg
ICAgICAgICAgICAgICB8IDIyOCArKysrKysrKysrKysrKysrKysrKysrKystDQo+IC0tLQ0KPiA+
ICBpbmNsdWRlL2xpbnV4L21mZC9zeXNjb24vaW14NnEtaW9tdXhjLWdwci5oIHwgIDE0ICsrDQo+
ID4gIDUgZmlsZXMgY2hhbmdlZCwgMjQ5IGluc2VydGlvbnMoKyksIDQyIGRlbGV0aW9ucygtKQ0K
PiA+DQo+ID4gZGlmZiAtLWdpdCBhL2FyY2gvYXJtL2Jvb3QvZHRzL2lteDZzeC1zZGIuZHRzDQo+
ID4gYi9hcmNoL2FybS9ib290L2R0cy9pbXg2c3gtc2RiLmR0cw0KPiA+IGluZGV4IGEzOTgwZDku
LjgzZDA4OTIgMTAwNjQ0DQo+ID4gLS0tIGEvYXJjaC9hcm0vYm9vdC9kdHMvaW14NnN4LXNkYi5k
dHMNCj4gPiArKysgYi9hcmNoL2FybS9ib290L2R0cy9pbXg2c3gtc2RiLmR0cw0KPiA+IEBAIC0y
NTEsNiArMjUxLDE0IEBADQo+ID4gIAl9Ow0KPiA+ICB9Ow0KPiA+DQo+ID4gKyZwY2llIHsNCj4g
PiArCXBpbmN0cmwtbmFtZXMgPSAiZGVmYXVsdCI7DQo+ID4gKwlwaW5jdHJsLTAgPSA8JnBpbmN0
cmxfcGNpZT47DQo+ID4gKwlwb3dlci1vbi1ncGlvID0gPCZncGlvMiAxIDA+Ow0KPiANCj4gTm8g
c3VjaCBHUElPIGluIHRoZSBiaW5kaW5nLg0KPiANCj4gPiArCXJlc2V0LWdwaW8gPSA8JmdwaW8y
IDAgMD47DQo+ID4gKwlzdGF0dXMgPSAib2theSI7DQo+ID4gK307DQo+ID4gKw0KPiA+ICAmc3Np
MiB7DQo+ID4gIAlzdGF0dXMgPSAib2theSI7DQo+ID4gIH07DQo+ID4gQEAgLTM2NSw2ICszNzMs
MTMgQEANCj4gPiAgCQkJPjsNCj4gPiAgCQl9Ow0KPiA+DQo+ID4gKwkJcGluY3RybF9wY2llOiBw
Y2llZ3JwIHsNCj4gPiArCQkJZnNsLHBpbnMgPSA8DQo+ID4gKwkJCQlNWDZTWF9QQURfRU5FVDFf
Q09MX19HUElPMl9JT18wIDB4MTcwNTkNCj4gPiArCQkJCU1YNlNYX1BBRF9FTkVUMV9DUlNfX0dQ
SU8yX0lPXzEJMHgxNzA1OQ0KPiA+ICsJCQk+Ow0KPiA+ICsJCX07DQo+ID4gKw0KPiA+ICAJCXBp
bmN0cmxfdmNjX3NkMzogdmNjc2QzZ3JwIHsNCj4gPiAgCQkJZnNsLHBpbnMgPSA8DQo+ID4gIAkJ
CQlNWDZTWF9QQURfS0VZX0NPTDFfX0dQSU8yX0lPXzExCQkweDE3MDU5DQo+ID4gZGlmZiAtLWdp
dCBhL2FyY2gvYXJtL2Jvb3QvZHRzL2lteDZzeC5kdHNpDQo+ID4gYi9hcmNoL2FybS9ib290L2R0
cy9pbXg2c3guZHRzaSBpbmRleCBmNGI5ZGE2Li5lYzM0Njk4IDEwMDY0NA0KPiA+IC0tLSBhL2Fy
Y2gvYXJtL2Jvb3QvZHRzL2lteDZzeC5kdHNpDQo+ID4gKysrIGIvYXJjaC9hcm0vYm9vdC9kdHMv
aW14NnN4LmR0c2kNCj4gPiBAQCAtNjg5LDkgKzY4OSwxMSBAQA0KPiA+ICAJCQl9Ow0KPiA+DQo+
ID4gIAkJCWdwYzogZ3BjQDAyMGRjMDAwIHsNCj4gPiAtCQkJCWNvbXBhdGlibGUgPSAiZnNsLGlt
eDZzeC1ncGMiLCAiZnNsLGlteDZxLWdwYyI7DQo+ID4gKwkJCQljb21wYXRpYmxlID0gImZzbCxp
bXg2c3gtZ3BjIiwNCj4gPiArCQkJCQkgICAgICJmc2wsaW14NnEtZ3BjIiwgInN5c2NvbiI7DQo+
ID4gIAkJCQlyZWcgPSA8MHgwMjBkYzAwMCAweDQwMDA+Ow0KPiA+ICAJCQkJaW50ZXJydXB0cyA9
IDxHSUNfU1BJIDg5IElSUV9UWVBFX0xFVkVMX0hJR0g+Ow0KPiA+ICsJCQkJcGNpZS1zdXBwbHkg
PSA8JnJlZ19wY2llPjsNCj4gPiAgCQkJfTsNCj4gPg0KPiA+ICAJCQlpb211eGM6IGlvbXV4Y0Aw
MjBlMDAwMCB7DQo+ID4gQEAgLTExODgsMjAgKzExOTAsMjMgQEANCj4gPiAgCQkJI2FkZHJlc3Mt
Y2VsbHMgPSA8Mz47DQo+ID4gIAkJCSNzaXplLWNlbGxzID0gPDI+Ow0KPiA+ICAJCQlkZXZpY2Vf
dHlwZSA9ICJwY2kiOw0KPiA+IC0JCQkJICAvKiBjb25maWd1cmF0aW9uIHNwYWNlICovDQo+ID4g
LQkJCXJhbmdlcyA9IDwweDAwMDAwODAwIDAgMHgwOGYwMDAwMCAweDA4ZjAwMDAwIDAgMHgwMDA4
MDAwMA0KPiA+IC0JCQkJICAvKiBkb3duc3RyZWFtIEkvTyAqLw0KPiA+IC0JCQkJICAweDgxMDAw
MDAwIDAgMCAgICAgICAgICAweDA4ZjgwMDAwIDAgMHgwMDAxMDAwMA0KPiA+IC0JCQkJICAvKiBu
b24tcHJlZmV0Y2hhYmxlIG1lbW9yeSAqLw0KPiA+IC0JCQkJICAweDgyMDAwMDAwIDAgMHgwODAw
MDAwMCAweDA4MDAwMDAwIDAgMHgwMGYwMDAwMD47DQo+ID4gKwkJCXJhbmdlcyA9IDwweDAwMDAw
ODAwIDAgMHgwMWYwMDAwMCAweDA4ZjAwMDAwIDAgMHgwMDA4MDAwMCAvKg0KPiBjb25maWd1cmF0
aW9uIHNwYWNlICovDQo+ID4gKwkJCQkgIDB4ODEwMDAwMDAgMCAwICAgICAgICAgIDB4MDhmODAw
MDAgMCAweDAwMDEwMDAwIC8qDQo+IGRvd25zdHJlYW0gSS9PICovDQo+ID4gKwkJCQkgIDB4ODIw
MDAwMDAgMCAweDAxMDAwMDAwIDB4MDgwMDAwMDAgMCAweDAwZjAwMDAwPjsgLyoNCj4gPiArbm9u
LXByZWZldGNoYWJsZSBtZW1vcnkgKi8NCj4gPiAgCQkJbnVtLWxhbmVzID0gPDE+Ow0KPiA+IC0J
CQlpbnRlcnJ1cHRzID0gPEdJQ19TUEkgMTIzIElSUV9UWVBFX0xFVkVMX0hJR0g+Ow0KPiA+IC0J
CQljbG9ja3MgPSA8JmNsa3MgSU1YNlNYX0NMS19QQ0lFX1JFRl8xMjVNPiwNCj4gPiAtCQkJCSA8
JmNsa3MgSU1YNlNYX0NMS19QQ0lFX0FYST4sDQo+ID4gLQkJCQkgPCZjbGtzIElNWDZTWF9DTEtf
TFZEUzFfT1VUPiwNCj4gPiAtCQkJCSA8JmNsa3MgSU1YNlNYX0NMS19ESVNQTEFZX0FYST47DQo+
ID4gLQkJCWNsb2NrLW5hbWVzID0gInBjaWVfcmVmXzEyNW0iLCAicGNpZV9heGkiLA0KPiA+IC0J
CQkJICAgICAgImx2ZHNfZ2F0ZSIsICJkaXNwbGF5X2F4aSI7DQo+ID4gKwkJCWludGVycnVwdHMg
PSA8R0lDX1NQSSAxMjAgSVJRX1RZUEVfTEVWRUxfSElHSD47DQo+ID4gKwkJCWludGVycnVwdC1u
YW1lcyA9ICJtc2kiOw0KPiA+ICsJCQkjaW50ZXJydXB0LWNlbGxzID0gPDE+Ow0KPiA+ICsJCQlp
bnRlcnJ1cHQtbWFwLW1hc2sgPSA8MCAwIDAgMHg3PjsNCj4gPiArCQkJaW50ZXJydXB0LW1hcCA9
IDwwIDAgMCAxICZpbnRjIEdJQ19TUEkgMTIzIElSUV9UWVBFX0xFVkVMX0hJR0g+LA0KPiA+ICsJ
CQkgICAgICAgICAgICAgICAgPDAgMCAwIDIgJmludGMgR0lDX1NQSSAxMjIgSVJRX1RZUEVfTEVW
RUxfSElHSD4sDQo+ID4gKwkJCSAgICAgICAgICAgICAgICA8MCAwIDAgMyAmaW50YyBHSUNfU1BJ
IDEyMSBJUlFfVFlQRV9MRVZFTF9ISUdIPiwNCj4gPiArCQkJICAgICAgICAgICAgICAgIDwwIDAg
MCA0ICZpbnRjIEdJQ19TUEkgMTIwIElSUV9UWVBFX0xFVkVMX0hJR0g+Ow0KPiA+ICsJCQljbG9j
a3MgPSA8JmNsa3MgSU1YNlNYX0NMS19QQ0lFX0FYST4sDQo+ID4gKwkJCQkgPCZjbGtzIElNWDZT
WF9DTEtfRElTUExBWV9BWEk+LA0KPiA+ICsJCQkJIDwmY2xrcyBJTVg2U1hfQ0xLX0xWRFMxX09V
VD47DQo+ID4gKwkJCWNsb2NrLW5hbWVzID0gInBjaWUiLCAicGNpZV9zZWMiLCAicGNpZV9idXMi
Ow0KPiA+ICsJCQlwY2llLXN1cHBseSA9IDwmcmVnX3BjaWU+Ow0KPiA+ICAJCQlzdGF0dXMgPSAi
ZGlzYWJsZWQiOw0KPiA+ICAJCX07DQo+ID4gIAl9Ow0KPiA+IGRpZmYgLS1naXQgYS9hcmNoL2Fy
bS9tYWNoLWlteC9LY29uZmlnIGIvYXJjaC9hcm0vbWFjaC1pbXgvS2NvbmZpZw0KPiA+IGluZGV4
IGJlOWE1MWEuLjBhMDU1ZjAgMTAwNjQ0DQo+ID4gLS0tIGEvYXJjaC9hcm0vbWFjaC1pbXgvS2Nv
bmZpZw0KPiA+ICsrKyBiL2FyY2gvYXJtL21hY2gtaW14L0tjb25maWcNCj4gPiBAQCAtNzE4LDYg
KzcxOCw3IEBAIGNvbmZpZyBTT0NfSU1YNlNMDQo+ID4NCj4gPiAgY29uZmlnIFNPQ19JTVg2U1gN
Cj4gPiAgCWJvb2wgImkuTVg2IFNvbG9YIHN1cHBvcnQiDQo+ID4gKwlzZWxlY3QgUENJX0RPTUFJ
TlMgaWYgUENJDQo+ID4gIAlzZWxlY3QgUElOQ1RSTF9JTVg2U1gNCj4gPiAgCXNlbGVjdCBTT0Nf
SU1YNg0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvcGNpL2hvc3QvcGNpLWlteDYuYyBi
L2RyaXZlcnMvcGNpL2hvc3QvcGNpLWlteDYuYw0KPiA+IGluZGV4IDIzM2ZlOGEuLmM5YjJmNjkg
MTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9wY2kvaG9zdC9wY2ktaW14Ni5jDQo+ID4gKysrIGIv
ZHJpdmVycy9wY2kvaG9zdC9wY2ktaW14Ni5jDQo+ID4gQEAgLTE4LDEyICsxOCwxNiBAQA0KPiA+
ICAjaW5jbHVkZSA8bGludXgvbWZkL3N5c2Nvbi5oPg0KPiA+ICAjaW5jbHVkZSA8bGludXgvbWZk
L3N5c2Nvbi9pbXg2cS1pb211eGMtZ3ByLmg+DQo+ID4gICNpbmNsdWRlIDxsaW51eC9tb2R1bGUu
aD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L29mX2FkZHJlc3MuaD4NCj4gPiArI2luY2x1ZGUgPGxp
bnV4L29mX2RldmljZS5oPg0KPiA+ICAjaW5jbHVkZSA8bGludXgvb2ZfZ3Bpby5oPg0KPiA+ICAj
aW5jbHVkZSA8bGludXgvcGNpLmg+DQo+ID4gICNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZp
Y2UuaD4NCj4gPiAgI2luY2x1ZGUgPGxpbnV4L3JlZ21hcC5oPg0KPiA+ICsjaW5jbHVkZSA8bGlu
dXgvcmVndWxhdG9yL2NvbnN1bWVyLmg+DQo+ID4gICNpbmNsdWRlIDxsaW51eC9yZXNvdXJjZS5o
Pg0KPiA+ICAjaW5jbHVkZSA8bGludXgvc2lnbmFsLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9z
eXNjb3JlX29wcy5oPg0KPiA+ICAjaW5jbHVkZSA8bGludXgvdHlwZXMuaD4NCj4gPiAgI2luY2x1
ZGUgPGxpbnV4L2ludGVycnVwdC5oPg0KPiA+DQo+ID4gQEAgLTMxLDE1ICszNSwzMiBAQA0KPiA+
DQo+ID4gICNkZWZpbmUgdG9faW14Nl9wY2llKHgpCWNvbnRhaW5lcl9vZih4LCBzdHJ1Y3QgaW14
Nl9wY2llLCBwcCkNCj4gPg0KPiA+ICsvKiBUaGUgcGNpZSB3aG8gaGF2ZSBzdGFuZGFsb25lIHBv
d2VyIGRvbWFpbiAqLw0KPiA+ICsjZGVmaW5lIFBDSUVfUEhZX0hBU19QV1JfRE9NQUlOCQlCSVQo
MCkNCj4gPiArDQo+ID4gK3N0cnVjdCBpbXhfcGNpZV9kYXRhIHsNCj4gPiArCXVuc2lnbmVkIGlu
dCBmbGFnczsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaW14X3Bj
aWVfZGF0YSBpbXg2c3hfcGNpZV9kYXRhID0gew0KPiA+ICsJLmZsYWdzID0gUENJRV9QSFlfSEFT
X1BXUl9ET01BSU4sDQo+ID4gK307DQo+ID4gKw0KPiA+ICBzdHJ1Y3QgaW14Nl9wY2llIHsNCj4g
PiAgCWludAkJCXJlc2V0X2dwaW87DQo+ID4gKwlpbnQJCQlwb3dlcl9vbl9ncGlvOw0KPiA+ICsJ
Y29uc3Qgc3RydWN0CQlpbXhfcGNpZV9kYXRhICpkYXRhOw0KPiA+ICAJc3RydWN0IGNsawkJKnBj
aWVfYnVzOw0KPiA+ICAJc3RydWN0IGNsawkJKnBjaWVfcGh5Ow0KPiA+ICsJc3RydWN0IGNsawkJ
KnBjaWVfc2VjOw0KPiA+ICAJc3RydWN0IGNsawkJKnBjaWU7DQo+ID4gIAlzdHJ1Y3QgcGNpZV9w
b3J0CXBwOw0KPiA+ICAJc3RydWN0IHJlZ21hcAkJKmlvbXV4Y19ncHI7DQo+ID4gKwlzdHJ1Y3Qg
cmVnbWFwCQkqZ3BjX2lwc19yZWc7DQo+ID4gKwlzdHJ1Y3QgcmVndWxhdG9yCSpwY2llX3JlZ3Vs
YXRvcjsNCj4gPiAgCXZvaWQgX19pb21lbQkJKm1lbV9iYXNlOw0KPiA+ICB9Ow0KPiA+ICtzdGF0
aWMgc3RydWN0IGlteDZfcGNpZSAqaW14Nl9wY2llOw0KPiA+DQo+ID4gIC8qIFBDSWUgUm9vdCBD
b21wbGV4IHJlZ2lzdGVycyAobWVtb3J5LW1hcHBlZCkgKi8NCj4gPiAgI2RlZmluZSBQQ0lFX1JD
X0xDUgkJCQkweDdjDQo+ID4gQEAgLTc3LDYgKzk4LDExIEBAIHN0cnVjdCBpbXg2X3BjaWUgew0K
PiA+ICAjZGVmaW5lIFBIWV9SWF9PVlJEX0lOX0xPX1JYX0RBVEFfRU4gKDEgPDwgNSkgICNkZWZp
bmUNCj4gPiBQSFlfUlhfT1ZSRF9JTl9MT19SWF9QTExfRU4gKDEgPDwgMykNCj4gPg0KPiA+ICtz
dGF0aWMgaW5saW5lIGJvb2wgaXNfaW14NnN4X3BjaWUoc3RydWN0IGlteDZfcGNpZSAqaW14Nl9w
Y2llKSB7DQo+ID4gKwlyZXR1cm4gaW14Nl9wY2llLT5kYXRhID09ICZpbXg2c3hfcGNpZV9kYXRh
OyB9DQo+ID4gKw0KPiA+ICBzdGF0aWMgaW50IHBjaWVfcGh5X3BvbGxfYWNrKHZvaWQgX19pb21l
bSAqZGJpX2Jhc2UsIGludCBleHBfdmFsKSAgew0KPiA+ICAJdTMyIHZhbDsNCj4gPiBAQCAtMjU3
LDEwICsyODMsMjEgQEAgc3RhdGljIGludCBpbXg2X3BjaWVfZGVhc3NlcnRfY29yZV9yZXNldChz
dHJ1Y3QNCj4gcGNpZV9wb3J0ICpwcCkNCj4gPiAgCXN0cnVjdCBpbXg2X3BjaWUgKmlteDZfcGNp
ZSA9IHRvX2lteDZfcGNpZShwcCk7DQo+ID4gIAlpbnQgcmV0Ow0KPiA+DQo+ID4gLQlyZXQgPSBj
bGtfcHJlcGFyZV9lbmFibGUoaW14Nl9wY2llLT5wY2llX3BoeSk7DQo+ID4gLQlpZiAocmV0KSB7
DQo+ID4gLQkJZGV2X2VycihwcC0+ZGV2LCAidW5hYmxlIHRvIGVuYWJsZSBwY2llX3BoeSBjbG9j
a1xuIik7DQo+ID4gLQkJZ290byBlcnJfcGNpZV9waHk7DQo+ID4gKwlpZiAoZ3Bpb19pc192YWxp
ZChpbXg2X3BjaWUtPnBvd2VyX29uX2dwaW8pKQ0KPiA+ICsJCWdwaW9fc2V0X3ZhbHVlKGlteDZf
cGNpZS0+cG93ZXJfb25fZ3BpbywgMSk7DQo+ID4gKw0KPiANCj4gSSB3b24ndCBhbGxvdyB0aGlz
IHRvIGNyZWVwIGluIGFnYWluLiBUaGlzIG5lZWRzIHRvIGJlIGEgcHJvcGVyIHJlZ3VsYXRvciwg
bm90DQo+IHNvbWUga2luZCBvZiBncGlvLg0KPiANCj4gPiArCWlmIChpc19pbXg2c3hfcGNpZShp
bXg2X3BjaWUpKSB7DQo+ID4gKwkJcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxlKGlteDZfcGNpZS0+
cGNpZV9zZWMpOw0KPiA+ICsJCWlmIChyZXQpIHsNCj4gPiArCQkJZGV2X2VycihwcC0+ZGV2LCAi
dW5hYmxlIHRvIGVuYWJsZSBwY2llX3NlYyBjbGsuXG4iKTsNCj4gPiArCQkJZ290byBlcnJfcGNp
ZV9zZWM7DQo+ID4gKwkJfQ0KPiA+ICsJfSBlbHNlIHsNCj4gPiArCQlyZXQgPSBjbGtfcHJlcGFy
ZV9lbmFibGUoaW14Nl9wY2llLT5wY2llX3BoeSk7DQo+ID4gKwkJaWYgKHJldCkgew0KPiA+ICsJ
CQlkZXZfZXJyKHBwLT5kZXYsICJ1bmFibGUgdG8gZW5hYmxlIHBjaWVfcGh5IGNsb2NrXG4iKTsN
Cj4gPiArCQkJZ290byBlcnJfcGNpZV9waHk7DQo+ID4gKwkJfQ0KPiA+ICAJfQ0KPiA+DQo+ID4g
IAlyZXQgPSBjbGtfcHJlcGFyZV9lbmFibGUoaW14Nl9wY2llLT5wY2llX2J1cyk7DQo+ID4gQEAg
LTI3NSwyOCArMzEyLDUwIEBAIHN0YXRpYyBpbnQgaW14Nl9wY2llX2RlYXNzZXJ0X2NvcmVfcmVz
ZXQoc3RydWN0DQo+IHBjaWVfcG9ydCAqcHApDQo+ID4gIAkJZ290byBlcnJfcGNpZTsNCj4gPiAg
CX0NCj4gPg0KPiA+ICsJaWYgKGlzX2lteDZzeF9wY2llKGlteDZfcGNpZSkpIHsNCj4gPiArCQly
ZWdtYXBfdXBkYXRlX2JpdHMoaW14Nl9wY2llLT5pb211eGNfZ3ByLCBJT01VWENfR1BSMTIsDQo+
ID4gKwkJCQlJTVg2U1hfR1BSMTJfUENJRV9URVNUX1BELA0KPiA+ICsJCQkJSU1YNlNYX0dQUjEy
X1BDSUVfVEVTVF9QRF9DTFIpOw0KPiA+ICsJfSBlbHNlIHsNCj4gPiArCQkvKiBwb3dlciB1cCBj
b3JlIHBoeSBhbmQgZW5hYmxlIHJlZiBjbG9jayAqLw0KPiA+ICsJCXJlZ21hcF91cGRhdGVfYml0
cyhpbXg2X3BjaWUtPmlvbXV4Y19ncHIsIElPTVVYQ19HUFIxLA0KPiA+ICsJCQkJSU1YNlFfR1BS
MV9QQ0lFX1RFU1RfUEQsIDAgPDwgMTgpOw0KPiA+ICsJCXJlZ21hcF91cGRhdGVfYml0cyhpbXg2
X3BjaWUtPmlvbXV4Y19ncHIsIElPTVVYQ19HUFIxLA0KPiA+ICsJCQkJSU1YNlFfR1BSMV9QQ0lF
X1JFRl9DTEtfRU4sIDEgPDwgMTYpOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiAgCS8qIGFsbG93IHRo
ZSBjbG9ja3MgdG8gc3RhYmlsaXplICovDQo+ID4gIAl1c2xlZXBfcmFuZ2UoMjAwLCA1MDApOw0K
PiA+DQo+ID4gLQkvKiBwb3dlciB1cCBjb3JlIHBoeSBhbmQgZW5hYmxlIHJlZiBjbG9jayAqLw0K
PiA+IC0JcmVnbWFwX3VwZGF0ZV9iaXRzKGlteDZfcGNpZS0+aW9tdXhjX2dwciwgSU9NVVhDX0dQ
UjEsDQo+ID4gLQkJCUlNWDZRX0dQUjFfUENJRV9URVNUX1BELCAwIDw8IDE4KTsNCj4gPiAtCXJl
Z21hcF91cGRhdGVfYml0cyhpbXg2X3BjaWUtPmlvbXV4Y19ncHIsIElPTVVYQ19HUFIxLA0KPiA+
IC0JCQlJTVg2UV9HUFIxX1BDSUVfUkVGX0NMS19FTiwgMSA8PCAxNik7DQo+ID4gLQ0KPiA+ICAJ
LyogU29tZSBib2FyZHMgZG9uJ3QgaGF2ZSBQQ0llIHJlc2V0IEdQSU8uICovDQo+ID4gIAlpZiAo
Z3Bpb19pc192YWxpZChpbXg2X3BjaWUtPnJlc2V0X2dwaW8pKSB7DQo+ID4gIAkJZ3Bpb19zZXRf
dmFsdWUoaW14Nl9wY2llLT5yZXNldF9ncGlvLCAwKTsNCj4gPiAgCQltc2xlZXAoMTAwKTsNCj4g
PiAgCQlncGlvX3NldF92YWx1ZShpbXg2X3BjaWUtPnJlc2V0X2dwaW8sIDEpOw0KPiA+ICAJfQ0K
PiA+ICsNCj4gPiArCS8qDQo+ID4gKwkgKiBpTVg2U1ggUENJZSBoYXMgdGhlIHN0YW5kLWFsb25l
IHBvd2VyIGRvbWFpbi4NCj4gPiArCSAqIHJlZmVyIHRvIHRoZSBpbml0aWFsaXphdGlvbiBmb3Ig
aU1YNlNYIFBDSWUsDQo+ID4gKwkgKiByZWxlYXNlIHRoZSBQQ0llIFBIWSByZXNldCBoZXJlLA0K
PiA+ICsJICogYmVmb3JlIExUU1NNIGVuYWJsZSBpcyBzZXQuDQo+ID4gKwkgKi8NCj4gPiArCWlm
IChpc19pbXg2c3hfcGNpZShpbXg2X3BjaWUpKQ0KPiA+ICsJCXJlZ21hcF91cGRhdGVfYml0cyhp
bXg2X3BjaWUtPmlvbXV4Y19ncHIsIElPTVVYQ19HUFI1LA0KPiA+ICsJCQkJSU1YNlNYX0dQUjVf
UENJRV9CVE5SU1QsDQo+ID4gKwkJCQlJTVg2U1hfR1BSNV9QQ0lFX0JUTlJTVF9DTFIpOw0KPiA+
ICsNCj4gPiAgCXJldHVybiAwOw0KPiA+DQo+ID4gIGVycl9wY2llOg0KPiA+ICAJY2xrX2Rpc2Fi
bGVfdW5wcmVwYXJlKGlteDZfcGNpZS0+cGNpZV9idXMpOw0KPiA+ICBlcnJfcGNpZV9idXM6DQo+
ID4gLQljbGtfZGlzYWJsZV91bnByZXBhcmUoaW14Nl9wY2llLT5wY2llX3BoeSk7DQo+ID4gKwlp
ZiAoIWlzX2lteDZzeF9wY2llKGlteDZfcGNpZSkpDQo+ID4gKwkJY2xrX2Rpc2FibGVfdW5wcmVw
YXJlKGlteDZfcGNpZS0+cGNpZV9waHkpOw0KPiA+ICBlcnJfcGNpZV9waHk6DQo+ID4gKwlpZiAo
aXNfaW14NnN4X3BjaWUoaW14Nl9wY2llKSkNCj4gPiArCQljbGtfZGlzYWJsZV91bnByZXBhcmUo
aW14Nl9wY2llLT5wY2llX3NlYyk7DQo+ID4gK2Vycl9wY2llX3NlYzoNCj4gPiAgCXJldHVybiBy
ZXQ7DQo+ID4NCj4gPiAgfQ0KPiA+IEBAIC0zMDQsMTUgKzM2MywzOCBAQCBlcnJfcGNpZV9waHk6
DQo+ID4gIHN0YXRpYyB2b2lkIGlteDZfcGNpZV9pbml0X3BoeShzdHJ1Y3QgcGNpZV9wb3J0ICpw
cCkgIHsNCj4gPiAgCXN0cnVjdCBpbXg2X3BjaWUgKmlteDZfcGNpZSA9IHRvX2lteDZfcGNpZShw
cCk7DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsNCj4gPiArCS8qDQo+ID4gKwkgKiBpTVg2U1ggUENJ
ZSBoYXMgdGhlIHN0YW5kLWFsb25lIHBvd2VyIGRvbWFpbg0KPiA+ICsJICogYWRkIHRoZSBpbml0
aWFsaXphdGlvbiBoZXJlIGZvciBpTVg2U1ggUENJZS4NCj4gPiArCSAqLw0KPiA+ICsJaWYgKGlz
X2lteDZzeF9wY2llKGlteDZfcGNpZSkpIHsNCj4gPiArCQkvKiBGb3JjZSBQQ0llIFBIWSByZXNl
dCAqLw0KPiA+ICsJCXJlZ21hcF91cGRhdGVfYml0cyhpbXg2X3BjaWUtPmlvbXV4Y19ncHIsIElP
TVVYQ19HUFI1LA0KPiA+ICsJCQkJSU1YNlNYX0dQUjVfUENJRV9CVE5SU1QsDQo+ID4gKwkJCQlJ
TVg2U1hfR1BSNV9QQ0lFX0JUTlJTVCk7DQo+ID4gKw0KPiA+ICsJCXJlZ21hcF91cGRhdGVfYml0
cyhpbXg2X3BjaWUtPmdwY19pcHNfcmVnLCAwLCAxIDw8IDcsIDEgPDwgNyk7DQo+IA0KPiBXaGF0
IGlzIHRoaXM/IElzIHRoaXMgYSByZWd1bGF0b3I/IElmIHNvLCB3aHkgaXNuJ3QgaXQgYWJzdHJh
Y3RlZCBhcyBhIHByb3Blcg0KPiByZWd1bGF0b3I/DQo+IA0KPiA+ICsJCS8qIFBvd2VyIHVwIFBD
SWUgUEhZLCBBTkFUT1BfUkVHX0NPUkUgb2Zmc2V0IDB4MTQwLCBiaXQxMy05ICovDQo+ID4gKwkJ
cmVndWxhdG9yX3NldF92b2x0YWdlKGlteDZfcGNpZS0+cGNpZV9yZWd1bGF0b3IsDQo+ID4gKwkJ
CQkxMTAwMDAwLCAxMTAwMDAwKTsNCj4gPiArCQlyZXQgPSByZWd1bGF0b3JfZW5hYmxlKGlteDZf
cGNpZS0+cGNpZV9yZWd1bGF0b3IpOw0KPiA+ICsJCWlmIChyZXQpDQo+ID4gKwkJCWRldl9pbmZv
KHBwLT5kZXYsICJmYWlsZWQgdG8gZW5hYmxlIHBjaWUgcmVndWxhdG9yLlxuIik7DQo+IA0KPiBU
aGlzIHJlZ3VsYXRvciBnZXRzIGVuYWJsZWQgaGVyZSwgYnV0IEkgZG9uJ3Qgc2VlIGFueSBwYXRo
IHdlcmUgd2Ugd291bGQNCj4gZGlzYWJsZSBpdC4gSXMgdGhpcyBhIGFsd2F5cy1vbiByZWd1bGF0
b3Igb3IgYXJlIHlvdSBzaW1wbHkgbWlzc2luZyB0aGUgY2FsbHMNCj4gdG8gZGlzYWJsZSBpdCBp
biB0aGUgcnVudGltZS1wbSBob29rcz8NCj4gDQo+ID4gKwkJcmVnbWFwX3VwZGF0ZV9iaXRzKGlt
eDZfcGNpZS0+aW9tdXhjX2dwciwgSU9NVVhDX0dQUjEyLA0KPiA+ICsJCQkJSU1YNlNYX0dQUjEy
X1JYX0VRX01BU0ssIElNWDZTWF9HUFIxMl9SWF9FUV8yKTsNCj4gPiArCX0NCj4gPg0KPiA+ICAJ
cmVnbWFwX3VwZGF0ZV9iaXRzKGlteDZfcGNpZS0+aW9tdXhjX2dwciwgSU9NVVhDX0dQUjEyLA0K
PiA+IC0JCQlJTVg2UV9HUFIxMl9QQ0lFX0NUTF8yLCAwIDw8IDEwKTsNCj4gPiArCQkJSU1YNlFf
R1BSMTJfUENJRV9DVExfMiwNCj4gPiArCQkJSU1YNlFfR1BSMTJfUENJRV9DVExfMl9DTFIpOw0K
PiA+DQo+ID4gIAkvKiBjb25maWd1cmUgY29uc3RhbnQgaW5wdXQgc2lnbmFsIHRvIHRoZSBwY2ll
IGN0cmwgYW5kIHBoeSAqLw0KPiA+ICAJcmVnbWFwX3VwZGF0ZV9iaXRzKGlteDZfcGNpZS0+aW9t
dXhjX2dwciwgSU9NVVhDX0dQUjEyLA0KPiA+ICAJCQlJTVg2UV9HUFIxMl9ERVZJQ0VfVFlQRSwg
UENJX0VYUF9UWVBFX1JPT1RfUE9SVCA8PCAxMik7DQo+ID4gIAlyZWdtYXBfdXBkYXRlX2JpdHMo
aW14Nl9wY2llLT5pb211eGNfZ3ByLCBJT01VWENfR1BSMTIsDQo+ID4gLQkJCUlNWDZRX0dQUjEy
X0xPU19MRVZFTCwgOSA8PCA0KTsNCj4gPiArCQkJSU1YNlFfR1BSMTJfTE9TX0xFVkVMLCBJTVg2
UV9HUFIxMl9MT1NfTEVWRUxfOSk7DQo+ID4NCj4gPiAgCXJlZ21hcF91cGRhdGVfYml0cyhpbXg2
X3BjaWUtPmlvbXV4Y19ncHIsIElPTVVYQ19HUFI4LA0KPiA+ICAJCQlJTVg2UV9HUFI4X1RYX0RF
RU1QSF9HRU4xLCAwIDw8IDApOyBAQCAtMzcwLDcgKzQ1Miw4IEBAIHN0YXRpYw0KPiBpbnQNCj4g
PiBpbXg2X3BjaWVfc3RhcnRfbGluayhzdHJ1Y3QgcGNpZV9wb3J0ICpwcCkNCj4gPg0KPiA+ICAJ
LyogU3RhcnQgTFRTU00uICovDQo+ID4gIAlyZWdtYXBfdXBkYXRlX2JpdHMoaW14Nl9wY2llLT5p
b211eGNfZ3ByLCBJT01VWENfR1BSMTIsDQo+ID4gLQkJCUlNWDZRX0dQUjEyX1BDSUVfQ1RMXzIs
IDEgPDwgMTApOw0KPiA+ICsJCQlJTVg2UV9HUFIxMl9QQ0lFX0NUTF8yLA0KPiA+ICsJCQlJTVg2
UV9HUFIxMl9QQ0lFX0NUTF8yKTsNCj4gPg0KPiA+ICAJcmV0ID0gaW14Nl9wY2llX3dhaXRfZm9y
X2xpbmsocHApOw0KPiA+ICAJaWYgKHJldCkNCj4gPiBAQCAtNTQ2LDEwICs2MjksNzMgQEAgc3Rh
dGljIGludCBfX2luaXQgaW14Nl9hZGRfcGNpZV9wb3J0KHN0cnVjdCBwY2llX3BvcnQNCj4gKnBw
LA0KPiA+ICAJcmV0dXJuIDA7DQo+ID4gIH0NCj4gPg0KPiA+ICtzdGF0aWMgY29uc3Qgc3RydWN0
IG9mX2RldmljZV9pZCBpbXg2X3BjaWVfb2ZfbWF0Y2hbXSA9IHsNCj4gPiArCXsgLmNvbXBhdGli
bGUgPSAiZnNsLGlteDZxLXBjaWUiLCB9LA0KPiA+ICsJeyAuY29tcGF0aWJsZSA9ICJmc2wsaW14
NnN4LXBjaWUiLCAuZGF0YSA9ICZpbXg2c3hfcGNpZV9kYXRhfSwNCj4gPiArCXt9LA0KPiA+ICt9
Ow0KPiA+ICtNT0RVTEVfREVWSUNFX1RBQkxFKG9mLCBpbXg2X3BjaWVfb2ZfbWF0Y2gpOw0KPiA+
ICsNCj4gPiArI2lmZGVmIENPTkZJR19QTV9TTEVFUA0KPiA+ICtzdGF0aWMgaW50IHBjaV9pbXhf
c3VzcGVuZCh2b2lkKQ0KPiA+ICt7DQo+ID4gKwlpbnQgcmMgPSAwOw0KPiA+ICsNCj4gPiArCWlm
IChpc19pbXg2c3hfcGNpZShpbXg2X3BjaWUpKSB7DQo+ID4gKwkJLyogUE1fVFVSTl9PRkYgKi8N
Cj4gPiArCQlyZWdtYXBfdXBkYXRlX2JpdHMoaW14Nl9wY2llLT5pb211eGNfZ3ByLCBJT01VWENf
R1BSMTIsDQo+ID4gKwkJCQlCSVQoMTYpLCAxIDw8IDE2KTsNCj4gPiArCQl1ZGVsYXkoMTApOw0K
PiA+ICsJCXJlZ21hcF91cGRhdGVfYml0cyhpbXg2X3BjaWUtPmlvbXV4Y19ncHIsIElPTVVYQ19H
UFIxMiwNCj4gPiArCQkJCUJJVCgxNiksIDAgPDwgMTYpOw0KPiANCj4gV2h5IGFyZSB0aGVyZSBu
byBkZWZpbmVzIGZvciB0aG9zZSBiaXRzPyBJIGNhbid0IHJlYWxseSB0ZWxsIHdoYXQncyBnb2lu
ZyBvbg0KPiBoZXJlLiBJcyB0aGlzIHNvbWUga2luZCBvZiBwb3dlciBnYXRpbmcgdGhlIFNvQyBw
YXJ0aXRpb24/IEluIHRoYXQgY2FzZSBpdA0KPiBzaG91bGQgcmVhbGx5IGJlIGltcGxlbWVudGVk
IGFzIGEgcG93ZXItZG9tYWluIGFuZCBub3QgYXMgc29tZSBraW5kIG9mIGFkLWhvYw0KPiBHUFIg
cmVnaXN0ZXIgYmFzaGluZy4NCj4gDQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0dXJuIHJjOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBwY2lfaW14X3Jlc3VtZSh2b2lkKQ0KPiA+
ICt7DQo+ID4gKwlzdHJ1Y3QgcGNpZV9wb3J0ICpwcCA9ICZpbXg2X3BjaWUtPnBwOw0KPiA+ICsN
Cj4gPiArCWlmIChpc19pbXg2c3hfcGNpZShpbXg2X3BjaWUpKSB7DQo+ID4gKwkJLyogcmVzZXQg
aU1YNlNYIFBDSWUgKi8NCj4gPiArCQlyZWdtYXBfdXBkYXRlX2JpdHMoaW14Nl9wY2llLT5pb211
eGNfZ3ByLA0KPiA+ICsJCQkJSU9NVVhDX0dQUjUsIEJJVCgxOCksIDEgPDwgMTgpOw0KPiA+ICsN
Cj4gPiArCQlyZWdtYXBfdXBkYXRlX2JpdHMoaW14Nl9wY2llLT5pb211eGNfZ3ByLA0KPiA+ICsJ
CQkJSU9NVVhDX0dQUjUsIEJJVCgxOCksIDAgPDwgMTgpOw0KPiA+ICsNCj4gPiArCQkvKg0KPiA+
ICsJCSAqIGNvbnRyb2xsZXIgbWF5YmUgdHVybiBvZmYsIHJlLWNvbmZpZ3VyZSBhZ2Fpbg0KPiA+
ICsJCSAqIFNldCB0aGUgQ0xBU1NfUkVWIG9mIFJDIENGRyBoZWFkZXIgdG8NCj4gPiArCQkgKiBQ
Q0lfQ0xBU1NfQlJJREdFX1BDSQ0KPiA+ICsJCSAqLw0KPiA+ICsJCXdyaXRlbChyZWFkbChwcC0+
ZGJpX2Jhc2UgKyBQQ0lfQ0xBU1NfUkVWSVNJT04pDQo+ID4gKwkJCXwgKFBDSV9DTEFTU19CUklE
R0VfUENJIDw8IDE2KSwNCj4gPiArCQkJcHAtPmRiaV9iYXNlICsgUENJX0NMQVNTX1JFVklTSU9O
KTsNCj4gPiArDQo+ID4gKwkJZHdfcGNpZV9zZXR1cF9yYyhwcCk7DQo+ID4gKw0KPiA+ICsJCS8q
IHJlc2V0IGlNWDZTWCBQQ0llICovDQo+ID4gKwkJcmVnbWFwX3VwZGF0ZV9iaXRzKGlteDZfcGNp
ZS0+aW9tdXhjX2dwciwNCj4gPiArCQkJCUlPTVVYQ19HUFI1LCBCSVQoMTgpLCAxIDw8IDE4KTsN
Cj4gPiArDQo+ID4gKwkJcmVnbWFwX3VwZGF0ZV9iaXRzKGlteDZfcGNpZS0+aW9tdXhjX2dwciwN
Cj4gPiArCQkJCUlPTVVYQ19HUFI1LCBCSVQoMTgpLCAwIDw8IDE4KTsNCj4gDQo+IFdoeSB0aGUg
ZG91YmxlIHJlc2V0Pw0KPiANCj4gPiArCX0NCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHN0
cnVjdCBzeXNjb3JlX29wcyBwY2lfaW14X3N5c2NvcmVfb3BzID0gew0KPiA+ICsJLnN1c3BlbmQg
PSBwY2lfaW14X3N1c3BlbmQsDQo+ID4gKwkucmVzdW1lID0gcGNpX2lteF9yZXN1bWUsDQo+ID4g
K307DQo+ID4gKyNlbmRpZg0KPiA+ICsNCj4gPiAgc3RhdGljIGludCBfX2luaXQgaW14Nl9wY2ll
X3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpICB7DQo+ID4gLQlzdHJ1Y3QgaW14
Nl9wY2llICppbXg2X3BjaWU7DQo+ID4gIAlzdHJ1Y3QgcGNpZV9wb3J0ICpwcDsNCj4gPiArCWNv
bnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgKm9mX2lkID0NCj4gPiArCQkJb2ZfbWF0Y2hfZGV2aWNl
KGlteDZfcGNpZV9vZl9tYXRjaCwgJnBkZXYtPmRldik7DQo+ID4gIAlzdHJ1Y3QgZGV2aWNlX25v
ZGUgKm5wID0gcGRldi0+ZGV2Lm9mX25vZGU7DQo+ID4gIAlzdHJ1Y3QgcmVzb3VyY2UgKmRiaV9i
YXNlOw0KPiA+ICAJaW50IHJldDsNCj4gPiBAQCAtNTYwLDYgKzcwNiw3IEBAIHN0YXRpYyBpbnQg
X19pbml0IGlteDZfcGNpZV9wcm9iZShzdHJ1Y3QNCj4gPiBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYp
DQo+ID4NCj4gPiAgCXBwID0gJmlteDZfcGNpZS0+cHA7DQo+ID4gIAlwcC0+ZGV2ID0gJnBkZXYt
PmRldjsNCj4gPiArCWlteDZfcGNpZS0+ZGF0YSA9IG9mX2lkLT5kYXRhOw0KPiA+DQo+ID4gIAkv
KiBBZGRlZCBmb3IgUENJIGFib3J0IGhhbmRsaW5nICovDQo+ID4gIAlob29rX2ZhdWx0X2NvZGUo
MTYgKyA2LCBpbXg2cV9wY2llX2Fib3J0X2hhbmRsZXIsIFNJR0JVUywgMCwgQEANCj4gPiAtNTgx
LDEyICs3MjgsMjYgQEAgc3RhdGljIGludCBfX2luaXQgaW14Nl9wY2llX3Byb2JlKHN0cnVjdCBw
bGF0Zm9ybV9kZXZpY2UNCj4gKnBkZXYpDQo+ID4gIAkJfQ0KPiA+ICAJfQ0KPiA+DQo+ID4gKwlp
bXg2X3BjaWUtPnBvd2VyX29uX2dwaW8gPSBvZl9nZXRfbmFtZWRfZ3BpbyhucCwgInBvd2VyLW9u
LWdwaW8iLCAwKTsNCj4gPiArCWlmIChncGlvX2lzX3ZhbGlkKGlteDZfcGNpZS0+cG93ZXJfb25f
Z3BpbykpIHsNCj4gPiArCQlyZXQgPSBkZXZtX2dwaW9fcmVxdWVzdF9vbmUoJnBkZXYtPmRldiwN
Cj4gPiArCQkJCQlpbXg2X3BjaWUtPnBvd2VyX29uX2dwaW8sDQo+ID4gKwkJCQkJR1BJT0ZfT1VU
X0lOSVRfTE9XLA0KPiA+ICsJCQkJCSJQQ0llIHBvd2VyIGVuYWJsZSIpOw0KPiA+ICsJCWlmIChy
ZXQpIHsNCj4gPiArCQkJZGV2X2VycigmcGRldi0+ZGV2LCAidW5hYmxlIHRvIGdldCBwb3dlci1v
biBncGlvXG4iKTsNCj4gPiArCQkJcmV0dXJuIHJldDsNCj4gPiArCQl9DQo+ID4gKwl9DQo+ID4g
Kw0KPiA+ICAJLyogRmV0Y2ggY2xvY2tzICovDQo+ID4gLQlpbXg2X3BjaWUtPnBjaWVfcGh5ID0g
ZGV2bV9jbGtfZ2V0KCZwZGV2LT5kZXYsICJwY2llX3BoeSIpOw0KPiA+IC0JaWYgKElTX0VSUihp
bXg2X3BjaWUtPnBjaWVfcGh5KSkgew0KPiA+IC0JCWRldl9lcnIoJnBkZXYtPmRldiwNCj4gPiAt
CQkJInBjaWVfcGh5IGNsb2NrIHNvdXJjZSBtaXNzaW5nIG9yIGludmFsaWRcbiIpOw0KPiA+IC0J
CXJldHVybiBQVFJfRVJSKGlteDZfcGNpZS0+cGNpZV9waHkpOw0KPiA+ICsJaWYgKCFpc19pbXg2
c3hfcGNpZShpbXg2X3BjaWUpKSB7DQo+ID4gKwkJaW14Nl9wY2llLT5wY2llX3BoeSA9IGRldm1f
Y2xrX2dldCgmcGRldi0+ZGV2LCAicGNpZV9waHkiKTsNCj4gPiArCQlpZiAoSVNfRVJSKGlteDZf
cGNpZS0+cGNpZV9waHkpKSB7DQo+ID4gKwkJCWRldl9lcnIoJnBkZXYtPmRldiwNCj4gPiArCQkJ
CSJwY2llX3BoeSBjbG9jayBzb3VyY2UgbWlzc2luZyBvciBpbnZhbGlkXG4iKTsNCj4gPiArCQkJ
cmV0dXJuIFBUUl9FUlIoaW14Nl9wY2llLT5wY2llX3BoeSk7DQo+ID4gKwkJfQ0KPiA+ICAJfQ0K
PiA+DQo+IA0KPiBNaXNzaW5nIGJpbmRpbmcgdXBkYXRlIGZvciB0aGUgY2hhbmdlZCBjbG9jayBo
YW5kbGluZy4gQWxzbyB3aGF0IGlzIHRoaXMgY2xvY2sNCj4gcGNpZV9zZWM/IElzIGl0IHJlYWxs
eSBhIHNlY29uZCBBWEkgY2xvY2s/IEkgaGlnaGx5IGRvdWJ0IHRoYXQgdGhlIHJlZ2lzdGVyDQo+
IGludGVyZmFjZSBvZiB0aGUgY29yZSBpcyBjbG9ja2VkIGJ5IHR3byBkaWZmZXJlbnQgY2xvY2tz
LiBXaGF0IGJsb2NrcyBvZiB0aGUNCj4gZHdfcGNpIGNvcmUgZG9lcyB0aGlzIGNsb2NrIGZlZWQ/
DQo+IA0KPiA+ICAJaW14Nl9wY2llLT5wY2llX2J1cyA9IGRldm1fY2xrX2dldCgmcGRldi0+ZGV2
LCAicGNpZV9idXMiKTsgQEANCj4gPiAtNjA0LDggKzc2NSwyMiBAQCBzdGF0aWMgaW50IF9faW5p
dCBpbXg2X3BjaWVfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZQ0KPiAqcGRldikNCj4gPiAg
CX0NCj4gPg0KPiA+ICAJLyogR3JhYiBHUFIgY29uZmlnIHJlZ2lzdGVyIHJhbmdlICovDQo+ID4g
LQlpbXg2X3BjaWUtPmlvbXV4Y19ncHIgPQ0KPiA+IC0JCSBzeXNjb25fcmVnbWFwX2xvb2t1cF9i
eV9jb21wYXRpYmxlKCJmc2wsaW14NnEtaW9tdXhjLWdwciIpOw0KPiA+ICsJaWYgKGlzX2lteDZz
eF9wY2llKGlteDZfcGNpZSkpIHsNCj4gPiArCQkvKiBHZXQgcGNpZSByZWd1bGF0b3IgKi8NCj4g
PiArCQlpbXg2X3BjaWUtPnBjaWVfcmVndWxhdG9yID0gZGV2bV9yZWd1bGF0b3JfZ2V0KHBwLT5k
ZXYsICJwY2llIik7DQo+IA0KPiBVaCwgdGhpcyBoYXMgbm90aGluZyB0byBkbyB3aXRoIHRoZSBH
UFIgcmFuZ2UsIHNvIHRoZSBjb21tZW50IGFib3ZlIGlzDQo+IGNvbmZ1c2luZy4gQWxzbyBtaXNz
aW5nIGJpbmRpbmcgdXBkYXRlIGZvciB0aGlzIHJlZ3VsYXRvci4NCj4gDQo+ID4gKw0KPiA+ICsJ
CS8qIEdyYWIgR1BSIGNvbmZpZyByZWdpc3RlciByYW5nZSAqLw0KPiA+ICsJCWlteDZfcGNpZS0+
aW9tdXhjX2dwciA9DQo+ID4gKwkJCSBzeXNjb25fcmVnbWFwX2xvb2t1cF9ieV9jb21wYXRpYmxl
DQo+ID4gKwkJCSAoImZzbCxpbXg2c3gtaW9tdXhjLWdwciIpOw0KPiA+ICsJCS8qIEdyYWIgR1BD
IElQUyByZWdpc3RlciByYW5nZSAqLw0KPiA+ICsJCWlteDZfcGNpZS0+Z3BjX2lwc19yZWcgPQ0K
PiA+ICsJCQkgc3lzY29uX3JlZ21hcF9sb29rdXBfYnlfY29tcGF0aWJsZSgiZnNsLGlteDZzeC1n
cGMiKTsNCj4gPiArCX0gZWxzZSB7DQo+ID4gKwkJaW14Nl9wY2llLT5pb211eGNfZ3ByID0NCj4g
PiArCQkJc3lzY29uX3JlZ21hcF9sb29rdXBfYnlfY29tcGF0aWJsZQ0KPiA+ICsJCQkoImZzbCxp
bXg2cS1pb211eGMtZ3ByIik7DQo+ID4gKwl9DQo+ID4gIAlpZiAoSVNfRVJSKGlteDZfcGNpZS0+
aW9tdXhjX2dwcikpIHsNCj4gPiAgCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJ1bmFibGUgdG8gZmlu
ZCBpb211eGMgcmVnaXN0ZXJzXG4iKTsNCj4gPiAgCQlyZXR1cm4gUFRSX0VSUihpbXg2X3BjaWUt
PmlvbXV4Y19ncHIpOyBAQCAtNjE2LDYgKzc5MSw5IEBAIHN0YXRpYw0KPiA+IGludCBfX2luaXQg
aW14Nl9wY2llX3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpDQo+ID4gIAkJcmV0
dXJuIHJldDsNCj4gPg0KPiA+ICAJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgaW14Nl9wY2ll
KTsNCj4gPiArI2lmZGVmIENPTkZJR19QTV9TTEVFUA0KPiA+ICsJcmVnaXN0ZXJfc3lzY29yZV9v
cHMoJnBjaV9pbXhfc3lzY29yZV9vcHMpOw0KPiA+ICsjZW5kaWYNCj4gPiAgCXJldHVybiAwOw0K
PiA+ICB9DQo+ID4NCj4gPiBAQCAtNjI3LDEyICs4MDUsNiBAQCBzdGF0aWMgdm9pZCBpbXg2X3Bj
aWVfc2h1dGRvd24oc3RydWN0IHBsYXRmb3JtX2RldmljZQ0KPiAqcGRldikNCj4gPiAgCWlteDZf
cGNpZV9hc3NlcnRfY29yZV9yZXNldCgmaW14Nl9wY2llLT5wcCk7DQo+ID4gIH0NCj4gPg0KPiA+
IC1zdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBpbXg2X3BjaWVfb2ZfbWF0Y2hbXSA9
IHsNCj4gPiAtCXsgLmNvbXBhdGlibGUgPSAiZnNsLGlteDZxLXBjaWUiLCB9LA0KPiA+IC0Je30s
DQo+ID4gLX07DQo+ID4gLU1PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIGlteDZfcGNpZV9vZl9tYXRj
aCk7DQo+ID4gLQ0KPiA+ICBzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2RyaXZlciBpbXg2X3BjaWVf
ZHJpdmVyID0gew0KPiA+ICAJLmRyaXZlciA9IHsNCj4gPiAgCQkubmFtZQk9ICJpbXg2cS1wY2ll
IiwNCj4gPiBkaWZmIC0tZ2l0IGEvaW5jbHVkZS9saW51eC9tZmQvc3lzY29uL2lteDZxLWlvbXV4
Yy1ncHIuaA0KPiA+IGIvaW5jbHVkZS9saW51eC9tZmQvc3lzY29uL2lteDZxLWlvbXV4Yy1ncHIu
aA0KPiA+IGluZGV4IGZmNDQzNzQuLmYwMjg3NWUgMTAwNjQ0DQo+ID4gLS0tIGEvaW5jbHVkZS9s
aW51eC9tZmQvc3lzY29uL2lteDZxLWlvbXV4Yy1ncHIuaA0KPiA+ICsrKyBiL2luY2x1ZGUvbGlu
dXgvbWZkL3N5c2Nvbi9pbXg2cS1pb211eGMtZ3ByLmgNCj4gPiBAQCAtMTEzLDEwICsxMTMsMTIg
QEANCj4gPiAgI2RlZmluZSBJTVg2UV9HUFIxX01JUElfSVBVMV9NVVhfR0FTS0VUCQkweDANCj4g
PiAgI2RlZmluZSBJTVg2UV9HUFIxX01JUElfSVBVMV9NVVhfSU9NVVgJCUJJVCgxOSkNCj4gPiAg
I2RlZmluZSBJTVg2UV9HUFIxX1BDSUVfVEVTVF9QRAkJCUJJVCgxOCkNCj4gPiArI2RlZmluZSBJ
TVg2UV9HUFIxX1BDSUVfVEVTVF9QRF9DTFIJCTB4MA0KPiA+ICAjZGVmaW5lIElNWDZRX0dQUjFf
SVBVX1ZQVV9NVVhfTUFTSwkJQklUKDE3KQ0KPiA+ICAjZGVmaW5lIElNWDZRX0dQUjFfSVBVX1ZQ
VV9NVVhfSVBVMQkJMHgwDQo+ID4gICNkZWZpbmUgSU1YNlFfR1BSMV9JUFVfVlBVX01VWF9JUFUy
CQlCSVQoMTcpDQo+ID4gICNkZWZpbmUgSU1YNlFfR1BSMV9QQ0lFX1JFRl9DTEtfRU4JCUJJVCgx
NikNCj4gPiArI2RlZmluZSBJTVg2UV9HUFIxX1BDSUVfUkVGX0NMS19DTFIJCTB4MA0KPiA+ICAj
ZGVmaW5lIElNWDZRX0dQUjFfVVNCX0VYUF9NT0RFCQkJQklUKDE1KQ0KPiA+ICAjZGVmaW5lIElN
WDZRX0dQUjFfUENJRV9JTlQJCQlCSVQoMTQpDQo+ID4gICNkZWZpbmUgSU1YNlFfR1BSMV9VU0Jf
T1RHX0lEX1NFTF9NQVNLCQlCSVQoMTMpDQo+ID4gQEAgLTMwMCw3ICszMDIsOSBAQA0KPiA+ICAj
ZGVmaW5lIElNWDZRX0dQUjEyX0FSTVBfQVBCX0NMS19FTgkJQklUKDI0KQ0KPiA+ICAjZGVmaW5l
IElNWDZRX0dQUjEyX0RFVklDRV9UWVBFCQkJKDB4ZiA8PCAxMikNCj4gPiAgI2RlZmluZSBJTVg2
UV9HUFIxMl9QQ0lFX0NUTF8yCQkJQklUKDEwKQ0KPiA+ICsjZGVmaW5lIElNWDZRX0dQUjEyX1BD
SUVfQ1RMXzJfQ0xSCQkweDANCj4gPiAgI2RlZmluZSBJTVg2UV9HUFIxMl9MT1NfTEVWRUwJCQko
MHgxZiA8PCA0KQ0KPiA+ICsjZGVmaW5lIElNWDZRX0dQUjEyX0xPU19MRVZFTF85CQkJKDB4OSA8
PCA0KQ0KPiA+DQo+ID4gICNkZWZpbmUgSU1YNlFfR1BSMTNfU0RNQV9TVE9QX1JFUQkJQklUKDMw
KQ0KPiA+ICAjZGVmaW5lIElNWDZRX0dQUjEzX0NBTjJfU1RPUF9SRVEJCUJJVCgyOSkNCj4gPiBA
QCAtMzk1LDQgKzM5OSwxNCBAQA0KPiA+ICAjZGVmaW5lIElNWDZTTF9HUFIxX0ZFQ19DTE9DS19N
VVgxX1NFTF9NQVNLICAgICgweDMgPDwgMTcpDQo+ID4gICNkZWZpbmUgSU1YNlNMX0dQUjFfRkVD
X0NMT0NLX01VWDJfU0VMX01BU0sgICAgKDB4MSA8PCAxNCkNCj4gPg0KPiA+ICsvKiBGb3IgaW14
NnN4IGlvbXV4IGdwciByZWdpc3RlciBmaWVsZCBkZWZpbmUgKi8NCj4gPiArI2RlZmluZSBJTVg2
U1hfR1BSNV9QQ0lFX0JUTlJTVAkJCUJJVCgxOSkNCj4gPiArI2RlZmluZSBJTVg2U1hfR1BSNV9Q
Q0lFX0JUTlJTVF9DTFIJCTB4MA0KPiA+ICsjZGVmaW5lIElNWDZTWF9HUFI1X1BDSUVfUEVSU1QJ
CQlCSVQoMTgpDQo+ID4gKyNkZWZpbmUgSU1YNlNYX0dQUjVfUENJRV9QRVJTVF9DTFIJCTB4MA0K
PiA+ICsNCj4gPiArI2RlZmluZSBJTVg2U1hfR1BSMTJfUENJRV9URVNUX1BECQlCSVQoMzApDQo+
ID4gKyNkZWZpbmUgSU1YNlNYX0dQUjEyX1BDSUVfVEVTVF9QRF9DTFIJCTB4MA0KPiA+ICsjZGVm
aW5lIElNWDZTWF9HUFIxMl9SWF9FUV9NQVNLCQkJKDB4NyA8PCAwKQ0KPiA+ICsjZGVmaW5lIElN
WDZTWF9HUFIxMl9SWF9FUV8yCQkJKDB4MiA8PCAwKQ0KPiA+ICAjZW5kaWYgLyogX19MSU5VWF9J
TVg2UV9JT01VWENfR1BSX0ggKi8NCj4gDQo+IC0tDQo+IFBlbmd1dHJvbml4IGUuSy4gICAgICAg
ICAgICAgfCBMdWNhcyBTdGFjaCAgICAgICAgICAgICAgICAgfA0KPiBJbmR1c3RyaWFsIExpbnV4
IFNvbHV0aW9ucyAgIHwgaHR0cDovL3d3dy5wZW5ndXRyb25peC5kZS8gIHwNCg0K
--
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
Greg Kroah-Hartman Sept. 22, 2014, 1:15 p.m. UTC | #4
On Mon, Sep 22, 2014 at 05:01:38PM +0800, Richard Zhu wrote:
> - 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.
> - another dis_axi clk is mandatory required by imx6sx pcie.
> Add one new clk named pcie_sec into imx6_pcie structure.
> - pcie_ref_125m is not used as pcie_phy clk anymore on imx6sx.
> The parent clk (pcie_ref) of the pcie_bus(lvds1_gate)
> is used as pcie_phy clk.
> - Register one PM call-back, enter/exit L2 state of the ASPM
> during system suspend/resume.
> - wait the clocks to stabilize after the pcie_ref_en
> (IMX6Q_GPR1_PCIE_REF_CLK_EN) is set.
> 
> Signed-off-by: Richard Zhu <r65037@freescale.com>
> ---
>  arch/arm/boot/dts/imx6sx-sdb.dts            |  15 ++
>  arch/arm/boot/dts/imx6sx.dtsi               |  33 ++--
>  arch/arm/mach-imx/Kconfig                   |   1 +
>  drivers/pci/host/pci-imx6.c                 | 228 ++++++++++++++++++++++++----
>  include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |  14 ++
>  5 files changed, 249 insertions(+), 42 deletions(-)

<formletter>

This is not the correct way to submit patches for inclusion in the
stable kernel tree.  Please read Documentation/stable_kernel_rules.txt
for how to do this properly.

</formletter>
--
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:11 a.m. UTC | #5
> -----Original Message-----
> From: Greg KH [mailto:gregkh@linuxfoundation.org]
> Sent: Monday, September 22, 2014 9:16 PM
> To: Zhu Richard-R65037
> Cc: linux-pci-owner@vger.kernel.org; stable@vger.kernel.org; linux-
> pci@vger.kernel.org; l.stach@pengutronix.de
> Subject: Re: [PATCH RFC 2/2] PCI: imx6: add imx6sx pcie support
> 
> On Mon, Sep 22, 2014 at 05:01:38PM +0800, Richard Zhu wrote:
> > - 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.
> > - another dis_axi clk is mandatory required by imx6sx pcie.
> > Add one new clk named pcie_sec into imx6_pcie structure.
> > - pcie_ref_125m is not used as pcie_phy clk anymore on imx6sx.
> > The parent clk (pcie_ref) of the pcie_bus(lvds1_gate) is used as
> > pcie_phy clk.
> > - Register one PM call-back, enter/exit L2 state of the ASPM during
> > system suspend/resume.
> > - wait the clocks to stabilize after the pcie_ref_en
> > (IMX6Q_GPR1_PCIE_REF_CLK_EN) is set.
> >
> > Signed-off-by: Richard Zhu <r65037@freescale.com>
> > ---
> >  arch/arm/boot/dts/imx6sx-sdb.dts            |  15 ++
> >  arch/arm/boot/dts/imx6sx.dtsi               |  33 ++--
> >  arch/arm/mach-imx/Kconfig                   |   1 +
> >  drivers/pci/host/pci-imx6.c                 | 228 ++++++++++++++++++++++++-
> ---
> >  include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |  14 ++
> >  5 files changed, 249 insertions(+), 42 deletions(-)
> 
> <formletter>
> 
> This is not the correct way to submit patches for inclusion in the stable
> kernel tree.  Please read Documentation/stable_kernel_rules.txt
> for how to do this properly.
> 
> </formletter>
[Richard] Roger that, thanks for your reminder.
It's my fault to make a mistake to send the patch review to table kernel mail-list. Sorry about that.

Best Regards
Richard Zhu

--
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/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts
index a3980d9..83d0892 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dts
+++ b/arch/arm/boot/dts/imx6sx-sdb.dts
@@ -251,6 +251,14 @@ 
 	};
 };
 
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	power-on-gpio = <&gpio2 1 0>;
+	reset-gpio = <&gpio2 0 0>;
+	status = "okay";
+};
+
 &ssi2 {
 	status = "okay";
 };
@@ -365,6 +373,13 @@ 
 			>;
 		};
 
+		pinctrl_pcie: pciegrp {
+			fsl,pins = <
+				MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x17059
+				MX6SX_PAD_ENET1_CRS__GPIO2_IO_1	0x17059
+			>;
+		};
+
 		pinctrl_vcc_sd3: vccsd3grp {
 			fsl,pins = <
 				MX6SX_PAD_KEY_COL1__GPIO2_IO_11		0x17059
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index f4b9da6..ec34698 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -689,9 +689,11 @@ 
 			};
 
 			gpc: gpc@020dc000 {
-				compatible = "fsl,imx6sx-gpc", "fsl,imx6q-gpc";
+				compatible = "fsl,imx6sx-gpc",
+					     "fsl,imx6q-gpc", "syscon";
 				reg = <0x020dc000 0x4000>;
 				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+				pcie-supply = <&reg_pcie>;
 			};
 
 			iomuxc: iomuxc@020e0000 {
@@ -1188,20 +1190,23 @@ 
 			#address-cells = <3>;
 			#size-cells = <2>;
 			device_type = "pci";
-				  /* configuration space */
-			ranges = <0x00000800 0 0x08f00000 0x08f00000 0 0x00080000
-				  /* downstream I/O */
-				  0x81000000 0 0          0x08f80000 0 0x00010000
-				  /* non-prefetchable memory */
-				  0x82000000 0 0x08000000 0x08000000 0 0x00f00000>;
+			ranges = <0x00000800 0 0x01f00000 0x08f00000 0 0x00080000 /* configuration space */
+				  0x81000000 0 0          0x08f80000 0 0x00010000 /* downstream I/O */
+				  0x82000000 0 0x01000000 0x08000000 0 0x00f00000>; /* non-prefetchable memory */
 			num-lanes = <1>;
-			interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>,
-				 <&clks IMX6SX_CLK_PCIE_AXI>,
-				 <&clks IMX6SX_CLK_LVDS1_OUT>,
-				 <&clks IMX6SX_CLK_DISPLAY_AXI>;
-			clock-names = "pcie_ref_125m", "pcie_axi",
-				      "lvds_gate", "display_axi";
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "msi";
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0x7>;
+			interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+			                <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+			                <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+			                <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clks IMX6SX_CLK_PCIE_AXI>,
+				 <&clks IMX6SX_CLK_DISPLAY_AXI>,
+				 <&clks IMX6SX_CLK_LVDS1_OUT>;
+			clock-names = "pcie", "pcie_sec", "pcie_bus";
+			pcie-supply = <&reg_pcie>;
 			status = "disabled";
 		};
 	};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index be9a51a..0a055f0 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -718,6 +718,7 @@  config SOC_IMX6SL
 
 config SOC_IMX6SX
 	bool "i.MX6 SoloX support"
+	select PCI_DOMAINS if PCI
 	select PINCTRL_IMX6SX
 	select SOC_IMX6
 
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index 233fe8a..c9b2f69 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,32 @@ 
 
 #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;
+	int			power_on_gpio;
+	const struct		imx_pcie_data *data;
 	struct clk		*pcie_bus;
 	struct clk		*pcie_phy;
+	struct clk		*pcie_sec;
 	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 +98,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;
@@ -257,10 +283,21 @@  static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
 	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
 	int ret;
 
-	ret = clk_prepare_enable(imx6_pcie->pcie_phy);
-	if (ret) {
-		dev_err(pp->dev, "unable to enable pcie_phy clock\n");
-		goto err_pcie_phy;
+	if (gpio_is_valid(imx6_pcie->power_on_gpio))
+		gpio_set_value(imx6_pcie->power_on_gpio, 1);
+
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		ret = clk_prepare_enable(imx6_pcie->pcie_sec);
+		if (ret) {
+			dev_err(pp->dev, "unable to enable pcie_sec clk.\n");
+			goto err_pcie_sec;
+		}
+	} else {
+		ret = clk_prepare_enable(imx6_pcie->pcie_phy);
+		if (ret) {
+			dev_err(pp->dev, "unable to enable pcie_phy clock\n");
+			goto err_pcie_phy;
+		}
 	}
 
 	ret = clk_prepare_enable(imx6_pcie->pcie_bus);
@@ -275,28 +312,50 @@  static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
 		goto err_pcie;
 	}
 
+	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);
 
-	/* 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);
-
 	/* Some boards don't have PCIe reset GPIO. */
 	if (gpio_is_valid(imx6_pcie->reset_gpio)) {
 		gpio_set_value(imx6_pcie->reset_gpio, 0);
 		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:
 	clk_disable_unprepare(imx6_pcie->pcie_bus);
 err_pcie_bus:
-	clk_disable_unprepare(imx6_pcie->pcie_phy);
+	if (!is_imx6sx_pcie(imx6_pcie))
+		clk_disable_unprepare(imx6_pcie->pcie_phy);
 err_pcie_phy:
+	if (is_imx6sx_pcie(imx6_pcie))
+		clk_disable_unprepare(imx6_pcie->pcie_sec);
+err_pcie_sec:
 	return ret;
 
 }
@@ -304,15 +363,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 +452,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 +629,73 @@  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);
+
+		/* 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);
+	}
+}
+
+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 +706,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,
@@ -581,12 +728,26 @@  static int __init imx6_pcie_probe(struct platform_device *pdev)
 		}
 	}
 
+	imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
+	if (gpio_is_valid(imx6_pcie->power_on_gpio)) {
+		ret = devm_gpio_request_one(&pdev->dev,
+					imx6_pcie->power_on_gpio,
+					GPIOF_OUT_INIT_LOW,
+					"PCIe power enable");
+		if (ret) {
+			dev_err(&pdev->dev, "unable to get power-on gpio\n");
+			return ret;
+		}
+	}
+
 	/* Fetch clocks */
-	imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");
-	if (IS_ERR(imx6_pcie->pcie_phy)) {
-		dev_err(&pdev->dev,
-			"pcie_phy clock source missing or invalid\n");
-		return PTR_ERR(imx6_pcie->pcie_phy);
+	if (!is_imx6sx_pcie(imx6_pcie)) {
+		imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");
+		if (IS_ERR(imx6_pcie->pcie_phy)) {
+			dev_err(&pdev->dev,
+				"pcie_phy clock source missing or invalid\n");
+			return PTR_ERR(imx6_pcie->pcie_phy);
+		}
 	}
 
 	imx6_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_bus");
@@ -604,8 +765,22 @@  static int __init imx6_pcie_probe(struct platform_device *pdev)
 	}
 
 	/* Grab GPR config register range */
-	imx6_pcie->iomuxc_gpr =
-		 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+	if (is_imx6sx_pcie(imx6_pcie)) {
+		/* Get pcie regulator */
+		imx6_pcie->pcie_regulator = devm_regulator_get(pp->dev, "pcie");
+
+		/* Grab GPR config register range */
+		imx6_pcie->iomuxc_gpr =
+			 syscon_regmap_lookup_by_compatible
+			 ("fsl,imx6sx-iomuxc-gpr");
+		/* Grab GPC IPS register range */
+		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 +791,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 +805,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",
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
index ff44374..f02875e 100644
--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
+++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
@@ -113,10 +113,12 @@ 
 #define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET		0x0
 #define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX		BIT(19)
 #define IMX6Q_GPR1_PCIE_TEST_PD			BIT(18)
+#define IMX6Q_GPR1_PCIE_TEST_PD_CLR		0x0
 #define IMX6Q_GPR1_IPU_VPU_MUX_MASK		BIT(17)
 #define IMX6Q_GPR1_IPU_VPU_MUX_IPU1		0x0
 #define IMX6Q_GPR1_IPU_VPU_MUX_IPU2		BIT(17)
 #define IMX6Q_GPR1_PCIE_REF_CLK_EN		BIT(16)
+#define IMX6Q_GPR1_PCIE_REF_CLK_CLR		0x0
 #define IMX6Q_GPR1_USB_EXP_MODE			BIT(15)
 #define IMX6Q_GPR1_PCIE_INT			BIT(14)
 #define IMX6Q_GPR1_USB_OTG_ID_SEL_MASK		BIT(13)
@@ -300,7 +302,9 @@ 
 #define IMX6Q_GPR12_ARMP_APB_CLK_EN		BIT(24)
 #define IMX6Q_GPR12_DEVICE_TYPE			(0xf << 12)
 #define IMX6Q_GPR12_PCIE_CTL_2			BIT(10)
+#define IMX6Q_GPR12_PCIE_CTL_2_CLR		0x0
 #define IMX6Q_GPR12_LOS_LEVEL			(0x1f << 4)
+#define IMX6Q_GPR12_LOS_LEVEL_9			(0x9 << 4)
 
 #define IMX6Q_GPR13_SDMA_STOP_REQ		BIT(30)
 #define IMX6Q_GPR13_CAN2_STOP_REQ		BIT(29)
@@ -395,4 +399,14 @@ 
 #define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK    (0x3 << 17)
 #define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK    (0x1 << 14)
 
+/* For imx6sx iomux gpr register field define */
+#define IMX6SX_GPR5_PCIE_BTNRST			BIT(19)
+#define IMX6SX_GPR5_PCIE_BTNRST_CLR		0x0
+#define IMX6SX_GPR5_PCIE_PERST			BIT(18)
+#define IMX6SX_GPR5_PCIE_PERST_CLR		0x0
+
+#define IMX6SX_GPR12_PCIE_TEST_PD		BIT(30)
+#define IMX6SX_GPR12_PCIE_TEST_PD_CLR		0x0
+#define IMX6SX_GPR12_RX_EQ_MASK			(0x7 << 0)
+#define IMX6SX_GPR12_RX_EQ_2			(0x2 << 0)
 #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */