linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
To: Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>, Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Viresh Kumar <vireshk@kernel.org>, Nishanth Menon <nm@ti.com>,
	Alim Akhtar <alim.akhtar@samsung.com>,
	Avri Altman <avri.altman@wdc.com>,
	"James E.J. Bottomley" <jejb@linux.ibm.com>,
	"Martin K. Petersen" <martin.petersen@oracle.com>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	Taniya Das <tdas@codeaurora.org>,
	linux-arm-msm@vger.kernel.org, linux-clk@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pm@vger.kernel.org, linux-scsi@vger.kernel.org
Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>,
	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Subject: [PATCH v3 6/7] PM: opp: parse multiple frequencies in each OPP
Date: Fri, 13 May 2022 08:13:46 +0200	[thread overview]
Message-ID: <20220513061347.46480-7-krzysztof.kozlowski@linaro.org> (raw)
In-Reply-To: <20220513061347.46480-1-krzysztof.kozlowski@linaro.org>

Devices might need to control several clocks when scaling the frequency
and voltage, with each clock having different frequency.  Parse the
'opp-hz' Devicetree property as an array and store all frequencies for
the custom set_opp in a new field 'rates'.

Since the PM OPP framework operates on only one clock (multiple clocks
are for custom set_opp helpers), these frequencies are actually not used
internally and still the core relies on the original field 'rate'.

All other PM OPP functions, like finding floor/ceil PM OPPs, operate
still on first rate given in the 'opp-hz' frequency.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

---

Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 drivers/opp/core.c     | 20 +++++++++++++++---
 drivers/opp/of.c       | 47 ++++++++++++++++++++++++++++++++++++++++++
 drivers/opp/opp.h      |  2 ++
 include/linux/pm_opp.h |  3 +++
 4 files changed, 69 insertions(+), 3 deletions(-)

diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index aac3c6d89ae0..563e962c3411 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -1033,7 +1033,9 @@ static int _set_opp_custom(const struct opp_table *opp_table,
 	data->clks = opp_table->clks;
 	data->dev = dev;
 	data->old_opp.rate = old_opp->rate;
+	data->old_opp.rates = old_opp->rates;
 	data->new_opp.rate = freq;
+	data->new_opp.rates = opp->rates;
 
 	return opp_table->set_opp(data);
 }
@@ -1307,6 +1309,11 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 				__func__, freq, ret);
 			goto put_opp_table;
 		}
+		/*
+		 * opp->rates are used for scaling clocks, so be sure accurate
+		 * 'freq' is used, instead what was defined via e.g. Devicetree.
+		 */
+		opp->rates[0] = freq;
 	}
 
 	ret = _set_opp(dev, opp_table, opp, freq);
@@ -1761,23 +1768,29 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
 struct dev_pm_opp *_opp_allocate(struct opp_table *table)
 {
 	struct dev_pm_opp *opp;
-	int supply_count, supply_size, icc_size;
+	int rate_count, rate_size, supply_count, supply_size, icc_size;
 
 	/* Allocate space for at least one supply */
 	supply_count = table->regulator_count > 0 ? table->regulator_count : 1;
 	supply_size = sizeof(*opp->supplies) * supply_count;
+	/* Allocate space for at least one rate */
+	rate_count = table->clk_count > 0 ? table->clk_count : 1;
+	rate_size = sizeof(*opp->rates) * rate_count;
 	icc_size = sizeof(*opp->bandwidth) * table->path_count;
 
 	/* allocate new OPP node and supplies structures */
-	opp = kzalloc(sizeof(*opp) + supply_size + icc_size, GFP_KERNEL);
+	opp = kzalloc(sizeof(*opp) + rate_size + supply_size + icc_size,
+		      GFP_KERNEL);
 
 	if (!opp)
 		return NULL;
 
 	/* Put the supplies at the end of the OPP structure as an empty array */
 	opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
+	opp->rates = (unsigned long *)(opp->supplies + supply_count);
 	if (icc_size)
-		opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->supplies + supply_count);
+		opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->rates + rate_count);
+
 	INIT_LIST_HEAD(&opp->node);
 
 	return opp;
@@ -1957,6 +1970,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
 
 	/* populate the opp table */
 	new_opp->rate = freq;
