diff options
author | Leonard Crestez <leonard.crestez@nxp.com> | 2018-07-19 10:02:10 -0400 |
---|---|---|
committer | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2018-10-05 07:00:35 -0400 |
commit | f4e833ba2a955bc15c1ccaa5b0b3c2a0d7989bca (patch) | |
tree | 6837d8a73f76dfd371476a380ea14f423e91829f /drivers/pci/controller/dwc | |
parent | 3aedf7e135b55cb74a62c0be79a86384f76e5724 (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.c | 24 |
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 | ||
774 | static 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 | |||
773 | static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) | 789 | static 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"); |