OPP updates for 6.2
- 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). -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEx73Crsp7f6M6scA70rkcPK6BEhwFAmOJkD4ACgkQ0rkcPK6B EhwH9w/+IzRvcBp69eGUgtAyDWJUqeUycdibzo3IjKLGxCaXhnb71fE0WpZFfTgH VzR60X3yWHAec1f3NUwVIu/EETqvjZjTeB+2MtM62P1JE73YIuPdZTsSreEkbpPP YBJ5d5i5iKz99xQ0SxTkAD72GTCbn8UwlrEv4lr6U9dFJ7LSKmdBONmtiTilb+rT SDRzzZyjy3TYbrXpduLLPrLVpD7/XL6bsWeYD2K1Souijw836L6jtWhLIk3nlI80 0TCCcVzChpBoQdF/Qtjg27iO9QrUTmZzxvEi7QOzvgQQnT3RIaMrPWnAX/4oMhzj xoLMIYca1804XZTPwcsJx1oXnOfFCJZrUaGlWsEfLJtKPa4w2QvSU3+lgE4ugwC6 XK2lIn9cLlVJwZwszqhxbFdokIWXnYijw50L/2cZrWFWs/Ru5s+3lc06n6bN4LL4 cLzP66TPS4vStvU0EZUv7TQNiFXTBNmLotxaVWQ+8G0hFjCoXbVB2TnPBebJAZRs GhKHaTLzSrzFYvYb8xnFQHoABFnZrjecdsOV60Pl16UhmjSLd3XjXEu9medoDGnf qQ++bM4ziIbV1Z/QC2qzJ2SqFOu6jBPu+ty73nIHlKBiBkq8MZlwELLxEbgU5os2 tpLbrVPU+/UwvO5OqAbJMUa047MMS4Ox5DqUCc6xU1MOiFBc3Jg= =Cu0W -----END PGP SIGNATURE----- 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:
Коммит
68bf66a108
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
272
drivers/opp/of.c
272
drivers/opp/of.c
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче