[PATCH 13/16] OPP: Extend dev_pm_opp_data with OPP provider support

Ulf Hansson ulf.hansson at linaro.org
Wed Jun 7 05:46:25 PDT 2023


To allow a dynamically added OPP to be coupled with a specific OPP provider
type, let's add a new enum variable in the struct dev_pm_opp_data.
Moreover, let's add support for a DEV_PM_OPP_TYPE_GENPD type, corresponding
to genpd's performance states support.

More precisely, this allows a genpd provider to dynamically add OPPs when a
device gets attached to it, that later can be used by a consumer driver
when it needs to change the performance level for its corresponding device.

Signed-off-by: Ulf Hansson <ulf.hansson at linaro.org>
---
 drivers/opp/core.c     | 19 +++++++++++++++++++
 drivers/opp/opp.h      |  1 +
 include/linux/pm_opp.h |  7 +++++++
 3 files changed, 27 insertions(+)

diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 79b4b44ced3e..81a3418e2eaf 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -1112,6 +1112,15 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
 			return ret;
 		}
 
+		if (opp->provider == DEV_PM_OPP_TYPE_GENPD) {
+			ret = dev_pm_genpd_set_performance_state(dev, opp->level);
+			if (ret) {
+				dev_err(dev, "Failed to set performance level: %d\n",
+					ret);
+				return ret;
+			}
+		}
+
 		ret = _set_opp_bw(opp_table, opp, dev);
 		if (ret) {
 			dev_err(dev, "Failed to set bw: %d\n", ret);
@@ -1155,6 +1164,15 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
 			return ret;
 		}
 
+		if (opp->provider == DEV_PM_OPP_TYPE_GENPD) {
+			ret = dev_pm_genpd_set_performance_state(dev, opp->level);
+			if (ret) {
+				dev_err(dev, "Failed to set performance level: %d\n",
+					ret);
+				return ret;
+			}
+		}
+
 		ret = _set_required_opps(dev, opp_table, opp, false);
 		if (ret) {
 			dev_err(dev, "Failed to set required opps: %d\n", ret);
@@ -1955,6 +1973,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
 	/* populate the opp table */
 	new_opp->rates[0] = opp->freq;
 	new_opp->level = opp->level;
+	new_opp->provider = opp->provider;
 	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/opp.h b/drivers/opp/opp.h
index b15770b2305e..ee2b3bd89213 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -104,6 +104,7 @@ struct dev_pm_opp {
 	unsigned int pstate;
 	unsigned long *rates;
 	unsigned int level;
+	enum dev_pm_opp_provider_type provider;
 
 	struct dev_pm_opp_supply *supplies;
 	struct dev_pm_opp_icc_bw *bandwidth;
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 2c6f67736579..4c40199c7728 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -26,6 +26,11 @@ enum dev_pm_opp_event {
 	OPP_EVENT_ADJUST_VOLTAGE,
 };
 
+enum dev_pm_opp_provider_type {
+	DEV_PM_OPP_TYPE_NONE = 0,
+	DEV_PM_OPP_TYPE_GENPD,
+};
+
 /**
  * struct dev_pm_opp_supply - Power supply voltage/current values
  * @u_volt:	Target voltage in microvolts corresponding to this OPP
@@ -97,11 +102,13 @@ struct dev_pm_opp_config {
  * @level: The performance level for the OPP.
  * @freq: The clock rate in Hz for the OPP.
  * @u_volt: The voltage in uV for the OPP.
+ * @provider: The type of provider for the OPP.
  */
 struct dev_pm_opp_data {
 	unsigned int level;
 	unsigned long freq;
 	unsigned long u_volt;
+	enum dev_pm_opp_provider_type provider;
 };
 
 #if defined(CONFIG_PM_OPP)
-- 
2.34.1




More information about the linux-arm-kernel mailing list