|
@@ -184,7 +184,6 @@ try_again:
|
|
|
|
|
|
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 +192,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 +208,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 +269,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)) {
|
|
@@ -293,10 +332,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|
|
|
|
|
policy->cpuinfo.transition_latency = transition_latency;
|
|
|
|
|
|
- pd = cpufreq_get_driver_data();
|
|
|
- if (!pd || !pd->independent_clocks)
|
|
|
- cpumask_setall(policy->cpus);
|
|
|
-
|
|
|
of_node_put(np);
|
|
|
|
|
|
return 0;
|
|
@@ -306,7 +341,8 @@ out_free_cpufreq_table:
|
|
|
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 +358,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);
|