Commit e0e44513 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branches 'powercap', 'pm-x86', 'pm-opp' and 'pm-misc'

Merge power capping code updates, x86-specific power management pdate,
operating performance points library updates and miscellaneous power
management updates for 6.2-rc1:

 - Fix compiler warnings with make W=1 in the idle_inject power capping
   driver (Srinivas Pandruvada).

 - Use kstrtobool() instead of strtobool() in the power capping sysfs
   interface (Christophe JAILLET).

 - Add SCMI Powercap based power capping driver (Cristian Marussi).

 - Add Emerald Rapids support to the intel-uncore-freq driver (Artem
   Bityutskiy).

 - Repair slips in kernel-doc comments in the generic notifier code
   (Lukas Bulwahn).

 - Fix several DT issues in the OPP library reorganize code 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 property in DT example (Serge Semin).

* powercap:
  powercap: idle_inject: Fix warnings with make W=1
  powercap: Use kstrtobool() instead of strtobool()
  powercap: arm_scmi: Add SCMI Powercap based driver

* pm-x86:
  platform/x86: intel-uncore-freq: add Emerald Rapids support

* pm-opp:
  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

* pm-misc:
  notifier: repair slips in kernel-doc comments
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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;
        };
    };
+1 −0
Original line number Diff line number Diff line
@@ -20004,6 +20004,7 @@ F: drivers/clk/clk-sc[mp]i.c
F:	drivers/cpufreq/sc[mp]i-cpufreq.c
F:	drivers/firmware/arm_scmi/
F:	drivers/firmware/arm_scpi.c
F:	drivers/powercap/arm_scmi_powercap.c
F:	drivers/regulator/scmi-regulator.c
F:	drivers/reset/reset-scmi.c
F:	include/linux/sc[mp]i_protocol.h
+99 −129
Original line number Diff line number Diff line
@@ -578,169 +578,140 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
	return false;
}

static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
			      struct opp_table *opp_table)
static u32 *_parse_named_prop(struct dev_pm_opp *opp, struct device *dev,
			      struct opp_table *opp_table,
			      const char *prop_type, bool *triplet)
{
	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];
	int count, ret;
	u32 *out;

	/* Search for "opp-microvolt-<name>" */
	/* Search for "opp-<prop_type>-<name>" */
	if (opp_table->prop_name) {
		snprintf(name, sizeof(name), "opp-microvolt-%s",
		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-microvolt" */
		sprintf(name, "opp-microvolt");
		/* Search for "opp-<prop_type>" */
		snprintf(name, sizeof(name), "opp-%s", prop_type);
		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 (!prop)
			return NULL;
	}

	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;
	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);
	}

	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;
	}
	/*
	 * 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;

	/* 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;
	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);
	}

	microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
	if (!microvolt)
		return -ENOMEM;
	out = kmalloc_array(count, sizeof(*out), GFP_KERNEL);
	if (!out)
		return ERR_PTR(-EINVAL);

	ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
	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);
		ret = -EINVAL;
		goto free_microvolt;
		kfree(out);
		return ERR_PTR(-EINVAL);
	}

	/* 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);
	}
	if (triplet)
		*triplet = count != opp_table->regulator_count;

	if (!prop) {
		/* Search for "opp-microamp" */
		sprintf(name, "opp-microamp");
		prop = of_find_property(opp->np, name, NULL);
	return out;
}

	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;
		}
static u32 *opp_parse_microvolt(struct dev_pm_opp *opp, struct device *dev,
				struct opp_table *opp_table, bool *triplet)
{
	u32 *microvolt;

		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;
		}
	microvolt = _parse_named_prop(opp, dev, opp_table, "microvolt", triplet);
	if (IS_ERR(microvolt))
		return microvolt;

		microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
		if (!microamp) {
			ret = -EINVAL;
			goto free_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);
		}

		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;
	}

	return microvolt;
}

	/* Search for "opp-microwatt" */
	sprintf(name, "opp-microwatt");
	prop = of_find_property(opp->np, name, NULL);
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
			      struct opp_table *opp_table)
{
	u32 *microvolt, *microamp, *microwatt;
	int ret = 0, i, j;
	bool triplet;

	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;
		}
	microvolt = opp_parse_microvolt(opp, dev, opp_table, &triplet);
	if (IS_ERR(microvolt))
		return PTR_ERR(microvolt);

		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;
	microamp = _parse_named_prop(opp, dev, opp_table, "microamp", NULL);
	if (IS_ERR(microamp)) {
		ret = PTR_ERR(microamp);
		goto free_microvolt;
	}

		microwatt = kmalloc_array(pcount, sizeof(*microwatt),
					  GFP_KERNEL);
		if (!microwatt) {
			ret = -EINVAL;
	microwatt = _parse_named_prop(opp, dev, opp_table, "microwatt", NULL);
	if (IS_ERR(microwatt)) {
		ret = PTR_ERR(microwatt);
		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;
		}
	/*
	 * 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;
	}

	for (i = 0, j = 0; i < supplies; i++) {
	for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
		if (microvolt) {
			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 {
			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);
+1 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ static const struct x86_cpu_id intel_uncore_cpu_ids[] = {
	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X,	NULL),
	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D,	NULL),
	X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL),
	X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, NULL),
	{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_uncore_cpu_ids);
Loading