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>,
	"Michał Mirosław" <mirq-linux@rere.qmqm.pl>,
	"Nikola Milosavljević" <mnidza@outlook.com>,
	"Ulf Hansson" <ulf.hansson@linaro.org>,
	"Peter Geis" <pgwipeout@gmail.com>,
	"Nicolas Chauvet" <kwizart@gmail.com>,
	"Viresh Kumar" <vireshk@kernel.org>,
	"Stephen Boyd" <sboyd@kernel.org>,
	"Matt Merhar" <mattmerhar@protonmail.com>,
	"Paul Fertser" <fercerpav@gmail.com>,
	"Mark Brown" <broonie@kernel.org>,
	"Liam Girdwood" <lgirdwood@gmail.com>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski@canonical.com>,
	"Mikko Perttunen" <mperttunen@nvidia.com>
Cc: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
	devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
	Nathan Chancellor <nathan@kernel.org>,
	linux-clk@vger.kernel.org
Subject: [PATCH v6 12/14] soc/tegra: pmc: Add core power domain
Date: Tue,  1 Jun 2021 05:31:17 +0300	[thread overview]
Message-ID: <20210601023119.22044-13-digetx@gmail.com> (raw)
In-Reply-To: <20210601023119.22044-1-digetx@gmail.com>

NVIDIA Tegra SoCs have multiple power domains, each domain corresponds
to an external SoC power rail. Core power domain covers vast majority of
hardware blocks within a Tegra SoC. The voltage of a power domain should
be set to a level which satisfies all devices within the power domain.
Add support for the core power domain which controls voltage state of the
domain. This allows us to support system-wide DVFS on Tegra20-210 SoCs.
The PMC powergate domains now are sub-domains of the core domain, this
requires device-tree updating, older DTBs are unaffected and will continue
to work as before.

Tested-by: Peter Geis <pgwipeout@gmail.com> # Ouya T30
Tested-by: Paul Fertser <fercerpav@gmail.com> # PAZ00 T20
Tested-by: Nicolas Chauvet <kwizart@gmail.com> # PAZ00 T20 and TK1 T124
Tested-by: Matt Merhar <mattmerhar@protonmail.com> # Ouya T30
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/soc/tegra/Kconfig |   2 +
 drivers/soc/tegra/pmc.c   | 120 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 122 insertions(+)

diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index 976dee036470..20ace654553a 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -144,6 +144,8 @@ config SOC_TEGRA_FLOWCTRL
 config SOC_TEGRA_PMC
 	bool
 	select GENERIC_PINCONF
+	select PM_OPP
+	select PM_GENERIC_DOMAINS
 
 config SOC_TEGRA_POWERGATE_BPMP
 	def_bool y
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 4a582eae82ef..7e07910b9b88 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -38,6 +38,7 @@
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
 #include <linux/reboot.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
@@ -1297,12 +1298,110 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 	return err;
 }
 
+static int
+tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
+					unsigned int level)
+{
+	struct dev_pm_opp *opp;
+	int err;
+
+	opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
+	if (IS_ERR(opp)) {
+		dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n",
+			level, opp);
+		return PTR_ERR(opp);
+	}
+
+	mutex_lock(&pmc->powergates_lock);
+	err = dev_pm_opp_set_opp(pmc->dev, opp);
+	mutex_unlock(&pmc->powergates_lock);
+
+	dev_pm_opp_put(opp);
+
+	if (err) {
+		dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n",
+			level, err);
+		return err;
+	}
+
+	return 0;
+}
+
+static unsigned int
+tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
+					   struct dev_pm_opp *opp)
+{
+	return dev_pm_opp_get_level(opp);
+}
+
+static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
+{
+	static struct lock_class_key tegra_core_domain_lock_class;
+	struct generic_pm_domain *genpd;
+	const char *rname = "core";
+	int err;
+
+	genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
+	if (!genpd)
+		return -ENOMEM;
+
+	genpd->name = np->name;
+	genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
+	genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
+
+	err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
+	if (err)
+		return dev_err_probe(pmc->dev, err,
+				     "failed to set core OPP regulator\n");
+
+	err = pm_genpd_init(genpd, NULL, false);
+	if (err) {
+		dev_err(pmc->dev, "failed to init core genpd: %d\n", err);
+		return err;
+	}
+
+	/*
+	 * We have a "PMC pwrgate -> Core" hierarchy of the power domains
+	 * where PMC needs to resume and change performance (voltage) of the
+	 * Core domain from the PMC GENPD on/off callbacks, hence we need
+	 * to annotate the lock in order to remove confusion from the
+	 * lockdep checker when a nested access happens.
+	 */
+	lockdep_set_class(&genpd->mlock, &tegra_core_domain_lock_class);
+
+	err = of_genpd_add_provider_simple(np, genpd);
+	if (err) {
+		dev_err(pmc->dev, "failed to add core genpd: %d\n", err);
+		goto remove_genpd;
+	}
+
+	return 0;
+
+remove_genpd:
+	pm_genpd_remove(genpd);
+
+	return err;
+}
+
 static int tegra_powergate_init(struct tegra_pmc *pmc,
 				struct device_node *parent)
 {
+	struct of_phandle_args child_args, parent_args;
 	struct device_node *np, *child;
 	int err = 0;
 
+	/*
+	 * Core power domain is the parent of powergate domains, hence it
+	 * should be registered first.
+	 */
+	np = of_get_child_by_name(parent, "core-domain");
+	if (np) {
+		err = tegra_pmc_core_pd_add(pmc, np);
+		of_node_put(np);
+		if (err)
+			return err;
+	}
+
 	np = of_get_child_by_name(parent, "powergates");
 	if (!np)
 		return 0;
@@ -1313,6 +1412,21 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,
 			of_node_put(child);
 			break;
 		}
