Commit 0a30c0e9 authored by Sudeep Holla's avatar Sudeep Holla
Browse files

Merge branch 'opp/pm-domain-scmi' of...

Merge branch 'opp/pm-domain-scmi' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm into for-next/scmi/updates

This is the merge of immutable point in PM OPP tree shared with SCMI so
that the SCMI changes based on these OPP changes can be merged via the
SCMI tree.

* 'opp/pm-domain-scmi' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  OPP: Extend support for the opp-level beyond required-opps
  OPP: Switch to use dev_pm_domain_set_performance_state()
  OPP: Extend dev_pm_opp_data with a level
  OPP: Add dev_pm_opp_add_dynamic() to allow more flexibility
  PM: domains: Implement the ->set_performance_state() callback for genpd
  PM: domains: Introduce dev_pm_domain_set_performance_state()
parents 8b6022be 0025ff64
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -228,3 +228,24 @@ void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd)
	device_pm_check_callbacks(dev);
}
EXPORT_SYMBOL_GPL(dev_pm_domain_set);

/**
 * dev_pm_domain_set_performance_state - Request a new performance state.
 * @dev: The device to make the request for.
 * @state: Target performance state for the device.
 *
 * This function should be called when a new performance state needs to be
 * requested for a device that is attached to a PM domain. Note that, the
 * support for performance scaling for PM domains is optional.
 *
 * Returns 0 on success and when performance scaling isn't supported, negative
 * error code on failure.
 */
int dev_pm_domain_set_performance_state(struct device *dev, unsigned int state)
{
	if (dev->pm_domain && dev->pm_domain->set_performance_state)
		return dev->pm_domain->set_performance_state(dev, state);

	return 0;
}
EXPORT_SYMBOL_GPL(dev_pm_domain_set_performance_state);
+21 −12
Original line number Diff line number Diff line
@@ -420,6 +420,25 @@ static void genpd_restore_performance_state(struct device *dev,
		genpd_set_performance_state(dev, state);
}

static int genpd_dev_pm_set_performance_state(struct device *dev,
					      unsigned int state)
{
	struct generic_pm_domain *genpd = dev_to_genpd(dev);
	int ret = 0;

	genpd_lock(genpd);
	if (pm_runtime_suspended(dev)) {
		dev_gpd_data(dev)->rpm_pstate = state;
	} else {
		ret = genpd_set_performance_state(dev, state);
		if (!ret)
			dev_gpd_data(dev)->rpm_pstate = 0;
	}
	genpd_unlock(genpd);

	return ret;
}

/**
 * dev_pm_genpd_set_performance_state- Set performance state of device's power
 * domain.
@@ -438,7 +457,6 @@ static void genpd_restore_performance_state(struct device *dev,
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
{
	struct generic_pm_domain *genpd;
	int ret = 0;

	genpd = dev_to_genpd_safe(dev);
	if (!genpd)
@@ -448,17 +466,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
		     !dev->power.subsys_data->domain_data))
		return -EINVAL;

	genpd_lock(genpd);
	if (pm_runtime_suspended(dev)) {
		dev_gpd_data(dev)->rpm_pstate = state;
	} else {
		ret = genpd_set_performance_state(dev, state);
		if (!ret)
			dev_gpd_data(dev)->rpm_pstate = 0;
	}
	genpd_unlock(genpd);

	return ret;
	return genpd_dev_pm_set_performance_state(dev, state);
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_set_performance_state);

@@ -2080,6 +2088,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
	genpd->domain.ops.restore_noirq = genpd_restore_noirq;
	genpd->domain.ops.complete = genpd_complete;
	genpd->domain.start = genpd_dev_pm_start;
	genpd->domain.set_performance_state = genpd_dev_pm_set_performance_state;

	if (genpd->flags & GENPD_FLAG_PM_CLK) {
		genpd->dev_ops.stop = pm_clk_suspend;
+47 −13
Original line number Diff line number Diff line
@@ -1030,7 +1030,7 @@ static int _set_performance_state(struct device *dev, struct device *pd_dev,
	if (!pd_dev)
		return 0;

	ret = dev_pm_genpd_set_performance_state(pd_dev, pstate);
	ret = dev_pm_domain_set_performance_state(pd_dev, pstate);
	if (ret) {
		dev_err(dev, "Failed to set performance state of %s: %d (%d)\n",
			dev_name(pd_dev), pstate, ret);
@@ -1107,6 +1107,28 @@ void _update_set_required_opps(struct opp_table *opp_table)
		opp_table->set_required_opps = _opp_set_required_opps_generic;
}

static int _set_opp_level(struct device *dev, struct opp_table *opp_table,
			  struct dev_pm_opp *opp)
{
	unsigned int level = 0;
	int ret = 0;

	if (opp) {
		if (!opp->level)
			return 0;

		level = opp->level;
	}

	/* Request a new performance state through the device's PM domain. */
	ret = dev_pm_domain_set_performance_state(dev, level);
	if (ret)
		dev_err(dev, "Failed to set performance state %u (%d)\n", level,
			ret);

	return ret;
}

