]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
OPP: decouple dt properties in opp_parse_supplies()
authorJames Calligeros <jcalligeros99@gmail.com>
Thu, 3 Nov 2022 09:10:44 +0000 (14:40 +0530)
committerViresh Kumar <viresh.kumar@linaro.org>
Fri, 4 Nov 2022 05:29:07 +0000 (10:59 +0530)
The opp-microwatt property was added with the intention of providing
platforms a way to specify a precise value for the power consumption
of a device at a given OPP to enable better energy-aware scheduling
decisions by informing the kernel of the total static and dynamic
power of a device at a given OPP, removing the reliance on the EM
subsystem's often flawed estimations. This property is parsed by
opp_parse_supplies(), which creates a hard dependency on the
opp-microvolt property.

Some platforms, such as Apple Silicon, do not describe their device's
voltage regulators in the DT as they cannot be controlled by the kernel
and/or rely on opaque firmware algorithms to control their voltage and
current characteristics at runtime. We can, however, experimentally
determine the power consumption of a given device at a given OPP, taking
advantage of opp-microwatt to provide EAS on such devices as was
initially intended.

Allow platforms to specify and consume any subset of opp-microvolt,
opp-microamp, or opp-microwatt without a hard dependency on
opp-microvolt to enable this functionality on such platforms.

Tested-by: James Calligeros <jcalligeros99@gmail.com>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Co-developed-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
drivers/opp/of.c

index 08d97b97c326569d91911358a7512350546110af..e55c6095adf00f36b1fab1cb52d185496e5ef952 100644 (file)
@@ -654,9 +654,12 @@ static u32 *opp_parse_microvolt(struct dev_pm_opp *opp, struct device *dev,
                /*
                 * Missing property isn't a problem, but an invalid
                 * entry is. This property isn't optional if regulator
-                * information is provided.
+                * information is provided. Check only for the first OPP, as
+                * regulator_count may get initialized after that to a valid
+                * value.
                 */
-               if (opp_table->regulator_count > 0) {
+               if (list_empty(&opp_table->opp_list) &&
+                   opp_table->regulator_count > 0) {
                        dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
                                __func__);
                        return ERR_PTR(-EINVAL);
@@ -674,7 +677,7 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
        bool triplet;
 
        microvolt = opp_parse_microvolt(opp, dev, opp_table, &triplet);
-       if (IS_ERR_OR_NULL(microvolt))
+       if (IS_ERR(microvolt))
                return PTR_ERR(microvolt);
 
        microamp = _parse_named_prop(opp, dev, opp_table, "microamp", NULL);
@@ -689,15 +692,26 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
                goto free_microamp;
        }
 
-       for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
-               opp->supplies[i].u_volt = microvolt[j++];
+       /*
+        * Initialize regulator_count if it is uninitialized and no properties
+        * are found.
+        */
+       if (unlikely(opp_table->regulator_count == -1)) {
+               opp_table->regulator_count = 0;
+               return 0;
+       }
 
-               if (triplet) {
-                       opp->supplies[i].u_volt_min = microvolt[j++];
-                       opp->supplies[i].u_volt_max = microvolt[j++];
-               } else {
-                       opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
-                       opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
+       for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
+               if (microvolt) {
+                       opp->supplies[i].u_volt = microvolt[j++];
+
+                       if (triplet) {
+                               opp->supplies[i].u_volt_min = microvolt[j++];
+                               opp->supplies[i].u_volt_max = microvolt[j++];
+                       } else {
+                               opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
+                               opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
+                       }
                }
 
                if (microamp)