+
+		if (of_parse_phandle_with_args(child, "power-domains",
+					       "#power-domain-cells",
+					       0, &parent_args))
+			continue;
+
+		child_args.np = child;
+		child_args.args_count = 0;
+
+		err = of_genpd_add_subdomain(&parent_args, &child_args);
+		of_node_put(parent_args.np);
+		if (err) {
+			of_node_put(child);
+			break;
+		}
 	}
 
 	of_node_put(np);
@@ -1356,6 +1470,12 @@ static void tegra_powergate_remove_all(struct device_node *parent)
 	}
 
 	of_node_put(np);
+
+	np = of_get_child_by_name(parent, "core-domain");
+	if (np) {
+		of_genpd_del_provider(np);
+		of_genpd_remove_last(np);
+	}
 }
 
 static const struct tegra_io_pad_soc *
-- 
2.30.2


  parent reply	other threads:[~2021-06-01  2:33 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-01  2:31 [PATCH v6 00/14] NVIDIA Tegra memory and power management changes for 5.14 Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 01/14] regulator: core: Add regulator_sync_voltage_rdev() Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 02/14] soc/tegra: regulators: Bump voltages on system reboot Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 03/14] soc/tegra: Add stub for soc_is_tegra() Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 04/14] soc/tegra: Add devm_tegra_core_dev_init_opp_table() Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 05/14] soc/tegra: fuse: Add stubs needed for compile-testing Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 06/14] clk: tegra: " Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 07/14] memory: tegra: Fix compilation warnings on 64bit platforms Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 08/14] memory: tegra: Enable compile testing for all drivers Dmitry Osipenko
2021-06-07  6:01   ` Krzysztof Kozlowski
2021-06-07 13:36     ` Thierry Reding
2021-06-07 13:37       ` Dmitry Osipenko
2021-06-07 14:01       ` Dmitry Osipenko
2021-06-07 14:19         ` Thierry Reding
2021-06-07 14:42           ` Krzysztof Kozlowski
2021-06-08 15:18             ` Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 09/14] memory: tegra20-emc: Use devm_tegra_core_dev_init_opp_table() Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 10/14] memory: tegra30-emc: " Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 11/14] dt-bindings: soc: tegra-pmc: Document core power domain Dmitry Osipenko
2021-06-01  2:31 ` Dmitry Osipenko [this message]
2021-06-01  2:31 ` [PATCH v6 13/14] soc/tegra: pmc: Add driver state syncing Dmitry Osipenko
2021-06-01  2:31 ` [PATCH v6 14/14] soc/tegra: regulators: Support core domain " Dmitry Osipenko
2021-06-01 11:27 ` [PATCH v6 00/14] NVIDIA Tegra memory and power management changes for 5.14 Thierry Reding
2021-06-01 15:51   ` Dmitry Osipenko
2021-06-01 17:10     ` Thierry Reding
2021-06-01 18:00       ` 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=20210601023119.22044-13-digetx@gmail.com \
    --to=digetx@gmail.com \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=fercerpav@gmail.com \
    --cc=jonathanh@nvidia.com \
    --cc=krzysztof.kozlowski@canonical.com \
    --cc=kwizart@gmail.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=mattmerhar@protonmail.com \
    --cc=mirq-linux@rere.qmqm.pl \
    --cc=mnidza@outlook.com \
    --cc=mperttunen@nvidia.com \
    --cc=nathan@kernel.org \
    --cc=pgwipeout@gmail.com \
    --cc=sboyd@kernel.org \
    --cc=thierry.reding@gmail.com \
    --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.