diff mbox series

[v7,20/37] mmc: sdhci-tegra: Add runtime PM and OPP support

Message ID 20210701232728.23591-21-digetx@gmail.com
State Changes Requested
Headers show
Series NVIDIA Tegra power management patches for 5.15 | expand

Commit Message

Dmitry Osipenko July 1, 2021, 11:27 p.m. UTC
The SDHCI on Tegra belongs to the core power domain and we're going to
enable GENPD support for the core domain. Now SDHCI must be resumed using
runtime PM API in order to initialize the SDHCI power state. The SDHCI
clock rate must be changed using OPP API that will reconfigure the power
domain performance state in accordance to the rate. Add runtime PM and OPP
support to the SDHCI driver.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mmc/host/sdhci-tegra.c | 81 +++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 16 deletions(-)

Comments

kernel test robot July 2, 2021, 3:39 a.m. UTC | #1
Hi Dmitry,

I love your patch! Yet something to improve:

[auto build test ERROR on next-20210701]
[cannot apply to tegra/for-next robh/for-next tegra-drm/drm/tegra/for-next v5.13 v5.13-rc7 v5.13-rc6 v5.13]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/NVIDIA-Tegra-power-management-patches-for-5-15/20210702-073048
base:    fb0ca446157a86b75502c1636b0d81e642fe6bf1
config: m68k-allmodconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/bd90f252831cdc7191a0fef94041489c066e286a
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Dmitry-Osipenko/NVIDIA-Tegra-power-management-patches-for-5-15/20210702-073048
        git checkout bd90f252831cdc7191a0fef94041489c066e286a
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/mmc/host/sdhci-tegra.c: In function 'sdhci_tegra_suspend':
>> drivers/mmc/host/sdhci-tegra.c:1813:8: error: implicit declaration of function 'sdhci_suspend_host'; did you mean 'sdhci_add_host'? [-Werror=implicit-function-declaration]
    1813 |  ret = sdhci_suspend_host(host);
         |        ^~~~~~~~~~~~~~~~~~
         |        sdhci_add_host
>> drivers/mmc/host/sdhci-tegra.c:1821:3: error: implicit declaration of function 'sdhci_resume_host'; did you mean 'sdhci_remove_host'? [-Werror=implicit-function-declaration]
    1821 |   sdhci_resume_host(host);
         |   ^~~~~~~~~~~~~~~~~
         |   sdhci_remove_host
   cc1: some warnings being treated as errors


vim +1813 drivers/mmc/host/sdhci-tegra.c

bd90f252831cdc Dmitry Osipenko     2021-07-02  1801  
bd90f252831cdc Dmitry Osipenko     2021-07-02  1802  static int __maybe_unused sdhci_tegra_suspend(struct device *dev)
bd90f252831cdc Dmitry Osipenko     2021-07-02  1803  {
bd90f252831cdc Dmitry Osipenko     2021-07-02  1804  	struct sdhci_host *host = dev_get_drvdata(dev);
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1805  	int ret;
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1806  
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1807  	if (host->mmc->caps2 & MMC_CAP2_CQE) {
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1808  		ret = cqhci_suspend(host->mmc);
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1809  		if (ret)
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1810  			return ret;
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1811  	}
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1812  
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11 @1813  	ret = sdhci_suspend_host(host);
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1814  	if (ret) {
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1815  		cqhci_resume(host->mmc);
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1816  		return ret;
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1817  	}
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1818  
bd90f252831cdc Dmitry Osipenko     2021-07-02  1819  	ret = pm_runtime_force_suspend(dev);
bd90f252831cdc Dmitry Osipenko     2021-07-02  1820  	if (ret) {
bd90f252831cdc Dmitry Osipenko     2021-07-02 @1821  		sdhci_resume_host(host);
bd90f252831cdc Dmitry Osipenko     2021-07-02  1822  		cqhci_resume(host->mmc);
bd90f252831cdc Dmitry Osipenko     2021-07-02  1823  		return ret;
bd90f252831cdc Dmitry Osipenko     2021-07-02  1824  	}
bd90f252831cdc Dmitry Osipenko     2021-07-02  1825  
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1826  	return 0;
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1827  }
71c733c4e1aeb8 Sowjanya Komatineni 2019-04-11  1828  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 387ce9cdbd7c..19be096b182a 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -15,6 +15,8 @@ 
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/mmc/card.h>
@@ -24,6 +26,8 @@ 
 #include <linux/gpio/consumer.h>
 #include <linux/ktime.h>
 
+#include <soc/tegra/common.h>
+
 #include "sdhci-pltfm.h"
 #include "cqhci.h"
 
@@ -758,10 +762,15 @@  static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+	struct device *dev = mmc_dev(host->mmc);
 	unsigned long host_clk;
