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>,
	Peter De Schrijver <pdeschrijver@nvidia.com>,
	Prashant Gaikwad <pgaikwad@nvidia.com>,
	"Rafael J. Wysocki" <rjw@rjwysocki.net>,
	Viresh Kumar <viresh.kumar@linaro.org>,
	Rob Herring <robh+dt@kernel.org>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>
Cc: Peter Geis <pgwipeout@gmail.com>,
	Nicolas Chauvet <kwizart@gmail.com>,
	Marcel Ziswiler <marcel.ziswiler@toradex.com>,
	linux-pm@vger.kernel.org, linux-tegra@vger.kernel.org,
	devicetree@vger.kernel.org, linux-clk@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH v1 07/17] cpufreq: tegra20: Use generic cpufreq-dt driver (Tegra30 supported now)
Date: Wed, 16 Oct 2019 00:16:08 +0300	[thread overview]
Message-ID: <20191015211618.20758-8-digetx@gmail.com> (raw)
In-Reply-To: <20191015211618.20758-1-digetx@gmail.com>

Re-parenting to intermediate clock is supported now by the clock driver
and thus there is no need in a customized CPUFreq driver, all that code
is common for both Tegra20 and Tegra30. The available CPU freqs are now
specified in device-tree in a form of OPPs, all users should update their
device-trees.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/cpufreq/Kconfig.arm          |   4 +-
 drivers/cpufreq/cpufreq-dt-platdev.c |   2 +
 drivers/cpufreq/tegra20-cpufreq.c    | 236 ++++++---------------------
 3 files changed, 55 insertions(+), 187 deletions(-)

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index a905796f7f85..2118c45d0acd 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -301,8 +301,8 @@ config ARM_TANGO_CPUFREQ
 	default y
 
 config ARM_TEGRA20_CPUFREQ
-	tristate "Tegra20 CPUFreq support"
-	depends on ARCH_TEGRA
+	bool "Tegra20 CPUFreq support"
+	depends on ARCH_TEGRA && CPUFREQ_DT
 	default y
 	help
 	  This adds the CPUFreq driver support for Tegra20 SOCs.
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 54bc76743b1f..07e88dcd112d 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -121,6 +121,8 @@ static const struct of_device_id blacklist[] __initconst = {
 	{ .compatible = "mediatek,mt8176", },
 	{ .compatible = "mediatek,mt8183", },
 
+	{ .compatible = "nvidia,tegra20", },
+	{ .compatible = "nvidia,tegra30", },
 	{ .compatible = "nvidia,tegra124", },
 	{ .compatible = "nvidia,tegra210", },
 
diff --git a/drivers/cpufreq/tegra20-cpufreq.c b/drivers/cpufreq/tegra20-cpufreq.c
index f84ecd22f488..042017c73afa 100644
--- a/drivers/cpufreq/tegra20-cpufreq.c
+++ b/drivers/cpufreq/tegra20-cpufreq.c
@@ -7,215 +7,81 @@
  *	Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
  */
 
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
+#define pr_fmt(fmt) "tegra20-cpufreq: " fmt
+
+#include <linux/bits.h>
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_opp.h>
 #include <linux/types.h>
 
-static struct cpufreq_frequency_table freq_table[] = {
-	{ .frequency = 216000 },
-	{ .frequency = 312000 },
-	{ .frequency = 456000 },
-	{ .frequency = 608000 },
-	{ .frequency = 760000 },
-	{ .frequency = 816000 },
-	{ .frequency = 912000 },
-	{ .frequency = 1000000 },
-	{ .frequency = CPUFREQ_TABLE_END },
-};
-
-struct tegra20_cpufreq {
-	struct device *dev;
-	struct cpufreq_driver driver;
-	struct clk *cpu_clk;
-	struct clk *pll_x_clk;
-	struct clk *pll_p_clk;
-	bool pll_x_prepared;
-};
-
-static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy,
-					   unsigned int index)
-{
-	struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
-	unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000;
-
-	/*
-	 * Don't switch to intermediate freq if:
-	 * - we are already at it, i.e. policy->cur == ifreq
-	 * - index corresponds to ifreq
-	 */
-	if (freq_table[index].frequency == ifreq || policy->cur == ifreq)
-		return 0;
-
-	return ifreq;
-}
+#include <soc/tegra/common.h>
+#include <soc/tegra/fuse.h>
 
