]> Git Repo - linux.git/commitdiff
PCI: j721e: Add suspend and resume support
authorThéo Lebrun <[email protected]>
Wed, 19 Jun 2024 10:15:15 +0000 (12:15 +0200)
committerKrzysztof Wilczyński <[email protected]>
Wed, 4 Sep 2024 14:09:33 +0000 (14:09 +0000)
Add suspend and resume support. Only the Root Complex mode is supported.

During the suspend stage PERST# is asserted, then deasserted during the
resume stage.

Link: https://lore.kernel.org/linux-pci/[email protected]
Signed-off-by: Théo Lebrun <[email protected]>
Signed-off-by: Thomas Richard <[email protected]>
[kwilczynski: commit log, update references to the PCI SIG specification]
Signed-off-by: Krzysztof Wilczyński <[email protected]>
Reviewed-by: Siddharth Vadapalli <[email protected]>
drivers/pci/controller/cadence/pci-j721e.c

index 4096cdd6e8ee7c616e278961a64b9b870992c8bf..284f2e0e4d261561819534f4861db60ced7166f2 100644 (file)
@@ -7,6 +7,8 @@
  */
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/container_of.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/io.h>
@@ -22,6 +24,8 @@
 #include "../../pci.h"
 #include "pcie-cadence.h"
 
+#define cdns_pcie_to_rc(p) container_of(p, struct cdns_pcie_rc, pcie)
+
 #define ENABLE_REG_SYS_2       0x108
 #define STATUS_REG_SYS_2       0x508
 #define STATUS_CLR_REG_SYS_2   0x708
@@ -568,12 +572,12 @@ static int j721e_pcie_probe(struct platform_device *pdev)
                pcie->refclk = clk;
 
                /*
-                * "Power Sequencing and Reset Signal Timings" table in
-                * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
-                * indicates PERST# should be deasserted after minimum of 100us
-                * once REFCLK is stable. The REFCLK to the connector in RC
-                * mode is selected while enabling the PHY. So deassert PERST#
-                * after 100 us.
+                * The "Power Sequencing and Reset Signal Timings" table of the
+                * PCI Express Card Electromechanical Specification, Revision
+                * 5.1, Section 2.9.2, Symbol "T_PERST-CLK", indicates PERST#
+                * should be deasserted after minimum of 100us once REFCLK is
+                * stable. The REFCLK to the connector in RC mode is selected
+                * while enabling the PHY. So deassert PERST# after 100 us.
                 */
                if (gpiod) {
                        fsleep(PCIE_T_PERST_CLK_US);
@@ -625,6 +629,87 @@ static void j721e_pcie_remove(struct platform_device *pdev)
        pm_runtime_disable(dev);
 }
 
+static int j721e_pcie_suspend_noirq(struct device *dev)
+{
+       struct j721e_pcie *pcie = dev_get_drvdata(dev);
+
+       if (pcie->mode == PCI_MODE_RC) {
+               gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+               clk_disable_unprepare(pcie->refclk);
+       }
+
+       cdns_pcie_disable_phy(pcie->cdns_pcie);
+
+       return 0;
+}
+
+static int j721e_pcie_resume_noirq(struct device *dev)
+{
+       struct j721e_pcie *pcie = dev_get_drvdata(dev);
+       struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
+       int ret;
+
+       ret = j721e_pcie_ctrl_init(pcie);
+       if (ret < 0)
+               return ret;
+
+       j721e_pcie_config_link_irq(pcie);
+
+       /*
+        * This is not called explicitly in the probe, it is called by
+        * cdns_pcie_init_phy().
+        */
+       ret = cdns_pcie_enable_phy(pcie->cdns_pcie);
+       if (ret < 0)
+               return ret;
+
+       if (pcie->mode == PCI_MODE_RC) {
+               struct cdns_pcie_rc *rc = cdns_pcie_to_rc(cdns_pcie);
+
+               ret = clk_prepare_enable(pcie->refclk);
+               if (ret < 0)
+                       return ret;
+
+               /*
+                * The "Power Sequencing and Reset Signal Timings" table of the
+                * PCI Express Card Electromechanical Specification, Revision
+                * 5.1, Section 2.9.2, Symbol "T_PERST-CLK", indicates PERST#
+                * should be deasserted after minimum of 100us once REFCLK is
+                * stable. The REFCLK to the connector in RC mode is selected
+                * while enabling the PHY. So deassert PERST# after 100 us.
+                */
+               if (pcie->reset_gpio) {
+                       fsleep(PCIE_T_PERST_CLK_US);
+                       gpiod_set_value_cansleep(pcie->reset_gpio, 1);
+               }
+
+               ret = cdns_pcie_host_link_setup(rc);
+               if (ret < 0) {
+                       clk_disable_unprepare(pcie->refclk);
+                       return ret;
+               }
+
+               /*
+                * Reset internal status of BARs to force reinitialization in
+                * cdns_pcie_host_init().
+                */
+               for (enum cdns_pcie_rp_bar bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
+                       rc->avail_ib_bar[bar] = true;
+
+               ret = cdns_pcie_host_init(rc);
+               if (ret) {
+                       clk_disable_unprepare(pcie->refclk);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static DEFINE_NOIRQ_DEV_PM_OPS(j721e_pcie_pm_ops,
+                              j721e_pcie_suspend_noirq,
+                              j721e_pcie_resume_noirq);
+
 static struct platform_driver j721e_pcie_driver = {
        .probe  = j721e_pcie_probe,
        .remove_new = j721e_pcie_remove,
@@ -632,6 +717,7 @@ static struct platform_driver j721e_pcie_driver = {
                .name   = "j721e-pcie",
                .of_match_table = of_j721e_pcie_match,
                .suppress_bind_attrs = true,
+               .pm     = pm_sleep_ptr(&j721e_pcie_pm_ops),
        },
 };
 builtin_platform_driver(j721e_pcie_driver);
This page took 0.062328 seconds and 4 git commands to generate.