static void _find_current_opp(struct device *dev, struct opp_table *opp_table)
{
	struct dev_pm_opp *opp = ERR_PTR(-ENODEV);
@@ -1154,8 +1176,13 @@ static int _disable_opp_table(struct device *dev, struct opp_table *opp_table)
	if (opp_table->regulators)
		regulator_disable(opp_table->regulators[0]);

	ret = _set_opp_level(dev, opp_table, NULL);
	if (ret)
		goto out;

	ret = _set_required_opps(dev, opp_table, NULL, false);

out:
	opp_table->enabled = false;
	return ret;
}
@@ -1198,6 +1225,10 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
			return ret;
		}

		ret = _set_opp_level(dev, opp_table, opp);
		if (ret)
			return ret;

		ret = _set_opp_bw(opp_table, opp, dev);
		if (ret) {
			dev_err(dev, "Failed to set bw: %d\n", ret);
@@ -1241,6 +1272,10 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
			return ret;
		}

		ret = _set_opp_level(dev, opp_table, opp);
		if (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);
@@ -2002,8 +2037,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
 * _opp_add_v1() - Allocate a OPP based on v1 bindings.
 * @opp_table:	OPP table
 * @dev:	device for which we do this operation
 * @freq:	Frequency in Hz for this OPP
 * @u_volt:	Voltage in uVolts for this OPP
 * @data:	The OPP data for the OPP to add
 * @dynamic:	Dynamically added OPPs.
 *
 * This function adds an opp definition to the opp table and returns status.
@@ -2021,10 +2055,10 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
 * -ENOMEM	Memory allocation failure
 */
int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
		unsigned long freq, long u_volt, bool dynamic)
		struct dev_pm_opp_data *data, bool dynamic)
{
	struct dev_pm_opp *new_opp;
	unsigned long tol;
	unsigned long tol, u_volt = data->u_volt;
	int ret;

	if (!assert_single_clk(opp_table))
@@ -2035,7 +2069,8 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
		return -ENOMEM;

	/* populate the opp table */
	new_opp->rates[0] = freq;
	new_opp->rates[0] = data->freq;
	new_opp->level = data->level;
	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;
@@ -2825,10 +2860,9 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
}

/**
 * dev_pm_opp_add()  - Add an OPP table from a table definitions
 * @dev:	device for which we do this operation
 * @freq:	Frequency in Hz for this OPP
 * @u_volt:	Voltage in uVolts for this OPP
 * dev_pm_opp_add_dynamic()  - Add an OPP table from a table definitions
 * @dev:	The device for which we do this operation
 * @data:	The OPP data for the OPP to add
 *
 * This function adds an opp definition to the opp table and returns status.
 * The opp is made available by default and it can be controlled using
@@ -2841,7 +2875,7 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
 *		Duplicate OPPs (both freq and volt are same) and !opp->available
 * -ENOMEM	Memory allocation failure
 */
int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
int dev_pm_opp_add_dynamic(struct device *dev, struct dev_pm_opp_data *data)
{
	struct opp_table *opp_table;
	int ret;
@@ -2853,13 +2887,13 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
	/* Fix regulator count for dynamic OPPs */
	opp_table->regulator_count = 1;

	ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
	ret = _opp_add_v1(opp_table, dev, data, true);
	if (ret)
		dev_pm_opp_put_opp_table(opp_table);

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
EXPORT_SYMBOL_GPL(dev_pm_opp_add_dynamic);

/**
 * _opp_set_availability() - helper to set the availability of an opp
+6 −4
Original line number Diff line number Diff line
@@ -1077,13 +1077,15 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)

	val = prop->value;
	while (nr) {
		unsigned long freq = be32_to_cpup(val++) * 1000;
		unsigned long volt = be32_to_cpup(val++);
		struct dev_pm_opp_data data = {
			.freq = be32_to_cpup(val++) * 1000,
			.u_volt = be32_to_cpup(val++),
		};

		ret = _opp_add_v1(opp_table, dev, freq, volt, false);
		ret = _opp_add_v1(opp_table, dev, &data, false);
		if (ret) {
			dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
				__func__, freq, ret);
				__func__, data.freq, ret);
			goto remove_static_opp;
		}
		nr -= 2;
+1 −1
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
void _opp_free(struct dev_pm_opp *opp);
int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, struct dev_pm_opp_data *data, bool dynamic);
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
void _put_opp_list_kref(struct opp_table *opp_table);
Loading