+	int err;
 
-	if (!clock)
-		return sdhci_set_clock(host, clock);
+	if (!clock) {
+		sdhci_set_clock(host, clock);
+		dev_pm_opp_set_rate(dev, clock);
+		return;
+	}
 
 	/*
 	 * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI
@@ -776,7 +785,12 @@  static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	 * from clk_get_rate() is used.
 	 */
 	host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;
-	clk_set_rate(pltfm_host->clk, host_clk);
+
+	err = dev_pm_opp_set_rate(dev, host_clk);
+	if (err)
+		dev_err(dev, "failed to set clk rate to %luHz: %d\n",
+			host_clk, err);
+
 	tegra_host->curr_clk_rate = host_clk;
 	if (tegra_host->ddr_signaling)
 		host->max_clk = host_clk;
@@ -1696,7 +1710,6 @@  static int sdhci_tegra_probe(struct platform_device *pdev)
 				   "failed to get clock\n");
 		goto err_clk_get;
 	}
-	clk_prepare_enable(clk);
 	pltfm_host->clk = clk;
 
 	tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev,
@@ -1704,9 +1717,18 @@  static int sdhci_tegra_probe(struct platform_device *pdev)
 	if (IS_ERR(tegra_host->rst)) {
 		rc = PTR_ERR(tegra_host->rst);
 		dev_err(&pdev->dev, "failed to get reset control: %d\n", rc);
-		goto err_rst_get;
+		goto err_clk_get;
 	}
 
+	rc = devm_tegra_core_dev_init_opp_table_simple(&pdev->dev);
+	if (rc)
+		goto err_clk_get;
+
+	pm_runtime_enable(&pdev->dev);
+	rc = pm_runtime_resume_and_get(&pdev->dev);
+	if (rc)
+		goto err_pm_get;
+
 	rc = reset_control_assert(tegra_host->rst);
 	if (rc)
 		goto err_rst_get;
@@ -1728,7 +1750,9 @@  static int sdhci_tegra_probe(struct platform_device *pdev)
 err_add_host:
 	reset_control_assert(tegra_host->rst);
 err_rst_get:
-	clk_disable_unprepare(pltfm_host->clk);
+	pm_runtime_put(&pdev->dev);
+err_pm_get:
+	pm_runtime_disable(&pdev->dev);
 err_clk_get:
 	clk_disable_unprepare(tegra_host->tmclk);
 err_power_req:
@@ -1747,7 +1771,9 @@  static int sdhci_tegra_remove(struct platform_device *pdev)
 
 	reset_control_assert(tegra_host->rst);
 	usleep_range(2000, 4000);
-	clk_disable_unprepare(pltfm_host->clk);
+
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	clk_disable_unprepare(tegra_host->tmclk);
 
 	sdhci_pltfm_free(pdev);
@@ -1755,11 +1781,27 @@  static int sdhci_tegra_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int __maybe_unused sdhci_tegra_suspend(struct device *dev)
+static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	clk_disable_unprepare(pltfm_host->clk);
+
+	return 0;
+}
+
+static int __maybe_unused sdhci_tegra_runtime_resume(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return clk_prepare_enable(pltfm_host->clk);
+}
+
+static int __maybe_unused sdhci_tegra_suspend(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
 	int ret;
 
 	if (host->mmc->caps2 & MMC_CAP2_CQE) {
@@ -1774,17 +1816,22 @@  static int __maybe_unused sdhci_tegra_suspend(struct device *dev)
 		return ret;
 	}
 
-	clk_disable_unprepare(pltfm_host->clk);
+	ret = pm_runtime_force_suspend(dev);
+	if (ret) {
+		sdhci_resume_host(host);
+		cqhci_resume(host->mmc);
+		return ret;
+	}
+
 	return 0;
 }
 
 static int __maybe_unused sdhci_tegra_resume(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	int ret;
 
-	ret = clk_prepare_enable(pltfm_host->clk);
+	ret = pm_runtime_force_resume(dev);
 	if (ret)
 		return ret;
 
@@ -1803,13 +1850,15 @@  static int __maybe_unused sdhci_tegra_resume(struct device *dev)
 suspend_host:
 	sdhci_suspend_host(host);
 disable_clk:
-	clk_disable_unprepare(pltfm_host->clk);
+	pm_runtime_force_suspend(dev);
 	return ret;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend,
-			 sdhci_tegra_resume);
+static const struct dev_pm_ops sdhci_tegra_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(sdhci_tegra_runtime_suspend, sdhci_tegra_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_tegra_suspend, sdhci_tegra_resume)
+};
 
 static struct platform_driver sdhci_tegra_driver = {
 	.driver		= {