Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

Merge branch 'pm-opp'

* pm-opp:
  PM / OPP: Drop unlikely before IS_ERR(_OR_NULL)
  PM / OPP: Fix static checker warning (broken 64bit big endian systems)
  PM / OPP: Free resources and properly return error on failure
  cpufreq-dt: make scaling_boost_freqs sysfs attr available when boost is enabled
  cpufreq: dt: Add support for turbo/boost mode
  cpufreq: dt: Add support for operating-points-v2 bindings
  cpufreq: Allow drivers to enable boost support after registering driver
  cpufreq: Update boost flag while initializing freq table from OPPs
  PM / OPP: add dev_pm_opp_is_turbo() helper
  PM / OPP: Add helpers for initializing CPU OPPs
  PM / OPP: Add support for opp-suspend
  PM / OPP: Add OPP sharing information to OPP library
  PM / OPP: Add clock-latency-ns support
  PM / OPP: Add support to parse "operating-points-v2" bindings
  PM / OPP: Break _opp_add_dynamic() into smaller functions
  PM / OPP: Allocate dev_opp from _add_device_opp()
  PM / OPP: Create _remove_device_opp() for freeing dev_opp
  PM / OPP: Relocate few routines
  PM / OPP: Create a directory for opp bindings
  PM / OPP: Update bindings to make opp-hz a 64 bit value
parents 4ffe18c2 50a3cb04
Loading
Loading
Loading
Loading
+20 −20
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ This defines voltage-current-frequency combinations along with other related
properties.

Required properties:
- opp-hz: Frequency in Hz
- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer.

