Merge tag 'opp-updates-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm

Pull OPP updates for 6.2 from Viresh Kumar:

"- Several DT fixes and code reorganization around opp-microvolt-<named>
   DT property (Viresh Kumar).

 - Allow any of opp-microvolt, opp-microamp, or opp-microwatt properties
   to be present without the others present (James Calligeros).

 - Fix clock-latency-ns prop in DT example (Serge Semin)."

* tag 'opp-updates-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  dt-bindings: opp-v2: Fix clock-latency-ns prop in example
  OPP: decouple dt properties in opp_parse_supplies()
  OPP: Simplify opp_parse_supplies() by restructuring it
  OPP: Parse named opp-microwatt property too
  dt-bindings: opp: Fix named microwatt property
  dt-bindings: opp: Fix usage of current in microwatt property
This commit is contained in:
Rafael J. Wysocki
2022-12-02 20:38:07 +01:00
3 changed files with 125 additions and 155 deletions
@@ -108,7 +108,7 @@ patternProperties:
The power for the OPP in micro-Watts.
Entries for multiple regulators shall be provided in the same field
separated by angular brackets <>. If current values aren't required
separated by angular brackets <>. If power values aren't required
for a regulator, then it shall be filled with 0. If power values
aren't required for any of the regulators, then this field is not
required. The OPP binding doesn't provide any provisions to relate the
@@ -230,9 +230,9 @@ patternProperties:
minItems: 1
maxItems: 8 # Should be enough regulators
'^opp-microwatt':
'^opp-microwatt-':
description:
Named opp-microwatt property. Similar to opp-microamp property,
Named opp-microwatt property. Similar to opp-microamp-<name> property,
but for microwatt instead.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
@@ -155,7 +155,7 @@ examples:
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <1025000>;
opp-microamp = <90000>;
lock-latency-ns = <290000>;
clock-latency-ns = <290000>;
turbo-mode;
};
};
+121 -151
View File
@@ -578,169 +578,140 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
return false;
}
static u32 *_parse_named_prop(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table,
const char *prop_type, bool *triplet)
{
struct property *prop = NULL;
char name[NAME_MAX];
int count, ret;
u32 *out;
/* Search for "opp-<prop_type>-<name>" */
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-%s-%s", prop_type,
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
if (!prop) {
/* Search for "opp-<prop_type>" */
snprintf(name, sizeof(name), "opp-%s", prop_type);
prop = of_find_property(opp->np, name, NULL);
if (!prop)
return NULL;
}
count = of_property_count_u32_elems(opp->np, name);
if (count < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__, name,
count);
return ERR_PTR(count);
}
/*
* Initialize regulator_count, if regulator information isn't provided
* by the platform. Now that one of the properties is available, fix the
* regulator_count to 1.
*/
if (unlikely(opp_table->regulator_count == -1))
opp_table->regulator_count = 1;
if (count != opp_table->regulator_count &&
(!triplet || count != opp_table->regulator_count * 3)) {
dev_err(dev, "%s: Invalid number of elements in %s property (%u) with supplies (%d)\n",
__func__, prop_type, count, opp_table->regulator_count);
return ERR_PTR(-EINVAL);
}
out = kmalloc_array(count, sizeof(*out), GFP_KERNEL);
if (!out)
return ERR_PTR(-EINVAL);
ret = of_property_read_u32_array(opp->np, name, out, count);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
kfree(out);
return ERR_PTR(-EINVAL);
}
if (triplet)
*triplet = count != opp_table->regulator_count;
return out;
}
static u32 *opp_parse_microvolt(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table, bool *triplet)
{
u32 *microvolt;
microvolt = _parse_named_prop(opp, dev, opp_table, "microvolt", triplet);
if (IS_ERR(microvolt))
return microvolt;
if (!microvolt) {
/*
* Missing property isn't a problem, but an invalid
* entry is. This property isn't optional if regulator
* information is provided. Check only for the first OPP, as
* regulator_count may get initialized after that to a valid
* value.
*/
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);
}
}
return microvolt;
}
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table)
{
u32 *microvolt, *microamp = NULL, *microwatt = NULL;
int supplies = opp_table->regulator_count;
int vcount, icount, pcount, ret, i, j;
struct property *prop = NULL;
char name[NAME_MAX];
u32 *microvolt, *microamp, *microwatt;
int ret = 0, i, j;
bool triplet;
/* Search for "opp-microvolt-<name>" */
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microvolt-%s",
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
microvolt = opp_parse_microvolt(opp, dev, opp_table, &triplet);
if (IS_ERR(microvolt))
return PTR_ERR(microvolt);
if (!prop) {
/* Search for "opp-microvolt" */
sprintf(name, "opp-microvolt");
prop = of_find_property(opp->np, name, NULL);
/* Missing property isn't a problem, but an invalid entry is */
if (!prop) {
if (unlikely(supplies == -1)) {
/* Initialize regulator_count */
opp_table->regulator_count = 0;
return 0;
}
if (!supplies)
return 0;
dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
__func__);
return -EINVAL;
}
}
if (unlikely(supplies == -1)) {
/* Initialize regulator_count */
supplies = opp_table->regulator_count = 1;
} else if (unlikely(!supplies)) {
dev_err(dev, "%s: opp-microvolt wasn't expected\n", __func__);
return -EINVAL;
}
vcount = of_property_count_u32_elems(opp->np, name);
if (vcount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n",
__func__, name, vcount);
return vcount;
}
/* There can be one or three elements per supply */
if (vcount != supplies && vcount != supplies * 3) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, vcount, supplies);
return -EINVAL;
}
microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
if (!microvolt)
return -ENOMEM;
ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
ret = -EINVAL;
microamp = _parse_named_prop(opp, dev, opp_table, "microamp", NULL);
if (IS_ERR(microamp)) {
ret = PTR_ERR(microamp);
goto free_microvolt;
}
/* Search for "opp-microamp-<name>" */
prop = NULL;
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microamp-%s",
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
microwatt = _parse_named_prop(opp, dev, opp_table, "microwatt", NULL);
if (IS_ERR(microwatt)) {
ret = PTR_ERR(microwatt);
goto free_microamp;
}
if (!prop) {
/* Search for "opp-microamp" */
sprintf(name, "opp-microamp");
prop = of_find_property(opp->np, name, NULL);
/*
* 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 (prop) {
icount = of_property_count_u32_elems(opp->np, name);
if (icount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
name, icount);
ret = icount;
goto free_microvolt;
}
for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
if (microvolt) {
opp->supplies[i].u_volt = microvolt[j++];
if (icount != supplies) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, icount, supplies);
ret = -EINVAL;
goto free_microvolt;
}
microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
if (!microamp) {
ret = -EINVAL;
goto free_microvolt;
}
ret = of_property_read_u32_array(opp->np, name, microamp,
icount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__,
name, ret);
ret = -EINVAL;
goto free_microamp;
}
}
/* Search for "opp-microwatt" */
sprintf(name, "opp-microwatt");
prop = of_find_property(opp->np, name, NULL);
if (prop) {
pcount = of_property_count_u32_elems(opp->np, name);
if (pcount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
name, pcount);
ret = pcount;
goto free_microamp;
}
if (pcount != supplies) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, pcount, supplies);
ret = -EINVAL;
goto free_microamp;
}
microwatt = kmalloc_array(pcount, sizeof(*microwatt),
GFP_KERNEL);
if (!microwatt) {
ret = -EINVAL;
goto free_microamp;
}
ret = of_property_read_u32_array(opp->np, name, microwatt,
pcount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__,
name, ret);
ret = -EINVAL;
goto free_microwatt;
}
}
for (i = 0, j = 0; i < supplies; i++) {
opp->supplies[i].u_volt = microvolt[j++];
if (vcount == supplies) {
opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
} else {
opp->supplies[i].u_volt_min = microvolt[j++];
opp->supplies[i].u_volt_max = 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)
@@ -750,7 +721,6 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
opp->supplies[i].u_watt = microwatt[i];
}
free_microwatt:
kfree(microwatt);
free_microamp:
kfree(microamp);