Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Leonard Crestez and committed by
Lorenzo Pieralisi
9e56f0df 3d71746c

+40 -5
+39 -5
drivers/pci/controller/dwc/pci-imx6.c
··· 817 817 818 818 static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) 819 819 { 820 - reset_control_assert(imx6_pcie->turnoff_reset); 821 - reset_control_deassert(imx6_pcie->turnoff_reset); 820 + struct device *dev = imx6_pcie->pci->dev; 821 + 822 + /* Some variants have a turnoff reset in DT */ 823 + if (imx6_pcie->turnoff_reset) { 824 + reset_control_assert(imx6_pcie->turnoff_reset); 825 + reset_control_deassert(imx6_pcie->turnoff_reset); 826 + goto pm_turnoff_sleep; 827 + } 828 + 829 + /* Others poke directly at IOMUXC registers */ 830 + switch (imx6_pcie->variant) { 831 + case IMX6SX: 832 + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, 833 + IMX6SX_GPR12_PCIE_PM_TURN_OFF, 834 + IMX6SX_GPR12_PCIE_PM_TURN_OFF); 835 + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, 836 + IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0); 837 + break; 838 + default: 839 + dev_err(dev, "PME_Turn_Off not implemented\n"); 840 + return; 841 + } 822 842 823 843 /* 824 844 * Components with an upstream port must respond to ··· 847 827 * The standard recommends a 1-10ms timeout after which to 848 828 * proceed anyway as if acks were received. 849 829 */ 830 + pm_turnoff_sleep: 850 831 usleep_range(1000, 10000); 851 832 } 852 833 ··· 857 836 clk_disable_unprepare(imx6_pcie->pcie_phy); 858 837 clk_disable_unprepare(imx6_pcie->pcie_bus); 859 838 860 - if (imx6_pcie->variant == IMX7D) { 839 + switch (imx6_pcie->variant) { 840 + case IMX6SX: 841 + clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); 842 + break; 843 + case IMX7D: 861 844 regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, 862 845 IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 863 846 IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); 847 + break; 848 + default: 849 + break; 864 850 } 851 + } 852 + 853 + static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie) 854 + { 855 + return (imx6_pcie->variant == IMX7D || 856 + imx6_pcie->variant == IMX6SX); 865 857 } 866 858 867 859 static int imx6_pcie_suspend_noirq(struct device *dev) 868 860 { 869 861 struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); 870 862 871 - if (imx6_pcie->variant != IMX7D) 863 + if (!imx6_pcie_supports_suspend(imx6_pcie)) 872 864 return 0; 873 865 874 866 imx6_pcie_pm_turnoff(imx6_pcie); ··· 897 863 struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); 898 864 struct pcie_port *pp = &imx6_pcie->pci->pp; 899 865 900 - if (imx6_pcie->variant != IMX7D) 866 + if (!imx6_pcie_supports_suspend(imx6_pcie)) 901 867 return 0; 902 868 903 869 imx6_pcie_assert_core_reset(imx6_pcie);
+1
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
··· 440 440 #define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1) 441 441 442 442 #define IMX6SX_GPR12_PCIE_TEST_POWERDOWN BIT(30) 443 + #define IMX6SX_GPR12_PCIE_PM_TURN_OFF BIT(16) 443 444 #define IMX6SX_GPR12_PCIE_RX_EQ_MASK (0x7 << 0) 444 445 #define IMX6SX_GPR12_PCIE_RX_EQ_2 (0x2 << 0) 445 446