aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/dwc
diff options
context:
space:
mode:
authorLeonard Crestez <leonard.crestez@nxp.com>2018-07-19 10:02:10 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2018-10-05 07:00:35 -0400
commitf4e833ba2a955bc15c1ccaa5b0b3c2a0d7989bca (patch)
tree6837d8a73f76dfd371476a380ea14f423e91829f /drivers/pci/controller/dwc
parent3aedf7e135b55cb74a62c0be79a86384f76e5724 (diff)
PCI: imx: Add PME_Turn_Off support
When the root complex suspends it must send a PME_Turn_Off TLP. Implement this by asserting the "turnoff" reset. On imx7d this functionality is part of the System Reset Controller (SRC) and is exposed through the linux reset-controller subsystem. On imx6 equivalent bits are in the IOMUXC pinmux controller General Purpose Register (GPR) area which the imx6-pcie driver accesses directly. This is only for imx7d right now but it's deliberately implemented as an optional reset, ignoring the chip variant: * Older dtbs won't have this reset so it will be ignored. * Future chips might also expose this as a reset controller. For example imx8m (not yet supported) has the exact same PCIE_CTRL_APPS_TURNOFF bit in the same location. Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index d13dae50dc99..2cbef2d7c207 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -50,6 +50,7 @@ struct imx6_pcie {
50 struct regmap *iomuxc_gpr; 50 struct regmap *iomuxc_gpr;
51 struct reset_control *pciephy_reset; 51 struct reset_control *pciephy_reset;
52 struct reset_control *apps_reset; 52 struct reset_control *apps_reset;
53 struct reset_control *turnoff_reset;
53 enum imx6_pcie_variants variant; 54 enum imx6_pcie_variants variant;
54 u32 tx_deemph_gen1; 55 u32 tx_deemph_gen1;
55 u32 tx_deemph_gen2_3p5db; 56 u32 tx_deemph_gen2_3p5db;
@@ -770,6 +771,21 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
770 } 771 }
771} 772}
772 773
774static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
775{
776 reset_control_assert(imx6_pcie->turnoff_reset);
777 reset_control_deassert(imx6_pcie->turnoff_reset);
778
779 /*
780 * Components with an upstream port must respond to
781 * PME_Turn_Off with PME_TO_Ack but we can't check.
782 *
783 * The standard recommends a 1-10ms timeout after which to
784 * proceed anyway as if acks were received.
785 */
786 usleep_range(1000, 10000);
787}
788
773static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) 789static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
774{ 790{
775 clk_disable_unprepare(imx6_pcie->pcie); 791 clk_disable_unprepare(imx6_pcie->pcie);
@@ -790,6 +806,7 @@ static int imx6_pcie_suspend_noirq(struct device *dev)
790 if (imx6_pcie->variant != IMX7D) 806 if (imx6_pcie->variant != IMX7D)
791 return 0; 807 return 0;
792 808
809 imx6_pcie_pm_turnoff(imx6_pcie);
793 imx6_pcie_clk_disable(imx6_pcie); 810 imx6_pcie_clk_disable(imx6_pcie);
794 imx6_pcie_ltssm_disable(dev); 811 imx6_pcie_ltssm_disable(dev);
795 812
@@ -917,6 +934,13 @@ static int imx6_pcie_probe(struct platform_device *pdev)
917 break; 934 break;
918 } 935 }
919 936
937 /* Grab turnoff reset */
938 imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff");
939 if (IS_ERR(imx6_pcie->turnoff_reset)) {
940 dev_err(dev, "Failed to get TURNOFF reset control\n");
941 return PTR_ERR(imx6_pcie->turnoff_reset);
942 }
943
920 /* Grab GPR config register range */ 944 /* Grab GPR config register range */
921 imx6_pcie->iomuxc_gpr = 945 imx6_pcie->iomuxc_gpr =
922 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); 946 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");