-static int tegra_target_intermediate(struct cpufreq_policy *policy,
-				     unsigned int index)
+static bool __init cpu0_node_has_opp_v2_prop(void)
 {
-	struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
-	int ret;
-
-	/*
-	 * Take an extra reference to the main pll so it doesn't turn
-	 * off when we move the cpu off of it as enabling it again while we
-	 * switch to it from tegra_target() would take additional time.
-	 *
-	 * When target-freq is equal to intermediate freq we don't need to
-	 * switch to an intermediate freq and so this routine isn't called.
-	 * Also, we wouldn't be using pll_x anymore and must not take extra
-	 * reference to it, as it can be disabled now to save some power.
-	 */
-	clk_prepare_enable(cpufreq->pll_x_clk);
-
-	ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk);
-	if (ret)
-		clk_disable_unprepare(cpufreq->pll_x_clk);
-	else
-		cpufreq->pll_x_prepared = true;
+	struct device_node *np = of_cpu_device_node_get(0);
+	bool ret = false;
 
-	return ret;
-}
-
-static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
-{
-	struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
-	unsigned long rate = freq_table[index].frequency;
-	unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000;
-	int ret;
-
-	/*
-	 * target freq == pll_p, don't need to take extra reference to pll_x_clk
-	 * as it isn't used anymore.
-	 */
-	if (rate == ifreq)
-		return clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk);
-
-	ret = clk_set_rate(cpufreq->pll_x_clk, rate * 1000);
-	/* Restore to earlier frequency on error, i.e. pll_x */
-	if (ret)
-		dev_err(cpufreq->dev, "Failed to change pll_x to %lu\n", rate);
-
-	ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_x_clk);
-	/* This shouldn't fail while changing or restoring */
-	WARN_ON(ret);
-
-	/*
-	 * Drop count to pll_x clock only if we switched to intermediate freq
-	 * earlier while transitioning to a target frequency.
-	 */
-	if (cpufreq->pll_x_prepared) {
-		clk_disable_unprepare(cpufreq->pll_x_clk);
-		cpufreq->pll_x_prepared = false;
-	}
+	if (of_get_property(np, "operating-points-v2", NULL))
+		ret = true;
 
+	of_node_put(np);
 	return ret;
 }
 