Optional properties:
- opp-microvolt: voltage in micro Volts.
@@ -158,20 +158,20 @@ Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together.
		opp-shared;

		opp00 {
			opp-hz = <1000000000>;
			opp-hz = /bits/ 64 <1000000000>;
			opp-microvolt = <970000 975000 985000>;
			opp-microamp = <70000>;
			clock-latency-ns = <300000>;
			opp-suspend;
		};
		opp01 {
			opp-hz = <1100000000>;
			opp-hz = /bits/ 64 <1100000000>;
			opp-microvolt = <980000 1000000 1010000>;
			opp-microamp = <80000>;
			clock-latency-ns = <310000>;
		};
		opp02 {
			opp-hz = <1200000000>;
			opp-hz = /bits/ 64 <1200000000>;
			opp-microvolt = <1025000>;
			clock-latency-ns = <290000>;
			turbo-mode;
@@ -237,20 +237,20 @@ independently.
		 */

		opp00 {
			opp-hz = <1000000000>;
			opp-hz = /bits/ 64 <1000000000>;
			opp-microvolt = <970000 975000 985000>;
			opp-microamp = <70000>;
			clock-latency-ns = <300000>;
			opp-suspend;
		};
		opp01 {
			opp-hz = <1100000000>;
			opp-hz = /bits/ 64 <1100000000>;
			opp-microvolt = <980000 1000000 1010000>;
			opp-microamp = <80000>;
			clock-latency-ns = <310000>;
		};
		opp02 {
			opp-hz = <1200000000>;
			opp-hz = /bits/ 64 <1200000000>;
			opp-microvolt = <1025000>;
			opp-microamp = <90000;
			lock-latency-ns = <290000>;
@@ -313,20 +313,20 @@ DVFS state together.
		opp-shared;

		opp00 {
			opp-hz = <1000000000>;
			opp-hz = /bits/ 64 <1000000000>;
			opp-microvolt = <970000 975000 985000>;
			opp-microamp = <70000>;
			clock-latency-ns = <300000>;
			opp-suspend;
		};
		opp01 {
			opp-hz = <1100000000>;
			opp-hz = /bits/ 64 <1100000000>;
			opp-microvolt = <980000 1000000 1010000>;
			opp-microamp = <80000>;
			clock-latency-ns = <310000>;
		};
		opp02 {
			opp-hz = <1200000000>;
			opp-hz = /bits/ 64 <1200000000>;
			opp-microvolt = <1025000>;
			opp-microamp = <90000>;
			clock-latency-ns = <290000>;
@@ -339,20 +339,20 @@ DVFS state together.
		opp-shared;

		opp10 {
			opp-hz = <1300000000>;
			opp-hz = /bits/ 64 <1300000000>;
			opp-microvolt = <1045000 1050000 1055000>;
			opp-microamp = <95000>;
			clock-latency-ns = <400000>;
			opp-suspend;
		};
		opp11 {
			opp-hz = <1400000000>;
			opp-hz = /bits/ 64 <1400000000>;
			opp-microvolt = <1075000>;
			opp-microamp = <100000>;
			clock-latency-ns = <400000>;
		};
		opp12 {
			opp-hz = <1500000000>;
			opp-hz = /bits/ 64 <1500000000>;
			opp-microvolt = <1010000 1100000 1110000>;
			opp-microamp = <95000>;
			clock-latency-ns = <400000>;
@@ -379,7 +379,7 @@ Example 4: Handling multiple regulators
		opp-shared;

		opp00 {
			opp-hz = <1000000000>;
			opp-hz = /bits/ 64 <1000000000>;
			opp-microvolt = <970000>, /* Supply 0 */
					<960000>, /* Supply 1 */
					<960000>; /* Supply 2 */
@@ -392,7 +392,7 @@ Example 4: Handling multiple regulators
		/* OR */

		opp00 {
			opp-hz = <1000000000>;
			opp-hz = /bits/ 64 <1000000000>;
			opp-microvolt = <970000 975000 985000>, /* Supply 0 */
					<960000 965000 975000>, /* Supply 1 */
					<960000 965000 975000>; /* Supply 2 */
@@ -405,7 +405,7 @@ Example 4: Handling multiple regulators
		/* OR */

		opp00 {
			opp-hz = <1000000000>;
			opp-hz = /bits/ 64 <1000000000>;
			opp-microvolt = <970000 975000 985000>, /* Supply 0 */
					<960000 965000 975000>, /* Supply 1 */
					<960000 965000 975000>; /* Supply 2 */
@@ -437,12 +437,12 @@ Example 5: Multiple OPP tables
		opp-shared;

		opp00 {
			opp-hz = <600000000>;
			opp-hz = /bits/ 64 <600000000>;
			...
		};

		opp01 {
			opp-hz = <800000000>;
			opp-hz = /bits/ 64 <800000000>;
			...
		};
	};
@@ -453,12 +453,12 @@ Example 5: Multiple OPP tables
		opp-shared;

		opp10 {
			opp-hz = <1000000000>;
			opp-hz = /bits/ 64 <1000000000>;
			...
		};

		opp11 {
			opp-hz = <1100000000>;
			opp-hz = /bits/ 64 <1100000000>;
			...
		};
	};
+868 −227

File changed.

Preview size limit exceeded, changes collapsed.

+62 −11
Original line number Diff line number Diff line
@@ -36,6 +36,12 @@ struct private_data {
	unsigned int voltage_tolerance; /* in percentage */
};

static struct freq_attr *cpufreq_dt_attr[] = {
	&cpufreq_freq_attr_scaling_available_freqs,
	NULL,   /* Extra space for boost-attr if required */
	NULL,
};

static int set_target(struct cpufreq_policy *policy, unsigned int index)
{
	struct dev_pm_opp *opp;
@@ -184,7 +190,6 @@ static int allocate_resources(int cpu, struct device **cdev,

static int cpufreq_init(struct cpufreq_policy *policy)
{
	struct cpufreq_dt_platform_data *pd;
	struct cpufreq_frequency_table *freq_table;
	struct device_node *np;
	struct private_data *priv;
@@ -193,6 +198,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
	struct clk *cpu_clk;
	unsigned long min_uV = ~0, max_uV = 0;
	unsigned int transition_latency;
	bool need_update = false;
	int ret;

	ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk);
@@ -208,8 +214,47 @@ static int cpufreq_init(struct cpufreq_policy *policy)
		goto out_put_reg_clk;
	}

	/* OPPs might be populated at runtime, don't check for error here */
	of_init_opp_table(cpu_dev);
	/* Get OPP-sharing information from "operating-points-v2" bindings */
	ret = of_get_cpus_sharing_opps(cpu_dev, policy->cpus);
	if (ret) {
		/*
		 * operating-points-v2 not supported, fallback to old method of
		 * finding shared-OPPs for backward compatibility.
		 */
		if (ret == -ENOENT)
			need_update = true;
		else
			goto out_node_put;
	}

	/*
	 * Initialize OPP tables for all policy->cpus. They will be shared by
	 * all CPUs which have marked their CPUs shared with OPP bindings.
	 *
	 * For platforms not using operating-points-v2 bindings, we do this
	 * before updating policy->cpus. Otherwise, we will end up creating
	 * duplicate OPPs for policy->cpus.
	 *
	 * OPPs might be populated at runtime, don't check for error here
	 */
	of_cpumask_init_opp_table(policy->cpus);

	if (need_update) {
		struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data();

		if (!pd || !pd->independent_clocks)
			cpumask_setall(policy->cpus);

		/*
		 * OPP tables are initialized only for policy->cpu, do it for
		 * others as well.
		 */
		set_cpus_sharing_opps(cpu_dev, policy->cpus);

		of_property_read_u32(np, "clock-latency", &transition_latency);
	} else {
		transition_latency = dev_pm_opp_get_max_clock_latency(cpu_dev);
	}

	/*
	 * But we need OPP table to function so if it is not there let's
@@ -230,7 +275,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)

	of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);

	if (of_property_read_u32(np, "clock-latency", &transition_latency))
	if (!transition_latency)
		transition_latency = CPUFREQ_ETERNAL;

	if (!IS_ERR(cpu_reg)) {
@@ -291,11 +336,16 @@ static int cpufreq_init(struct cpufreq_policy *policy)
		goto out_free_cpufreq_table;
	}

	policy->cpuinfo.transition_latency = transition_latency;
	/* Support turbo/boost mode */
	if (policy_has_boost_freq(policy)) {
		/* This gets disabled by core on driver unregister */
		ret = cpufreq_enable_boost_support();
		if (ret)
			goto out_free_cpufreq_table;
		cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs;
	}

	pd = cpufreq_get_driver_data();
	if (!pd || !pd->independent_clocks)
		cpumask_setall(policy->cpus);
	policy->cpuinfo.transition_latency = transition_latency;

	of_node_put(np);

@@ -306,7 +356,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
out_free_priv:
	kfree(priv);
out_free_opp:
	of_free_opp_table(cpu_dev);
	of_cpumask_free_opp_table(policy->cpus);
out_node_put:
	of_node_put(np);
out_put_reg_clk:
	clk_put(cpu_clk);
@@ -322,7 +373,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)

	cpufreq_cooling_unregister(priv->cdev);
	dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
	of_free_opp_table(priv->cpu_dev);
	of_cpumask_free_opp_table(policy->related_cpus);
	clk_put(policy->clk);
	if (!IS_ERR(priv->cpu_reg))
		regulator_put(priv->cpu_reg);
@@ -367,7 +418,7 @@ static struct cpufreq_driver dt_cpufreq_driver = {
	.exit = cpufreq_exit,
	.ready = cpufreq_ready,
	.name = "cpufreq-dt",
	.attr = cpufreq_generic_attr,
	.attr = cpufreq_dt_attr,
};

static int dt_cpufreq_probe(struct platform_device *pdev)
+48 −20
Original line number Diff line number Diff line
@@ -2412,6 +2412,49 @@ int cpufreq_boost_supported(void)
}
EXPORT_SYMBOL_GPL(cpufreq_boost_supported);

static int create_boost_sysfs_file(void)
{
	int ret;

	if (!cpufreq_boost_supported())
		return 0;

	/*
	 * Check if driver provides function to enable boost -
	 * if not, use cpufreq_boost_set_sw as default
	 */
	if (!cpufreq_driver->set_boost)
		cpufreq_driver->set_boost = cpufreq_boost_set_sw;

	ret = cpufreq_sysfs_create_file(&boost.attr);
	if (ret)
		pr_err("%s: cannot register global BOOST sysfs file\n",
		       __func__);

	return ret;
}

static void remove_boost_sysfs_file(void)
{
	if (cpufreq_boost_supported())
		cpufreq_sysfs_remove_file(&boost.attr);
}

int cpufreq_enable_boost_support(void)
{
	if (!cpufreq_driver)
		return -EINVAL;

	if (cpufreq_boost_supported())
		return 0;

	cpufreq_driver->boost_supported = true;

	/* This will get removed on driver unregister */
	return create_boost_sysfs_file();
}
EXPORT_SYMBOL_GPL(cpufreq_enable_boost_support);

int cpufreq_boost_enabled(void)
{
	return cpufreq_driver->boost_enabled;
@@ -2465,21 +2508,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
	if (driver_data->setpolicy)
		driver_data->flags |= CPUFREQ_CONST_LOOPS;

	if (cpufreq_boost_supported()) {
		/*
		 * Check if driver provides function to enable boost -
		 * if not, use cpufreq_boost_set_sw as default
		 */
		if (!cpufreq_driver->set_boost)
			cpufreq_driver->set_boost = cpufreq_boost_set_sw;

		ret = cpufreq_sysfs_create_file(&boost.attr);
		if (ret) {
			pr_err("%s: cannot register global BOOST sysfs file\n",
			       __func__);
	ret = create_boost_sysfs_file();
	if (ret)
		goto err_null_driver;
		}
	}

	ret = subsys_interface_register(&cpufreq_interface);
	if (ret)
@@ -2503,8 +2534,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
err_if_unreg:
	subsys_interface_unregister(&cpufreq_interface);
err_boost_unreg:
	if (cpufreq_boost_supported())
		cpufreq_sysfs_remove_file(&boost.attr);
	remove_boost_sysfs_file();
err_null_driver:
	write_lock_irqsave(&cpufreq_driver_lock, flags);
	cpufreq_driver = NULL;
@@ -2533,9 +2563,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
	/* Protect against concurrent cpu hotplug */
	get_online_cpus();
	subsys_interface_unregister(&cpufreq_interface);
	if (cpufreq_boost_supported())
		cpufreq_sysfs_remove_file(&boost.attr);

	remove_boost_sysfs_file();
	unregister_hotcpu_notifier(&cpufreq_cpu_notifier);

	write_lock_irqsave(&cpufreq_driver_lock, flags);
+4 −0
Original line number Diff line number Diff line
@@ -75,6 +75,10 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
		}
		freq_table[i].driver_data = i;
		freq_table[i].frequency = rate / 1000;

		/* Is Boost/turbo opp ? */
		if (dev_pm_opp_is_turbo(opp))
			freq_table[i].flags = CPUFREQ_BOOST_FREQ;
	}

	freq_table[i].driver_data = i;
Loading