Commit 9e56f0df authored by Leonard Crestez's avatar Leonard Crestez Committed by Lorenzo Pieralisi

PCI: imx: Add imx6sx suspend/resume support

Enable PCI suspend/resume support on imx6sx SOCs. This is similar to
imx7d with a few differences:

* The PM_Turn_Off bit is exposed through an IOMUX GPR, like all other
pcie control bits on 6sx.
* The pcie_inbound_axi clk needs to be turned off in suspend. On resume
it is restored via resume -> deassert_core_reset -> enable_ref_clk.

Most of the resume logic is shared with the initial reset after probe.
Signed-off-by: default avatarLeonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: default avatarAndrey Smirnov <andrew.smirnov@gmail.com>
Acked-by: default avatarLucas Stach <l.stach@pengutronix.de>
parent 3d71746c
...@@ -817,8 +817,28 @@ static void imx6_pcie_ltssm_disable(struct device *dev) ...@@ -817,8 +817,28 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
{ {
reset_control_assert(imx6_pcie->turnoff_reset); struct device *dev = imx6_pcie->pci->dev;
reset_control_deassert(imx6_pcie->turnoff_reset);
/* Some variants have a turnoff reset in DT */
if (imx6_pcie->turnoff_reset) {
reset_control_assert(imx6_pcie->turnoff_reset);
reset_control_deassert(imx6_pcie->turnoff_reset);
goto pm_turnoff_sleep;
}
/* Others poke directly at IOMUXC registers */
switch (imx6_pcie->variant) {
case IMX6SX:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_PM_TURN_OFF,
IMX6SX_GPR12_PCIE_PM_TURN_OFF);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0);
break;
default:
dev_err(dev, "PME_Turn_Off not implemented\n");
return;
}
/* /*
* Components with an upstream port must respond to * Components with an upstream port must respond to
...@@ -827,6 +847,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) ...@@ -827,6 +847,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
* The standard recommends a 1-10ms timeout after which to * The standard recommends a 1-10ms timeout after which to
* proceed anyway as if acks were received. * proceed anyway as if acks were received.
*/ */
pm_turnoff_sleep:
usleep_range(1000, 10000); usleep_range(1000, 10000);
} }
...@@ -836,18 +857,31 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) ...@@ -836,18 +857,31 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
clk_disable_unprepare(imx6_pcie->pcie_phy); clk_disable_unprepare(imx6_pcie->pcie_phy);
clk_disable_unprepare(imx6_pcie->pcie_bus); clk_disable_unprepare(imx6_pcie->pcie_bus);
if (imx6_pcie->variant == IMX7D) { switch (imx6_pcie->variant) {
case IMX6SX:
clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
break;
case IMX7D:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
break;
default:
break;
} }
} }
static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie)
{
return (imx6_pcie->variant == IMX7D ||
imx6_pcie->variant == IMX6SX);
}
static int imx6_pcie_suspend_noirq(struct device *dev) static int imx6_pcie_suspend_noirq(struct device *dev)
{ {
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
if (imx6_pcie->variant != IMX7D) if (!imx6_pcie_supports_suspend(imx6_pcie))
return 0; return 0;
imx6_pcie_pm_turnoff(imx6_pcie); imx6_pcie_pm_turnoff(imx6_pcie);
...@@ -863,7 +897,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) ...@@ -863,7 +897,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
struct pcie_port *pp = &imx6_pcie->pci->pp; struct pcie_port *pp = &imx6_pcie->pci->pp;
if (imx6_pcie->variant != IMX7D) if (!imx6_pcie_supports_suspend(imx6_pcie))
return 0; return 0;
imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_assert_core_reset(imx6_pcie);
......
...@@ -440,6 +440,7 @@ ...@@ -440,6 +440,7 @@
#define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1) #define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1)
#define IMX6SX_GPR12_PCIE_TEST_POWERDOWN BIT(30) #define IMX6SX_GPR12_PCIE_TEST_POWERDOWN BIT(30)
#define IMX6SX_GPR12_PCIE_PM_TURN_OFF BIT(16)
#define IMX6SX_GPR12_PCIE_RX_EQ_MASK (0x7 << 0) #define IMX6SX_GPR12_PCIE_RX_EQ_MASK (0x7 << 0)
#define IMX6SX_GPR12_PCIE_RX_EQ_2 (0x2 << 0) #define IMX6SX_GPR12_PCIE_RX_EQ_2 (0x2 << 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment