All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Osipenko <digetx@gmail.com>
To: "Thierry Reding" <thierry.reding@gmail.com>,
	"Jonathan Hunter" <jonathanh@nvidia.com>,
	"Ulf Hansson" <ulf.hansson@linaro.org>,
	"Viresh Kumar" <vireshk@kernel.org>,
	"Stephen Boyd" <sboyd@kernel.org>,
	"Peter De Schrijver" <pdeschrijver@nvidia.com>,
	"Mikko Perttunen" <mperttunen@nvidia.com>,
	"Lee Jones" <lee.jones@linaro.org>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Nishanth Menon" <nm@ti.com>,
	"Adrian Hunter" <adrian.hunter@intel.com>,
	"Michael Turquette" <mturquette@baylibre.com>
Cc: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
	linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org,
	linux-mmc@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linux-clk@vger.kernel.org, David Heidelberg <david@ixit.cz>
Subject: [PATCH v14 29/39] soc/tegra: regulators: Prepare for suspend
Date: Tue, 26 Oct 2021 01:40:22 +0300	[thread overview]
Message-ID: <20211025224032.21012-30-digetx@gmail.com> (raw)
In-Reply-To: <20211025224032.21012-1-digetx@gmail.com>

Depending on hardware version, Tegra SoC may require a higher voltages
during resume from system suspend, otherwise hardware will crash. Set
SoC voltages to a nominal levels during suspend.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/soc/tegra/regulators-tegra20.c |  99 ++++++++++++++++++++
 drivers/soc/tegra/regulators-tegra30.c | 122 +++++++++++++++++++++++++
 2 files changed, 221 insertions(+)

diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c
index b8ce9fd0650d..6a2f90ab9d3e 100644
--- a/drivers/soc/tegra/regulators-tegra20.c
+++ b/drivers/soc/tegra/regulators-tegra20.c
@@ -16,7 +16,9 @@
 #include <linux/regulator/coupler.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/suspend.h>
 
+#include <soc/tegra/fuse.h>
 #include <soc/tegra/pmc.h>
 
 struct tegra_regulator_coupler {
@@ -25,9 +27,12 @@ struct tegra_regulator_coupler {
 	struct regulator_dev *cpu_rdev;
 	struct regulator_dev *rtc_rdev;
 	struct notifier_block reboot_notifier;
+	struct notifier_block suspend_notifier;
 	int core_min_uV, cpu_min_uV;
 	bool sys_reboot_mode_req;
 	bool sys_reboot_mode;
+	bool sys_suspend_mode_req;
+	bool sys_suspend_mode;
 };
 
 static inline struct tegra_regulator_coupler *
@@ -105,6 +110,28 @@ static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev,
 	return 150000;
 }
 
+static int tegra20_cpu_nominal_uV(void)
+{
+	switch (tegra_sku_info.soc_speedo_id) {
+	case 0:
+		return 1100000;
+	case 1:
+		return 1025000;
+	default:
+		return 1125000;
+	}
+}
+
+static int tegra20_core_nominal_uV(void)
+{
+	switch (tegra_sku_info.soc_speedo_id) {
+	default:
+		return 1225000;
+	case 2:
+		return 1300000;
+	}
+}
+
 static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra,
 				   struct regulator_dev *core_rdev,
 				   struct regulator_dev *rtc_rdev,
@@ -144,6 +171,11 @@ static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra,
 	if (err)
 		return err;
 
+	/* prepare voltage level for suspend */
+	if (tegra->sys_suspend_mode)
+		core_min_uV = clamp(tegra20_core_nominal_uV(),
+				    core_min_uV, core_max_uV);
+
 	core_uV = regulator_get_voltage_rdev(core_rdev);
 	if (core_uV < 0)
 		return core_uV;
@@ -279,6 +311,11 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
 	if (tegra->sys_reboot_mode)
 		cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
 
+	/* prepare voltage level for suspend */
+	if (tegra->sys_suspend_mode)
+		cpu_min_uV = clamp(tegra20_cpu_nominal_uV(),
+				   cpu_min_uV, cpu_max_uV);
+
 	if (cpu_min_uV > cpu_uV) {
 		err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
 					      cpu_uV, cpu_min_uV);
@@ -320,6 +357,7 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
 	}
 
 	tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
+	tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req);
 
 	if (rdev == cpu_rdev)
 		return tegra20_cpu_voltage_update(tegra, cpu_rdev,
@@ -334,6 +372,63 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
 	return -EPERM;
 }
 
+static int tegra20_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra,
+					     bool sys_suspend_mode)
+{
+	int err;
+
+	if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev)
+		return 0;
+
+	/*
+	 * All power domains are enabled early during resume from suspend
+	 * by GENPD core.  Domains like VENC may require a higher voltage
+	 * when enabled during resume from suspend.  This also prepares
+	 * hardware for resuming from LP0.
+	 */
+
+	WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode);
+
+	err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
+	if (err)
+		return err;
+
+	err = regulator_sync_voltage_rdev(tegra->core_rdev);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int tegra20_regulator_suspend(struct notifier_block *notifier,
+				     unsigned long mode, void *arg)
+{
+	struct tegra_regulator_coupler *tegra;
+	int ret = 0;
+
+	tegra = container_of(notifier, struct tegra_regulator_coupler,
+			     suspend_notifier);
+
+	switch (mode) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_RESTORE_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		ret = tegra20_regulator_prepare_suspend(tegra, true);
+		break;
+
+	case PM_POST_HIBERNATION:
+	case PM_POST_RESTORE:
+	case PM_POST_SUSPEND:
+		ret = tegra20_regulator_prepare_suspend(tegra, false);
+		break;
+	}
+
+	if (ret)
+		pr_err("failed to prepare regulators: %d\n", ret);
+
+	return notifier_from_errno(ret);
+}
+
 static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
 					    bool sys_reboot_mode)
 {
@@ -444,6 +539,7 @@ static struct tegra_regulator_coupler tegra20_coupler = {
 		.balance_voltage = tegra20_regulator_balance_voltage,
 	},
 	.reboot_notifier.notifier_call = tegra20_regulator_reboot,
+	.suspend_notifier.notifier_call = tegra20_regulator_suspend,
 };
 
 static int __init tegra_regulator_coupler_init(void)
@@ -456,6 +552,9 @@ static int __init tegra_regulator_coupler_init(void)
 	err = register_reboot_notifier(&tegra20_coupler.reboot_notifier);
 	WARN_ON(err);
 
+	err = register_pm_notifier(&tegra20_coupler.suspend_notifier);
+	WARN_ON(err);
+
 	return regulator_coupler_register(&tegra20_coupler.coupler);
 }
 arch_initcall(tegra_regulator_coupler_init);
diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c
index e74bbc9c7859..8fd43c689134 100644
--- a/drivers/soc/tegra/regulators-tegra30.c
+++ b/drivers/soc/tegra/regulators-tegra30.c
@@ -16,6 +16,7 @@
 #include <linux/regulator/coupler.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/suspend.h>
 
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/pmc.h>
@@ -25,9 +26,12 @@ struct tegra_regulator_coupler {
 	struct regulator_dev *core_rdev;
 	struct regulator_dev *cpu_rdev;
 	struct notifier_block reboot_notifier;
+	struct notifier_block suspend_notifier;
 	int core_min_uV, cpu_min_uV;
 	bool sys_reboot_mode_req;
 	bool sys_reboot_mode;
+	bool sys_suspend_mode_req;
+	bool sys_suspend_mode;
 };
 
 static inline struct tegra_regulator_coupler *
@@ -113,6 +117,52 @@ static int tegra30_core_cpu_limit(int cpu_uV)
 	return -EINVAL;
 }
 
+static int tegra30_cpu_nominal_uV(void)
+{
+	switch (tegra_sku_info.cpu_speedo_id) {
+	case 10 ... 11:
+		return  850000;
+
+	case 9:
+		return  912000;
+
+	case 1 ...  3:
+	case 7 ...  8:
+		return 1050000;
+
+	default:
+		return 1125000;
+
+	case  4 ...  6:
+	case 12 ... 13:
+		return 1237000;
+	}
+}
+
+static int tegra30_core_nominal_uV(void)
+{
+	switch (tegra_sku_info.soc_speedo_id) {
+	case 0:
+		return 1200000;
+
+	case 1:
+		if (tegra_sku_info.cpu_speedo_id != 7 &&
+		    tegra_sku_info.cpu_speedo_id != 8)
+			return 1200000;
+
+		fallthrough;
+
+	case 2:
+		if (tegra_sku_info.cpu_speedo_id != 13)
+			return 1300000;
+
+		return 1350000;
+
+	default:
+		return 1250000;
+	}
+}
+
 static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
 				  struct regulator_dev *cpu_rdev,
 				  struct regulator_dev *core_rdev)
@@ -168,6 +218,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
 	if (err)
 		return err;
 
+	/* prepare voltage level for suspend */
+	if (tegra->sys_suspend_mode)
+		core_min_uV = clamp(tegra30_core_nominal_uV(),
+				    core_min_uV, core_max_uV);
+
 	core_uV = regulator_get_voltage_rdev(core_rdev);
 	if (core_uV < 0)
 		return core_uV;
@@ -223,6 +278,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
 	if (tegra->sys_reboot_mode)
 		cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
 
+	/* prepare voltage level for suspend */
+	if (tegra->sys_suspend_mode)
+		cpu_min_uV = clamp(tegra30_cpu_nominal_uV(),
+				   cpu_min_uV, cpu_max_uV);
+
 	if (core_min_limited_uV > core_uV) {
 		pr_err("core voltage constraint violated: %d %d %d\n",
 		       core_uV, core_min_limited_uV, cpu_uV);
@@ -292,10 +352,68 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler,
 	}
 
 	tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
+	tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req);
 
 	return tegra30_voltage_update(tegra, cpu_rdev, core_rdev);
 }
 
+static int tegra30_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra,
+					     bool sys_suspend_mode)
+{
+	int err;
+
+	if (!tegra->core_rdev || !tegra->cpu_rdev)
+		return 0;
+
+	/*
+	 * All power domains are enabled early during resume from suspend
+	 * by GENPD core.  Domains like VENC may require a higher voltage
+	 * when enabled during resume from suspend.  This also prepares
+	 * hardware for resuming from LP0.
+	 */
+
+	WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode);
+
+	err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
+	if (err)
+		return err;
+
+	err = regulator_sync_voltage_rdev(tegra->core_rdev);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int tegra30_regulator_suspend(struct notifier_block *notifier,
+				     unsigned long mode, void *arg)
+{
+	struct tegra_regulator_coupler *tegra;
+	int ret = 0;
+
+	tegra = container_of(notifier, struct tegra_regulator_coupler,
+			     suspend_notifier);
+
+	switch (mode) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_RESTORE_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		ret = tegra30_regulator_prepare_suspend(tegra, true);
+		break;
+
+	case PM_POST_HIBERNATION:
+	case PM_POST_RESTORE:
+	case PM_POST_SUSPEND:
+		ret = tegra30_regulator_prepare_suspend(tegra, false);
+		break;
+	}
+
+	if (ret)
+		pr_err("failed to prepare regulators: %d\n", ret);
+
+	return notifier_from_errno(ret);
+}
+
 static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
 					    bool sys_reboot_mode)
 {
@@ -395,6 +513,7 @@ static struct tegra_regulator_coupler tegra30_coupler = {
 		.balance_voltage = tegra30_regulator_balance_voltage,
 	},
 	.reboot_notifier.notifier_call = tegra30_regulator_reboot,
+	.suspend_notifier.notifier_call = tegra30_regulator_suspend,
 };
 
 static int __init tegra_regulator_coupler_init(void)
@@ -407,6 +526,9 @@ static int __init tegra_regulator_coupler_init(void)
 	err = register_reboot_notifier(&tegra30_coupler.reboot_notifier);
 	WARN_ON(err);
 
+	err = register_pm_notifier(&tegra30_coupler.suspend_notifier);
+	WARN_ON(err);
+
 	return regulator_coupler_register(&tegra30_coupler.coupler);
 }
 arch_initcall(tegra_regulator_coupler_init);
-- 
2.33.1


  parent reply	other threads:[~2021-10-25 22:48 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-25 22:39 [PATCH v14 00/39] NVIDIA Tegra power management patches for 5.17 Dmitry Osipenko
2021-10-25 22:39 ` [PATCH v14 01/39] soc/tegra: Enable runtime PM during OPP state-syncing Dmitry Osipenko
2021-10-27 15:06   ` Ulf Hansson
2021-10-27 19:32     ` Dmitry Osipenko
2021-10-25 22:39 ` [PATCH v14 02/39] soc/tegra: Add devm_tegra_core_dev_init_opp_table_common() Dmitry Osipenko
2021-10-25 22:39 ` [PATCH v14 03/39] soc/tegra: Don't print error message when OPPs not available Dmitry Osipenko
2021-10-25 22:39 ` [PATCH v14 04/39] dt-bindings: clock: tegra-car: Document new clock sub-nodes Dmitry Osipenko
2021-10-25 22:39 ` [PATCH v14 05/39] clk: tegra: Support runtime PM and power domain Dmitry Osipenko
2021-10-25 22:39 ` [PATCH v14 06/39] dt-bindings: host1x: Document OPP and power domain properties Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 07/39] dt-bindings: host1x: Document Memory Client resets of Host1x, GR2D and GR3D Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 08/39] gpu: host1x: Add initial runtime PM and OPP support Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 09/39] gpu: host1x: Add host1x_channel_stop() Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 10/39] drm/tegra: dc: Support OPP and SoC core voltage scaling Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 11/39] drm/tegra: hdmi: Add OPP support Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 12/39] drm/tegra: gr2d: Support generic power domain and runtime PM Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 13/39] drm/tegra: gr3d: " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 14/39] drm/tegra: vic: Stop channel on suspend Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 15/39] drm/tegra: nvdec: " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 16/39] drm/tegra: submit: Remove pm_runtime_enabled() checks Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 17/39] drm/tegra: submit: Add missing pm_runtime_mark_last_busy() Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 18/39] usb: chipidea: tegra: Add runtime PM and OPP support Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 19/39] bus: tegra-gmi: " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 20/39] pwm: tegra: " Dmitry Osipenko
2021-10-29 15:20   ` Dmitry Osipenko
2021-10-29 15:28     ` Ulf Hansson
2021-10-29 16:28       ` Dmitry Osipenko
2021-10-29 15:56     ` Rafael J. Wysocki
2021-10-29 16:29       ` Dmitry Osipenko
2021-10-29 18:06         ` Rafael J. Wysocki
2021-10-30  0:47           ` Dmitry Osipenko
2021-10-30  1:04             ` Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 21/39] mmc: sdhci-tegra: " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 22/39] mtd: rawnand: tegra: " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 23/39] spi: tegra20-slink: Add " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 24/39] media: dt: bindings: tegra-vde: Convert to schema Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 25/39] media: dt: bindings: tegra-vde: Document OPP and power domain Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 26/39] media: staging: tegra-vde: Support generic " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 27/39] soc/tegra: fuse: Reset hardware Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 28/39] soc/tegra: fuse: Use resource-managed helpers Dmitry Osipenko
2021-10-25 22:40 ` Dmitry Osipenko [this message]
2021-10-27 15:47   ` [PATCH v14 29/39] soc/tegra: regulators: Prepare for suspend Ulf Hansson
2021-10-27 19:39     ` Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 30/39] soc/tegra: pmc: Rename 3d power domains Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 31/39] soc/tegra: pmc: Rename core power domain Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 32/39] soc/tegra: pmc: Enable core domain support for Tegra20 and Tegra30 Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 33/39] ARM: tegra: Rename CPU and EMC OPP table device-tree nodes Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 34/39] ARM: tegra: Add 500MHz entry to Tegra30 memory OPP table Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 35/39] ARM: tegra: Add OPP tables and power domains to Tegra20 device-trees Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 36/39] ARM: tegra: Add OPP tables and power domains to Tegra30 device-trees Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 37/39] ARM: tegra: Add Memory Client resets to Tegra20 GR2D, GR3D and Host1x Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 38/39] ARM: tegra: Add Memory Client resets to Tegra30 " Dmitry Osipenko
2021-10-25 22:40 ` [PATCH v14 39/39] ARM: tegra20/30: Disable unused host1x hardware Dmitry Osipenko
2021-10-27 16:01 ` [PATCH v14 00/39] NVIDIA Tegra power management patches for 5.17 Ulf Hansson
2021-10-27 19:42   ` Dmitry Osipenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211025224032.21012-30-digetx@gmail.com \
    --to=digetx@gmail.com \
    --cc=adrian.hunter@intel.com \
    --cc=david@ixit.cz \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jonathanh@nvidia.com \
    --cc=lee.jones@linaro.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=mperttunen@nvidia.com \
    --cc=mturquette@baylibre.com \
    --cc=nm@ti.com \
    --cc=pdeschrijver@nvidia.com \
    --cc=sboyd@kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    --cc=ulf.hansson@linaro.org \
    --cc=vireshk@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.