-static int tegra_cpu_init(struct cpufreq_policy *policy)
+static int __init tegra20_cpufreq_init(void)
 {
-	struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
-
-	clk_prepare_enable(cpufreq->cpu_clk);
-
-	/* FIXME: what's the actual transition time? */
-	cpufreq_generic_init(policy, freq_table, 300 * 1000);
-	policy->clk = cpufreq->cpu_clk;
-	policy->suspend_freq = freq_table[0].frequency;
-	return 0;
-}
-
-static int tegra_cpu_exit(struct cpufreq_policy *policy)
-{
-	struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
-
-	clk_disable_unprepare(cpufreq->cpu_clk);
-	return 0;
-}
-
-static int tegra20_cpufreq_probe(struct platform_device *pdev)
-{
-	struct tegra20_cpufreq *cpufreq;
+	struct platform_device *cpufreq_dt;
+	struct opp_table *opp_table;
+	u32 versions[2];
 	int err;
 
-	cpufreq = devm_kzalloc(&pdev->dev, sizeof(*cpufreq), GFP_KERNEL);
-	if (!cpufreq)
-		return -ENOMEM;
+	if (!soc_is_tegra())
+		return 0;
 
-	cpufreq->cpu_clk = clk_get_sys(NULL, "cclk");
-	if (IS_ERR(cpufreq->cpu_clk))
-		return PTR_ERR(cpufreq->cpu_clk);
+	switch (tegra_get_chip_id()) {
+	case TEGRA20:
+		versions[0] = BIT(tegra_sku_info.cpu_process_id);
+		versions[1] = BIT(tegra_sku_info.soc_speedo_id);
+		break;
+	case TEGRA30:
+		versions[0] = BIT(tegra_sku_info.cpu_process_id);
+		versions[1] = BIT(tegra_sku_info.cpu_speedo_id);
+		break;
+	default:
+		return 0;
+	}
 
-	cpufreq->pll_x_clk = clk_get_sys(NULL, "pll_x");
-	if (IS_ERR(cpufreq->pll_x_clk)) {
-		err = PTR_ERR(cpufreq->pll_x_clk);
-		goto put_cpu;
+	if (!cpu0_node_has_opp_v2_prop()) {
+		pr_err("operating points not found\n");
+		pr_err("can't continue, please update your device tree\n");
+		return 0;
 	}
 
-	cpufreq->pll_p_clk = clk_get_sys(NULL, "pll_p");
-	if (IS_ERR(cpufreq->pll_p_clk)) {
-		err = PTR_ERR(cpufreq->pll_p_clk);
-		goto put_pll_x;
+	pr_info("hardware version 0x%x 0x%x\n", versions[0], versions[1]);
+
+	opp_table = dev_pm_opp_set_supported_hw(get_cpu_device(0), versions, 2);
+	err = PTR_ERR_OR_ZERO(opp_table);
+	if (err) {
+		pr_err("failed to set supported hw: %d\n", err);
+		return err;
 	}
 
-	cpufreq->dev = &pdev->dev;
-	cpufreq->driver.get = cpufreq_generic_get;
-	cpufreq->driver.attr = cpufreq_generic_attr;
-	cpufreq->driver.init = tegra_cpu_init;
-	cpufreq->driver.exit = tegra_cpu_exit;
-	cpufreq->driver.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK;
-	cpufreq->driver.verify = cpufreq_generic_frequency_table_verify;
-	cpufreq->driver.suspend = cpufreq_generic_suspend;
-	cpufreq->driver.driver_data = cpufreq;
-	cpufreq->driver.target_index = tegra_target;
-	cpufreq->driver.get_intermediate = tegra_get_intermediate;
-	cpufreq->driver.target_intermediate = tegra_target_intermediate;
-	snprintf(cpufreq->driver.name, CPUFREQ_NAME_LEN, "tegra");
-
-	err = cpufreq_register_driver(&cpufreq->driver);
-	if (err)
-		goto put_pll_p;
-
-	platform_set_drvdata(pdev, cpufreq);
+	cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+	err = PTR_ERR_OR_ZERO(cpufreq_dt);
+	if (err) {
+		pr_err("failed to create cpufreq-dt device: %d\n", err);
+		goto err_put_supported_hw;
+	}
 
 	return 0;
 
-put_pll_p:
-	clk_put(cpufreq->pll_p_clk);
-put_pll_x:
-	clk_put(cpufreq->pll_x_clk);
-put_cpu:
-	clk_put(cpufreq->cpu_clk);
+err_put_supported_hw:
+	dev_pm_opp_put_supported_hw(opp_table);
 
 	return err;
 }
-
-static int tegra20_cpufreq_remove(struct platform_device *pdev)
-{
-	struct tegra20_cpufreq *cpufreq = platform_get_drvdata(pdev);
-
-	cpufreq_unregister_driver(&cpufreq->driver);
-
-	clk_put(cpufreq->pll_p_clk);
-	clk_put(cpufreq->pll_x_clk);
-	clk_put(cpufreq->cpu_clk);
-
-	return 0;
-}
-
-static struct platform_driver tegra20_cpufreq_driver = {
-	.probe		= tegra20_cpufreq_probe,
-	.remove		= tegra20_cpufreq_remove,
-	.driver		= {
-		.name	= "tegra20-cpufreq",
-	},
-};
-module_platform_driver(tegra20_cpufreq_driver);
-
-MODULE_ALIAS("platform:tegra20-cpufreq");
-MODULE_AUTHOR("Colin Cross <ccross@android.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra20 cpufreq driver");
-MODULE_LICENSE("GPL");
+late_initcall(tegra20_cpufreq_init);
-- 
2.23.0

  parent reply	other threads:[~2019-10-15 21:16 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-15 21:16 [PATCH v1 00/17] NVIDIA Tegra20 CPUFreq driver major update Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 01/17] clk: tegra: Add custom CCLK implementation Dmitry Osipenko
2019-10-28 14:57   ` Peter De Schrijver
2019-10-28 14:57     ` Peter De Schrijver
2019-10-28 23:48     ` Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 02/17] clk: tegra: pll: Add pre/post rate-change hooks Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 03/17] clk: tegra: cclk: Add helpers for handling PLLX rate changes Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 04/17] clk: tegra20: Support custom CCLK implementation Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 05/17] clk: tegra30: " Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 06/17] dt-bindings: cpufreq: Add binding for NVIDIA Tegra20/30 Dmitry Osipenko
2019-10-16  5:13   ` Viresh Kumar
2019-10-17  2:32   ` Viresh Kumar
2019-10-15 21:16 ` Dmitry Osipenko [this message]
2019-10-16  5:18   ` [PATCH v1 07/17] cpufreq: tegra20: Use generic cpufreq-dt driver (Tegra30 supported now) Viresh Kumar
2019-10-16 13:29     ` Dmitry Osipenko
2019-10-16 14:58       ` Peter Geis
2019-10-16 18:19         ` Dmitry Osipenko
2019-10-17  2:32           ` Viresh Kumar
2019-10-17 21:09             ` Dmitry Osipenko
2019-10-17  2:33   ` Viresh Kumar
2019-10-15 21:16 ` [PATCH v1 08/17] ARM: tegra: Remove tegra20-cpufreq platform device creation Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 09/17] ARM: dts: tegra20: Add CPU clock Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 10/17] ARM: dts: tegra30: " Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 11/17] ARM: dts: tegra20: Add CPU Operating Performance Points Dmitry Osipenko
2019-10-16  5:23   ` Viresh Kumar
2019-10-16 13:21     ` Dmitry Osipenko
2019-10-17  2:28       ` Viresh Kumar
2019-10-17  2:32   ` Viresh Kumar
2019-10-15 21:16 ` [PATCH v1 12/17] ARM: dts: tegra30: " Dmitry Osipenko
2019-10-17  2:33   ` Viresh Kumar
2019-10-15 21:16 ` [PATCH v1 13/17] ARM: dts: tegra20: paz00: Set up voltage regulators for DVFS Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 14/17] ARM: dts: tegra20: paz00: Add CPU Operating Performance Points Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 15/17] ARM: dts: tegra20: trimslice: " Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 16/17] ARM: dts: tegra30: beaver: Set up voltage regulators for DVFS Dmitry Osipenko
2019-10-15 21:16 ` [PATCH v1 17/17] ARM: dts: tegra30: beaver: Add CPU Operating Performance Points Dmitry Osipenko
2019-10-16  5:27 ` [PATCH v1 00/17] NVIDIA Tegra20 CPUFreq driver major update Viresh Kumar
2019-10-16 13:16   ` Dmitry Osipenko
2019-10-16 14:01     ` Thierry Reding
2019-10-16 14:20       ` 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=20191015211618.20758-8-digetx@gmail.com \
    --to=digetx@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=jonathanh@nvidia.com \
    --cc=kwizart@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=marcel.ziswiler@toradex.com \
    --cc=mturquette@baylibre.com \
    --cc=pdeschrijver@nvidia.com \
    --cc=pgaikwad@nvidia.com \
    --cc=pgwipeout@gmail.com \
    --cc=rjw@rjwysocki.net \
    --cc=robh+dt@kernel.org \
    --cc=sboyd@kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=viresh.kumar@linaro.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.