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>
Cc: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
linux-pm@vger.kernel.org
Subject: [PATCH v7 02/37] soc/tegra: pmc: Implement attach_dev() of power domain drivers
Date: Fri, 2 Jul 2021 02:26:53 +0300 [thread overview]
Message-ID: <20210701232728.23591-3-digetx@gmail.com> (raw)
In-Reply-To: <20210701232728.23591-1-digetx@gmail.com>
Implement attach_dev() callback of power domain drivers that initializes
the domain's performance state. GENPD core will apply the performance
state on the first runtime PM resume of the attached device.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
drivers/soc/tegra/pmc.c | 147 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 147 insertions(+)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index f63dfb2ca3f9..ebafb818b08e 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -506,6 +506,151 @@ static void tegra_pmc_scratch_writel(struct tegra_pmc *pmc, u32 value,
writel(value, pmc->scratch + offset);
}
+static const char * const tegra_emc_compats[] = {
+ "nvidia,tegra20-emc",
+ "nvidia,tegra30-emc",
+ NULL,
+};
+
+/*
+ * This GENPD callback is used by both powergate and core domains.
+ *
+ * We retrieve clock rate of the attached device and initialize domain's
+ * performance state in accordance to the clock rate.
+ */
+static int tegra_pmc_pd_attach_dev(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
+ struct opp_table *opp_table, *pd_opp_table;
+ struct generic_pm_domain *core_genpd;
+ struct dev_pm_opp *opp, *pd_opp;
+ unsigned long rate, state;
+ struct gpd_link *link;
+ struct clk *clk;
+ u32 hw_version;
+ int ret;
+
+ /*
+ * Tegra114+ SocS don't support OPP yet. But if they will get OPP
+ * support, then we want to skip OPP for older kernels to preserve
+ * compatibility of newer DTBs with older kernels.
+ */
+ if (!pmc->soc->supports_core_domain)
+ return 0;
+
+ /*
+ * The EMC devices are a special case because we have a protection
+ * from non-EMC drivers getting clock handle before EMC driver is
+ * fully initialized. The goal of the protection is to prevent
+ * devfreq driver from getting failures if it will try to change
+ * EMC clock rate until clock is fully initialized. The EMC drivers
+ * will initialize the performance state by themselves.
+ */
+ if (of_device_compatible_match(dev->of_node, tegra_emc_compats))
+ return 0;
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&genpd->dev, "failed to get clk of %s: %pe\n",
+ dev_name(dev), clk);
+ return PTR_ERR(clk);
+ }
+
+ rate = clk_get_rate(clk);
+ if (!rate) {
+ dev_err(&genpd->dev, "failed to get clk rate of %s\n",
+ dev_name(dev));
+ ret = -EINVAL;
+ goto put_clk;
+ }
+
+ if (of_machine_is_compatible("nvidia,tegra20"))
+ hw_version = BIT(tegra_sku_info.soc_process_id);
+ else
+ hw_version = BIT(tegra_sku_info.soc_speedo_id);
+
+ opp_table = dev_pm_opp_set_supported_hw(dev, &hw_version, 1);
+ if (IS_ERR(opp_table)) {
+ dev_err(&genpd->dev, "failed to set OPP supported HW for %s: %d\n",
+ dev_name(dev), ret);
+ ret = PTR_ERR(opp_table);
+ goto put_clk;
+ }
+
+ ret = dev_pm_opp_of_add_table(dev);
+ if (ret) {
+ /* older DTBs that don't have OPPs will get -ENODEV here */
+ if (ret != -ENODEV)
+ dev_err(&genpd->dev, "failed to get OPP table of %s: %d\n",
+ dev_name(dev), ret);
+ else
+ ret = 0;
+
+ goto put_supported_hw;
+ }
+
+ /* find suitable OPP for the rate */
+ opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+
+ if (opp == ERR_PTR(-ERANGE))
+ opp = dev_pm_opp_find_freq_floor(dev, &rate);
+
+ if (IS_ERR(opp)) {
+ dev_err(&genpd->dev, "failed to find OPP for %luHz of %s: %pe\n",
+ rate, dev_name(dev), opp);
+ ret = PTR_ERR(opp);
+ goto remove_dev_table;
+ }
+
+ if (!list_empty(&genpd->child_links)) {
+ link = list_first_entry(&genpd->child_links, struct gpd_link,
+ child_node);
+ core_genpd = link->parent;
+ } else {
+ core_genpd = genpd;
+ }
+
+ pd_opp_table = dev_pm_opp_get_opp_table(&core_genpd->dev);
+ if (IS_ERR(pd_opp_table)) {
+ dev_err(&genpd->dev, "failed to get OPP table of %s: %pe\n",
+ dev_name(&core_genpd->dev), pd_opp_table);
+ ret = PTR_ERR(pd_opp_table);
+ goto put_dev_opp;
+ }
+
+ pd_opp = dev_pm_opp_xlate_required_opp(opp_table, pd_opp_table, opp);
+ if (IS_ERR(pd_opp)) {
+ dev_err(&genpd->dev,
+ "failed to xlate required OPP for %luHz of %s: %pe\n",
+ rate, dev_name(dev), pd_opp);
+ ret = PTR_ERR(pd_opp);
+ goto put_pd_opp_table;
+ }
+
+ /*
+ * The initialized state will be applied by GENPD core on the first
+ * RPM-resume of the device. This means that drivers don't need to
+ * explicitly initialize performance state.
+ */
+ state = pm_genpd_opp_to_performance_state(&core_genpd->dev, pd_opp);
+ gpd_data->rpm_pstate = state;
+ dev_pm_opp_put(pd_opp);
+
+put_pd_opp_table:
+ dev_pm_opp_put_opp_table(pd_opp_table);
+put_dev_opp:
+ dev_pm_opp_put(opp);
+remove_dev_table:
+ dev_pm_opp_of_remove_table(dev);
+put_supported_hw:
+ dev_pm_opp_put_supported_hw(opp_table);
+put_clk:
+ clk_put(clk);
+
+ return ret;
+}
+
/*
* TODO Figure out a way to call this with the struct tegra_pmc * passed in.
* This currently doesn't work because readx_poll_timeout() can only operate
@@ -1238,6 +1383,7 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
pg->id = id;
pg->genpd.name = np->name;
+ pg->genpd.attach_dev = tegra_pmc_pd_attach_dev;
pg->genpd.power_off = tegra_genpd_power_off;
pg->genpd.power_on = tegra_genpd_power_on;
pg->pmc = pmc;
@@ -1354,6 +1500,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
return -ENOMEM;
genpd->name = np->name;
+ genpd->attach_dev = tegra_pmc_pd_attach_dev;
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
--
2.30.2
next prev parent reply other threads:[~2021-07-01 23:28 UTC|newest]
Thread overview: 58+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-01 23:26 [PATCH v7 00/37] NVIDIA Tegra power management patches for 5.15 Dmitry Osipenko
2021-07-01 23:26 ` [PATCH v7 01/37] soc/tegra: pmc: Temporarily disable PMC state syncing Dmitry Osipenko
2021-08-12 16:02 ` Dmitry Osipenko
2021-07-01 23:26 ` Dmitry Osipenko [this message]
2021-08-02 14:48 ` [PATCH v7 02/37] soc/tegra: pmc: Implement attach_dev() of power domain drivers Ulf Hansson
2021-08-02 18:23 ` Dmitry Osipenko
2021-08-04 9:59 ` Ulf Hansson
2021-08-04 21:16 ` Dmitry Osipenko
2021-08-09 14:15 ` Ulf Hansson
2021-08-09 23:56 ` Dmitry Osipenko
2021-08-10 10:51 ` Ulf Hansson
2021-08-11 19:30 ` Dmitry Osipenko
2021-08-11 22:41 ` Dmitry Osipenko
2021-08-12 1:40 ` Dmitry Osipenko
2021-08-12 11:17 ` Ulf Hansson
2021-08-12 16:24 ` Dmitry Osipenko
2021-07-01 23:26 ` [PATCH v7 03/37] soc/tegra: Don't print error message when OPPs not available Dmitry Osipenko
2021-07-01 23:26 ` [PATCH v7 04/37] soc/tegra: Add devm_tegra_core_dev_init_opp_table_simple() Dmitry Osipenko
2021-07-01 23:26 ` [PATCH v7 05/37] dt-bindings: clock: tegra-car: Document new tegra-clocks node Dmitry Osipenko
2021-07-01 23:26 ` [PATCH v7 06/37] clk: tegra: Support runtime PM and power domain Dmitry Osipenko
2021-07-01 23:26 ` [PATCH v7 07/37] dt-bindings: host1x: Document OPP and power domain properties Dmitry Osipenko
2021-07-01 23:26 ` [PATCH v7 08/37] dt-bindings: host1x: Document Memory Client resets of Host1x, GR2D and GR3D Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 09/37] gpu: host1x: Add host1x_channel_stop() Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 10/37] gpu: host1x: Add runtime PM support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 11/37] gpu: host1x: Add stub driver for MPE, VI, EPP and ISP Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 12/37] drm/tegra: dc: Support OPP and SoC core voltage scaling Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 13/37] drm/tegra: hdmi: Add OPP support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 14/37] drm/tegra: gr2d: Support OPP and power management Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 15/37] drm/tegra: gr3d: " Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 16/37] drm/tegra: vic: Stop channel before suspending Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 17/37] usb: chipidea: tegra: Add runtime PM support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 18/37] bus: tegra-gmi: " Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 19/37] pwm: tegra: Add runtime PM and OPP support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 20/37] mmc: sdhci-tegra: " Dmitry Osipenko
2021-07-02 3:39 ` kernel test robot
2021-07-02 3:39 ` kernel test robot
2021-07-01 23:27 ` [PATCH v7 21/37] mtd: rawnand: tegra: Add runtime PM support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 22/37] soc/tegra: fuse: Clear fuse->clk on driver probe failure Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 23/37] soc/tegra: fuse: Add runtime PM support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 24/37] soc/tegra: fuse: Enable fuse clock on suspend Dmitry Osipenko
2021-07-21 16:00 ` Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 25/37] clk: tegra: Remove CLK_IS_CRITICAL flag from fuse clock Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 26/37] spi: tegra20-slink: Improve runtime PM usage Dmitry Osipenko
2021-07-02 8:29 ` kernel test robot
2021-07-02 8:29 ` kernel test robot
2021-07-01 23:27 ` [PATCH v7 27/37] spi: tegra20-slink: Add OPP support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 28/37] memory: tegra20-emc: Add minimal runtime PM support Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 29/37] memory: tegra30-emc: " Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 30/37] media: dt: bindings: tegra-vde: Convert to schema Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 31/37] media: dt: bindings: tegra-vde: Document OPP and power domain Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 32/37] media: staging: tegra-vde: Support generic " Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 33/37] ARM: tegra: Add OPP tables and power domains to Tegra20 device-trees Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 34/37] ARM: tegra: Add OPP tables and power domains to Tegra30 device-trees Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 35/37] ARM: tegra: Add Memory Client resets to Tegra20 GR2D, GR3D and Host1x Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 36/37] ARM: tegra: Add Memory Client resets to Tegra30 " Dmitry Osipenko
2021-07-01 23:27 ` [PATCH v7 37/37] soc/tegra: pmc: Enable core domain support on Tegra20 and Tegra30 Dmitry Osipenko
2021-07-09 13:01 ` [PATCH v7 00/37] NVIDIA Tegra power management patches for 5.15 Ulf Hansson
2021-07-09 21:23 ` 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=20210701232728.23591-3-digetx@gmail.com \
--to=digetx@gmail.com \
--cc=jonathanh@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=pdeschrijver@nvidia.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.