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: Leonard Crestez <leonard.crestez@nxp.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Andrey Smirnov <andrew.smirnov@gmail.com> Acked-by: Lucas Stach <l.stach@pengutronix.de>
This commit is contained in:
parent
3d71746c42
commit
9e56f0df36
@ -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)
|
||||||
{
|
{
|
||||||
|
struct device *dev = imx6_pcie->pci->dev;
|
||||||
|
|
||||||
|
/* Some variants have a turnoff reset in DT */
|
||||||
|
if (imx6_pcie->turnoff_reset) {
|
||||||
reset_control_assert(imx6_pcie->turnoff_reset);
|
reset_control_assert(imx6_pcie->turnoff_reset);
|
||||||
reset_control_deassert(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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user