+	new_opp->rates[0] = freq;
 	tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
 	new_opp->supplies[0].u_volt = u_volt;
 	new_opp->supplies[0].u_volt_min = u_volt - tol;
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 30394929d700..b226d2c7a84b 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -767,6 +767,46 @@ void dev_pm_opp_of_remove_table(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
 
+static int _read_clocks(struct dev_pm_opp *opp, struct opp_table *opp_table,
+			struct device_node *np)
+{
+	int i, count, ret;
+	u64 *freq;
+
+	count = of_property_count_u64_elems(np, "opp-hz");
+	if (count < 0) {
+		pr_err("%s: Invalid %s property (%d)\n",
+			__func__, of_node_full_name(np), count);
+		return count;
+	}
+
+	if (count != opp_table->clk_count) {
+		pr_err("%s: number of rates %d does not match number of clocks %d in %pOF\n",
+		       __func__, count, opp_table->clk_count, np);
+		return -EINVAL;
+	}
+
+	freq = kmalloc_array(count, sizeof(*freq), GFP_KERNEL);
+	if (!freq)
+		return -ENOMEM;
+
+	ret = of_property_read_u64_array(np, "opp-hz", freq, count);
+	if (ret) {
+		pr_err("%s: error parsing %s: %d\n", __func__,
+		       of_node_full_name(np), ret);
+		ret = -EINVAL;
+		goto free_freq;
+	}
+
+	for (i = 0; i < count; i++)
+		opp->rates[i] = freq[i];
+
+free_freq:
+	kfree(freq);
+
+	return ret;
+}
+
 static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
 		    struct device_node *np, bool peak)
 {
@@ -827,6 +867,13 @@ static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table,
 	}
 	*rate_not_available = !!ret;
 
+	if (!ret) {
+		ret = _read_clocks(new_opp, table, np);
+		/* The properties were found but we failed to parse them */
+		if (ret && ret != -ENODEV)
+			return ret;
+	}
+
 	/*
 	 * Bandwidth consists of peak and average (optional) values:
 	 * opp-peak-kBps = <path1_value path2_value>;
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index 59aac08baf82..217d4376af9b 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -61,6 +61,7 @@ extern struct list_head opp_tables, lazy_opp_tables;
  * @rate:	Frequency in hertz
  * @level:	Performance level
  * @supplies:	Power supplies voltage/current values
+ * @rates:	Frequency rates for the clocks (equal to @rate for one clock)
  * @bandwidth:	Interconnect bandwidth values
  * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
  *		frequency from any other OPP's frequency.
@@ -85,6 +86,7 @@ struct dev_pm_opp {
 	unsigned int level;
 
 	struct dev_pm_opp_supply *supplies;
+	unsigned long *rates;
 	struct dev_pm_opp_icc_bw *bandwidth;
 
 	unsigned long clock_latency_ns;
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 5f17f10fcc3f..5fd3895af605 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -60,12 +60,15 @@ struct dev_pm_opp_icc_bw {
 /**
  * struct dev_pm_opp_info - OPP freq/voltage/current values
  * @rate:	Target clk rate in hz
+ * @rates:	Array of clock frequencies for all clocks (equal to @rate for
+ *		one clock)
  * @supplies:	Array of voltage/current values for all power supplies
  *
  * This structure stores the freq/voltage/current values for a single OPP.
  */
 struct dev_pm_opp_info {
 	unsigned long rate;
+	unsigned long *rates;
 	struct dev_pm_opp_supply *supplies;
 };
 
-- 
2.32.0


  parent reply	other threads:[~2022-05-13  6:15 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-13  6:13 [PATCH v3 0/7] ufs: set power domain performance state when scaling gears Krzysztof Kozlowski
2022-05-13  6:13 ` [PATCH v3 1/7] dt-bindings: clock: qcom,gcc-sdm845: add parent power domain Krzysztof Kozlowski
2022-05-13 15:51   ` Manivannan Sadhasivam
2022-06-28 20:19   ` (subset) " Bjorn Andersson
2022-05-13  6:13 ` [PATCH v3 2/7] dt-bindings: opp: accept array of frequencies Krzysztof Kozlowski
2022-05-13 17:22   ` Manivannan Sadhasivam
2022-06-30  9:55   ` Viresh Kumar
2022-05-13  6:13 ` [PATCH v3 3/7] dt-bindings: ufs: common: add OPP table Krzysztof Kozlowski
2022-05-13 17:40   ` Manivannan Sadhasivam
2022-05-13 18:32     ` Manivannan Sadhasivam
2022-05-13  6:13 ` [PATCH v3 4/7] arm64: dts: qcom: sdm845: control RPMHPD performance states with UFS Krzysztof Kozlowski
2022-05-25  7:16   ` Viresh Kumar
2022-05-30  7:42     ` Krzysztof Kozlowski
2022-05-13  6:13 ` [PATCH v3 5/7] PM: opp: allow control of multiple clocks Krzysztof Kozlowski
2022-05-13  6:13 ` Krzysztof Kozlowski [this message]
2022-05-13  6:13 ` [PATCH v3 7/7] ufs: use PM OPP when scaling gears Krzysztof Kozlowski
2022-05-13 18:25   ` Manivannan Sadhasivam
2022-05-16  6:10     ` Krzysztof Kozlowski

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=20220513061347.46480-7-krzysztof.kozlowski@linaro.org \
    --to=krzysztof.kozlowski@linaro.org \
    --cc=agross@kernel.org \
    --cc=alim.akhtar@samsung.com \
    --cc=avri.altman@wdc.com \
    --cc=bjorn.andersson@linaro.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jejb@linux.ibm.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=manivannan.sadhasivam@linaro.org \
    --cc=martin.petersen@oracle.com \
    --cc=mturquette@baylibre.com \
    --cc=nm@ti.com \
    --cc=rafael@kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=sboyd@kernel.org \
    --cc=tdas@codeaurora.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).