Commit 9c2ff665 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-cpufreq'

* pm-cpufreq: (30 commits)
  cpufreq: stats: Fix string format specifier mismatch
  arm: disable frequency invariance for CONFIG_BL_SWITCHER
  cpufreq,arm,arm64: restructure definitions of arch_set_freq_scale()
  cpufreq: stats: Add memory barrier to store_reset()
  cpufreq: schedutil: Simplify sugov_fast_switch()
  cpufreq: Move traces and update to policy->cur to cpufreq core
  cpufreq: stats: Enable stats for fast-switch as well
  cpufreq: stats: Mark few conditionals with unlikely()
  cpufreq: stats: Remove locking
  cpufreq: stats: Defer stats update to cpufreq_stats_record_transition()
  arch_topology, arm, arm64: define arch_scale_freq_invariant()
  arch_topology, cpufreq: constify arch_* cpumasks
  cpufreq: report whether cpufreq supports Frequency Invariance (FI)
  cpufreq: move invariance setter calls in cpufreq core
  arch_topology: validate input frequencies to arch_set_freq_scale()
  cpufreq: qcom: Don't add frequencies without an OPP
  cpufreq: qcom-hw: Add cpufreq support for SM8250 SoC
  cpufreq: qcom-hw: Use of_device_get_match_data for offsets and row size
  cpufreq: qcom-hw: Use devm_platform_ioremap_resource() to simplify code
  dt-bindings: cpufreq: cpufreq-qcom-hw: Document Qcom EPSS compatible
  ...
parents 757e2821 b7af6080
...@@ -8,7 +8,7 @@ Properties: ...@@ -8,7 +8,7 @@ Properties:
- compatible - compatible
Usage: required Usage: required
Value type: <string> Value type: <string>
Definition: must be "qcom,cpufreq-hw". Definition: must be "qcom,cpufreq-hw" or "qcom,cpufreq-epss".
- clocks - clocks
Usage: required Usage: required
......
...@@ -7,8 +7,13 @@ ...@@ -7,8 +7,13 @@
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/arch_topology.h> #include <linux/arch_topology.h>
/* big.LITTLE switcher is incompatible with frequency invariance */
#ifndef CONFIG_BL_SWITCHER
/* Replace task scheduler's default frequency-invariant accounting */ /* Replace task scheduler's default frequency-invariant accounting */
#define arch_set_freq_scale topology_set_freq_scale
#define arch_scale_freq_capacity topology_get_freq_scale #define arch_scale_freq_capacity topology_get_freq_scale
#define arch_scale_freq_invariant topology_scale_freq_invariant
#endif
/* Replace task scheduler's default cpu-invariant accounting */ /* Replace task scheduler's default cpu-invariant accounting */
#define arch_scale_cpu_capacity topology_get_cpu_scale #define arch_scale_cpu_capacity topology_get_cpu_scale
......
...@@ -26,7 +26,9 @@ void topology_scale_freq_tick(void); ...@@ -26,7 +26,9 @@ void topology_scale_freq_tick(void);
#endif /* CONFIG_ARM64_AMU_EXTN */ #endif /* CONFIG_ARM64_AMU_EXTN */
/* Replace task scheduler's default frequency-invariant accounting */ /* Replace task scheduler's default frequency-invariant accounting */
#define arch_set_freq_scale topology_set_freq_scale
#define arch_scale_freq_capacity topology_get_freq_scale #define arch_scale_freq_capacity topology_get_freq_scale
#define arch_scale_freq_invariant topology_scale_freq_invariant
/* Replace task scheduler's default cpu-invariant accounting */ /* Replace task scheduler's default cpu-invariant accounting */
#define arch_scale_cpu_capacity topology_get_cpu_scale #define arch_scale_cpu_capacity topology_get_cpu_scale
......
...@@ -246,6 +246,13 @@ static int __init init_amu_fie(void) ...@@ -246,6 +246,13 @@ static int __init init_amu_fie(void)
static_branch_enable(&amu_fie_key); static_branch_enable(&amu_fie_key);
} }
/*
* If the system is not fully invariant after AMU init, disable
* partial use of counters for frequency invariance.
*/
if (!topology_scale_freq_invariant())
static_branch_disable(&amu_fie_key);
free_valid_mask: free_valid_mask:
free_cpumask_var(valid_cpus); free_cpumask_var(valid_cpus);
...@@ -253,7 +260,7 @@ static int __init init_amu_fie(void) ...@@ -253,7 +260,7 @@ static int __init init_amu_fie(void)
} }
late_initcall_sync(init_amu_fie); late_initcall_sync(init_amu_fie);
bool arch_freq_counters_available(struct cpumask *cpus) bool arch_freq_counters_available(const struct cpumask *cpus)
{ {
return amu_freq_invariant() && return amu_freq_invariant() &&
cpumask_subset(cpus, amu_fie_cpus); cpumask_subset(cpus, amu_fie_cpus);
......
...@@ -21,18 +21,27 @@ ...@@ -21,18 +21,27 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/smp.h> #include <linux/smp.h>
__weak bool arch_freq_counters_available(struct cpumask *cpus) bool topology_scale_freq_invariant(void)
{
return cpufreq_supports_freq_invariance() ||
arch_freq_counters_available(cpu_online_mask);
}
__weak bool arch_freq_counters_available(const struct cpumask *cpus)
{ {
return false; return false;
} }
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
unsigned long max_freq) unsigned long max_freq)
{ {
unsigned long scale; unsigned long scale;
int i; int i;
if (WARN_ON_ONCE(!cur_freq || !max_freq))
return;
/* /*
* If the use of counters for FIE is enabled, just return as we don't * If the use of counters for FIE is enabled, just return as we don't
* want to update the scale factor with information from CPUFREQ. * want to update the scale factor with information from CPUFREQ.
......
...@@ -283,7 +283,7 @@ config ARM_SPEAR_CPUFREQ ...@@ -283,7 +283,7 @@ config ARM_SPEAR_CPUFREQ
config ARM_STI_CPUFREQ config ARM_STI_CPUFREQ
tristate "STi CPUFreq support" tristate "STi CPUFreq support"
depends on SOC_STIH407 depends on CPUFREQ_DT && SOC_STIH407
help help
This driver uses the generic OPP framework to match the running This driver uses the generic OPP framework to match the running
platform with a predefined set of suitable values. If not provided platform with a predefined set of suitable values. If not provided
......
...@@ -484,6 +484,12 @@ static int __init armada37xx_cpufreq_driver_init(void) ...@@ -484,6 +484,12 @@ static int __init armada37xx_cpufreq_driver_init(void)
/* late_initcall, to guarantee the driver is loaded after A37xx clock driver */ /* late_initcall, to guarantee the driver is loaded after A37xx clock driver */
late_initcall(armada37xx_cpufreq_driver_init); late_initcall(armada37xx_cpufreq_driver_init);
static const struct of_device_id __maybe_unused armada37xx_cpufreq_of_match[] = {
{ .compatible = "marvell,armada-3700-nb-pm" },
{ },
};
MODULE_DEVICE_TABLE(of, armada37xx_cpufreq_of_match);
MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
MODULE_DESCRIPTION("Armada 37xx cpufreq driver"); MODULE_DESCRIPTION("Armada 37xx cpufreq driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -137,6 +137,7 @@ static const struct of_device_id blacklist[] __initconst = { ...@@ -137,6 +137,7 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "st,stih407", }, { .compatible = "st,stih407", },
{ .compatible = "st,stih410", }, { .compatible = "st,stih410", },
{ .compatible = "st,stih418", },
{ .compatible = "sigma,tango4", }, { .compatible = "sigma,tango4", },
......
This diff is collapsed.
...@@ -61,6 +61,12 @@ static struct cpufreq_driver *cpufreq_driver; ...@@ -61,6 +61,12 @@ static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_RWLOCK(cpufreq_driver_lock); static DEFINE_RWLOCK(cpufreq_driver_lock);
static DEFINE_STATIC_KEY_FALSE(cpufreq_freq_invariance);
bool cpufreq_supports_freq_invariance(void)
{
return static_branch_likely(&cpufreq_freq_invariance);
}
/* Flag to suspend/resume CPUFreq governors */ /* Flag to suspend/resume CPUFreq governors */
static bool cpufreq_suspended; static bool cpufreq_suspended;
...@@ -154,12 +160,6 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) ...@@ -154,12 +160,6 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
} }
EXPORT_SYMBOL_GPL(get_cpu_idle_time); EXPORT_SYMBOL_GPL(get_cpu_idle_time);
__weak void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
unsigned long max_freq)
{
}
EXPORT_SYMBOL_GPL(arch_set_freq_scale);
/* /*
* This is a generic cpufreq init() routine which can be used by cpufreq * This is a generic cpufreq init() routine which can be used by cpufreq
* drivers of SMP systems. It will do following: * drivers of SMP systems. It will do following:
...@@ -446,6 +446,10 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, ...@@ -446,6 +446,10 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
cpufreq_notify_post_transition(policy, freqs, transition_failed); cpufreq_notify_post_transition(policy, freqs, transition_failed);
arch_set_freq_scale(policy->related_cpus,
policy->cur,
policy->cpuinfo.max_freq);
policy->transition_ongoing = false; policy->transition_ongoing = false;
policy->transition_task = NULL; policy->transition_task = NULL;
...@@ -2056,9 +2060,26 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier); ...@@ -2056,9 +2060,26 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq) unsigned int target_freq)
{ {
unsigned int freq;
int cpu;
target_freq = clamp_val(target_freq, policy->min, policy->max); target_freq = clamp_val(target_freq, policy->min, policy->max);
freq = cpufreq_driver->fast_switch(policy, target_freq);
return cpufreq_driver->fast_switch(policy, target_freq); if (!freq)
return 0;
policy->cur = freq;
arch_set_freq_scale(policy->related_cpus, freq,
policy->cpuinfo.max_freq);
cpufreq_stats_record_transition(policy, freq);
if (trace_cpu_frequency_enabled()) {
for_each_cpu(cpu, policy->cpus)
trace_cpu_frequency(freq, cpu);
}
return freq;
} }
EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch); EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
...@@ -2710,6 +2731,15 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ...@@ -2710,6 +2731,15 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data; cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
/*
* Mark support for the scheduler's frequency invariance engine for
* drivers that implement target(), target_index() or fast_switch().
*/
if (!cpufreq_driver->setpolicy) {
static_branch_enable_cpuslocked(&cpufreq_freq_invariance);
pr_debug("supports frequency invariance");
}
if (driver_data->setpolicy) if (driver_data->setpolicy)
driver_data->flags |= CPUFREQ_CONST_LOOPS; driver_data->flags |= CPUFREQ_CONST_LOOPS;
...@@ -2779,6 +2809,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) ...@@ -2779,6 +2809,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
cpus_read_lock(); cpus_read_lock();
subsys_interface_unregister(&cpufreq_interface); subsys_interface_unregister(&cpufreq_interface);
remove_boost_sysfs_file(); remove_boost_sysfs_file();
static_branch_disable_cpuslocked(&cpufreq_freq_invariance);
cpuhp_remove_state_nocalls_cpuslocked(hp_online); cpuhp_remove_state_nocalls_cpuslocked(hp_online);
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
......
...@@ -19,64 +19,104 @@ struct cpufreq_stats { ...@@ -19,64 +19,104 @@ struct cpufreq_stats {
unsigned int state_num; unsigned int state_num;
unsigned int last_index; unsigned int last_index;
u64 *time_in_state; u64 *time_in_state;
spinlock_t lock;
unsigned int *freq_table; unsigned int *freq_table;
unsigned int *trans_table; unsigned int *trans_table;
/* Deferred reset */
unsigned int reset_pending;
unsigned long long reset_time;
}; };
static void cpufreq_stats_update(struct cpufreq_stats *stats) static void cpufreq_stats_update(struct cpufreq_stats *stats,
unsigned long long time)
{ {
unsigned long long cur_time = get_jiffies_64(); unsigned long long cur_time = get_jiffies_64();
stats->time_in_state[stats->last_index] += cur_time - stats->last_time; stats->time_in_state[stats->last_index] += cur_time - time;
stats->last_time = cur_time; stats->last_time = cur_time;
} }
static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) static void cpufreq_stats_reset_table(struct cpufreq_stats *stats)
{ {
unsigned int count = stats->max_state; unsigned int count = stats->max_state;
spin_lock(&stats->lock);
memset(stats->time_in_state, 0, count * sizeof(u64)); memset(stats->time_in_state, 0, count * sizeof(u64));
memset(stats->trans_table, 0, count * count * sizeof(int)); memset(stats->trans_table, 0, count * count * sizeof(int));
stats->last_time = get_jiffies_64(); stats->last_time = get_jiffies_64();
stats->total_trans = 0; stats->total_trans = 0;
spin_unlock(&stats->lock);
/* Adjust for the time elapsed since reset was requested */
WRITE_ONCE(stats->reset_pending, 0);
/*
* Prevent the reset_time read from being reordered before the
* reset_pending accesses in cpufreq_stats_record_transition().
*/
smp_rmb();
cpufreq_stats_update(stats, READ_ONCE(stats->reset_time));
} }
static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
{ {
return sprintf(buf, "%d\n", policy->stats->total_trans); struct cpufreq_stats *stats = policy->stats;
if (READ_ONCE(stats->reset_pending))
return sprintf(buf, "%d\n", 0);
else
return sprintf(buf, "%u\n", stats->total_trans);
} }
cpufreq_freq_attr_ro(total_trans); cpufreq_freq_attr_ro(total_trans);
static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
{ {
struct cpufreq_stats *stats = policy->stats; struct cpufreq_stats *stats = policy->stats;
bool pending = READ_ONCE(stats->reset_pending);
unsigned long long time;
ssize_t len = 0; ssize_t len = 0;
int i; int i;
if (policy->fast_switch_enabled)
return 0;
spin_lock(&stats->lock);
cpufreq_stats_update(stats);
spin_unlock(&stats->lock);
for (i = 0; i < stats->state_num; i++) { for (i = 0; i < stats->state_num; i++) {
if (pending) {
if (i == stats->last_index) {
/*
* Prevent the reset_time read from occurring
* before the reset_pending read above.
*/
smp_rmb();
time = get_jiffies_64() - READ_ONCE(stats->reset_time);
} else {
time = 0;
}
} else {
time = stats->time_in_state[i];
if (i == stats->last_index)
time += get_jiffies_64() - stats->last_time;
}
len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i], len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
(unsigned long long) jiffies_64_to_clock_t(time));
jiffies_64_to_clock_t(stats->time_in_state[i]));
} }
return len; return len;
} }
cpufreq_freq_attr_ro(time_in_state); cpufreq_freq_attr_ro(time_in_state);
/* We don't care what is written to the attribute */
static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf, static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
size_t count) size_t count)
{ {
/* We don't care what is written to the attribute. */ struct cpufreq_stats *stats = policy->stats;
cpufreq_stats_clear_table(policy->stats);
/*
* Defer resetting of stats to cpufreq_stats_record_transition() to
* avoid races.
*/
WRITE_ONCE(stats->reset_time, get_jiffies_64());
/*
* The memory barrier below is to prevent the readers of reset_time from
* seeing a stale or partially updated value.
*/
smp_wmb();
WRITE_ONCE(stats->reset_pending, 1);
return count; return count;
} }
cpufreq_freq_attr_wo(reset); cpufreq_freq_attr_wo(reset);
...@@ -84,11 +124,9 @@ cpufreq_freq_attr_wo(reset); ...@@ -84,11 +124,9 @@ cpufreq_freq_attr_wo(reset);
static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
{ {
struct cpufreq_stats *stats = policy->stats; struct cpufreq_stats *stats = policy->stats;
bool pending = READ_ONCE(stats->reset_pending);
ssize_t len = 0; ssize_t len = 0;
int i, j; int i, j, count;
if (policy->fast_switch_enabled)
return 0;
len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n");
len += scnprintf(buf + len, PAGE_SIZE - len, " : "); len += scnprintf(buf + len, PAGE_SIZE - len, " : ");
...@@ -113,8 +151,13 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) ...@@ -113,8 +151,13 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
for (j = 0; j < stats->state_num; j++) { for (j = 0; j < stats->state_num; j++) {
if (len >= PAGE_SIZE) if (len >= PAGE_SIZE)
break; break;
len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ",
stats->trans_table[i*stats->max_state+j]); if (pending)
count = 0;
else
count = stats->trans_table[i * stats->max_state + j];
len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ", count);
} }
if (len >= PAGE_SIZE) if (len >= PAGE_SIZE)
break; break;
...@@ -208,7 +251,6 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) ...@@ -208,7 +251,6 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
stats->state_num = i; stats->state_num = i;
stats->last_time = get_jiffies_64(); stats->last_time = get_jiffies_64();
stats->last_index = freq_table_get_index(stats, policy->cur); stats->last_index = freq_table_get_index(stats, policy->cur);
spin_lock_init(&stats->lock);
policy->stats = stats; policy->stats = stats;
ret = sysfs_create_group(&policy->kobj, &stats_attr_group); ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
...@@ -228,23 +270,22 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy, ...@@ -228,23 +270,22 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
struct cpufreq_stats *stats = policy->stats; struct cpufreq_stats *stats = policy->stats;
int old_index, new_index; int old_index, new_index;
if (!stats) { if (unlikely(!stats))
pr_debug("%s: No stats found\n", __func__);
return; return;
}
if (unlikely(READ_ONCE(stats->reset_pending)))
cpufreq_stats_reset_table(stats);
old_index = stats->last_index; old_index = stats->last_index;
new_index = freq_table_get_index(stats, new_freq); new_index = freq_table_get_index(stats, new_freq);
/* We can't do stats->time_in_state[-1]= .. */ /* We can't do stats->time_in_state[-1]= .. */
if (old_index == -1 || new_index == -1 || old_index == new_index) if (unlikely(old_index == -1 || new_index == -1 || old_index == new_index))
return; return;
spin_lock(&stats->lock); cpufreq_stats_update(stats, stats->last_time);
cpufreq_stats_update(stats);
stats->last_index = new_index; stats->last_index = new_index;
stats->trans_table[old_index * stats->max_state + new_index]++; stats->trans_table[old_index * stats->max_state + new_index]++;
stats->total_trans++; stats->total_trans++;
spin_unlock(&stats->lock);
} }
...@@ -48,7 +48,6 @@ static struct clk_bulk_data clks[] = { ...@@ -48,7 +48,6 @@ static struct clk_bulk_data clks[] = {
}; };
static struct device *cpu_dev; static struct device *cpu_dev;
static bool free_opp;
static struct cpufreq_frequency_table *freq_table; static struct cpufreq_frequency_table *freq_table;
static unsigned int max_freq; static unsigned int max_freq;
static unsigned int transition_latency; static unsigned int transition_latency;
...@@ -390,9 +389,6 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) ...@@ -390,9 +389,6 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
goto put_reg; goto put_reg;
} }
/* Because we have added the OPPs here, we must free them */
free_opp = true;
if (of_machine_is_compatible("fsl,imx6ul") || if (of_machine_is_compatible("fsl,imx6ul") ||
of_machine_is_compatible("fsl,imx6ull")) { of_machine_is_compatible("fsl,imx6ull")) {
ret = imx6ul_opp_check_speed_grading(cpu_dev); ret = imx6ul_opp_check_speed_grading(cpu_dev);
...@@ -507,8 +503,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) ...@@ -507,8 +503,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
free_freq_table: free_freq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
out_free_opp: out_free_opp:
if (free_opp) dev_pm_opp_of_remove_table(cpu_dev);
dev_pm_opp_of_remove_table(cpu_dev);
put_reg: put_reg:
if (!IS_ERR(arm_reg)) if (!IS_ERR(arm_reg))
regulator_put(arm_reg); regulator_put(arm_reg);
...@@ -528,8 +523,7 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev) ...@@ -528,8 +523,7 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
{ {
cpufreq_unregister_driver(&imx6q_cpufreq_driver); cpufreq_unregister_driver(&imx6q_cpufreq_driver);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
if (free_opp) dev_pm_opp_of_remove_table(cpu_dev);
dev_pm_opp_of_remove_table(cpu_dev);
regulator_put(arm_reg); regulator_put(arm_reg);
if (!IS_ERR(pu_reg)) if (!IS_ERR(pu_reg))
regulator_put(pu_reg); regulator_put(pu_reg);
......
...@@ -19,18 +19,23 @@ ...@@ -19,18 +19,23 @@
#define LUT_L_VAL GENMASK(7, 0) #define LUT_L_VAL GENMASK(7, 0)
#define LUT_CORE_COUNT GENMASK(18, 16) #define LUT_CORE_COUNT GENMASK(18, 16)
#define LUT_VOLT GENMASK(11, 0) #define LUT_VOLT GENMASK(11, 0)
#define LUT_ROW_SIZE 32
#define CLK_HW_DIV 2 #define CLK_HW_DIV 2
#define LUT_TURBO_IND 1 #define LUT_TURBO_IND 1
/* Register offsets */ struct qcom_cpufreq_soc_data {
#define REG_ENABLE 0x0 u32 reg_enable;
#define REG_FREQ_LUT 0x110 u32 reg_freq_lut;
#define REG_VOLT_LUT 0x114 u32 reg_volt_lut;
#define REG_PERF_STATE 0x920 u32 reg_perf_state;
u8 lut_row_size;
};
struct qcom_cpufreq_data {
void __iomem *base;
const struct qcom_cpufreq_soc_data *soc_data;
};
static unsigned long cpu_hw_rate, xo_rate; static unsigned long cpu_hw_rate, xo_rate;
static struct platform_device *global_pdev;
static bool icc_scaling_enabled; static bool icc_scaling_enabled;
static int qcom_cpufreq_set_bw(struct cpufreq_policy *policy, static int qcom_cpufreq_set_bw(struct cpufreq_policy *policy,
...@@ -77,22 +82,22 @@ static int qcom_cpufreq_update_opp(struct device *cpu_dev, ...@@ -77,22 +82,22 @@ static int qcom_cpufreq_update_opp(struct device *cpu_dev,
static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
void __iomem *perf_state_reg = policy->driver_data; struct qcom_cpufreq_data *data = policy->driver_data;
const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
unsigned long freq = policy->freq_table[index].frequency; unsigned long freq = policy->freq_table[index].frequency;
writel_relaxed(index, perf_state_reg); writel_relaxed(index, data->base + soc_data->reg_perf_state);
if (icc_scaling_enabled) if (icc_scaling_enabled)
qcom_cpufreq_set_bw(policy, freq); qcom_cpufreq_set_bw(policy, freq);
arch_set_freq_scale(policy->related_cpus, freq,
policy->cpuinfo.max_freq);
return 0; return 0;
} }
static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
{ {
void __iomem *perf_state_reg; struct qcom_cpufreq_data *data;
const struct qcom_cpufreq_soc_data *soc_data;
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
unsigned int index; unsigned int index;
...@@ -100,9 +105,10 @@ static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) ...@@ -100,9 +105,10 @@ static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
if (!policy) if (!policy)
return 0; return 0;
perf_state_reg = policy->driver_data; data = policy->driver_data;
soc_data = data->soc_data;
index = readl_relaxed(perf_state_reg); index = readl_relaxed(data->base + soc_data->reg_perf_state);
index = min(index, LUT_MAX_ENTRIES - 1); index = min(index, LUT_MAX_ENTRIES - 1);
return policy->freq_table[index].frequency; return policy->freq_table[index].frequency;
...@@ -111,23 +117,18 @@ static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) ...@@ -111,23 +117,18 @@ static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq) unsigned int target_freq)
{ {
void __iomem *perf_state_reg = policy->driver_data; struct qcom_cpufreq_data *data = policy->driver_data;
const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
unsigned int index; unsigned int index;
unsigned long freq;
index = policy->cached_resolved_idx; index = policy->cached_resolved_idx;
writel_relaxed(index, perf_state_reg); writel_relaxed(index, data->base + soc_data->reg_perf_state);
freq = policy->freq_table[index].frequency; return policy->freq_table[index].frequency;
arch_set_freq_scale(policy->related_cpus, freq,
policy->cpuinfo.max_freq);
return freq;
} }
static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
struct cpufreq_policy *policy, struct cpufreq_policy *policy)
void __iomem *base)
{ {
u32 data, src, lval, i, core_count, prev_freq = 0, freq; u32 data, src, lval, i, core_count, prev_freq = 0, freq;
u32 volt; u32 volt;
...@@ -135,6 +136,8 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, ...@@ -135,6 +136,8 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
unsigned long rate; unsigned long rate;
int ret; int ret;
struct qcom_cpufreq_data *drv_data = policy->driver_data;
const struct qcom_cpufreq_soc_data *soc_data = drv_data->soc_data;
table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL); table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL);
if (!table) if (!table)
...@@ -161,14 +164,14 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, ...@@ -161,14 +164,14 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
} }
for (i = 0; i < LUT_MAX_ENTRIES; i++) { for (i = 0; i < LUT_MAX_ENTRIES; i++) {
data = readl_relaxed(base + REG_FREQ_LUT + data = readl_relaxed(drv_data->base + soc_data->reg_freq_lut +
i * LUT_ROW_SIZE); i * soc_data->lut_row_size);
src = FIELD_GET(LUT_SRC, data); src = FIELD_GET(LUT_SRC, data);
lval = FIELD_GET(LUT_L_VAL, data); lval = FIELD_GET(LUT_L_VAL, data);
core_count = FIELD_GET(LUT_CORE_COUNT, data); core_count = FIELD_GET(LUT_CORE_COUNT, data);
data = readl_relaxed(base + REG_VOLT_LUT + data = readl_relaxed(drv_data->base + soc_data->reg_volt_lut +
i * LUT_ROW_SIZE); i * soc_data->lut_row_size);
volt = FIELD_GET(LUT_VOLT, data) * 1000; volt = FIELD_GET(LUT_VOLT, data) * 1000;
if (src) if (src)
...@@ -177,10 +180,15 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, ...@@ -177,10 +180,15 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
freq = cpu_hw_rate / 1000; freq = cpu_hw_rate / 1000;
if (freq != prev_freq && core_count != LUT_TURBO_IND) { if (freq != prev_freq && core_count != LUT_TURBO_IND) {
table[i].frequency = freq; if (!qcom_cpufreq_update_opp(cpu_dev, freq, volt)) {
qcom_cpufreq_update_opp(cpu_dev, freq, volt); table[i].frequency = freq;
dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d\n", i, dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d\n", i,
freq, core_count); freq, core_count);
} else {
dev_warn(cpu_dev, "failed to update OPP for freq=%d\n", freq);
table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
} else if (core_count == LUT_TURBO_IND) { } else if (core_count == LUT_TURBO_IND) {
table[i].frequency = CPUFREQ_ENTRY_INVALID; table[i].frequency = CPUFREQ_ENTRY_INVALID;
} }
...@@ -197,9 +205,13 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, ...@@ -197,9 +205,13 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
* as the boost frequency * as the boost frequency
*/ */
if (prev->frequency == CPUFREQ_ENTRY_INVALID) { if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
prev->frequency = prev_freq; if (!qcom_cpufreq_update_opp(cpu_dev, prev_freq, volt)) {
prev->flags = CPUFREQ_BOOST_FREQ; prev->frequency = prev_freq;
qcom_cpufreq_update_opp(cpu_dev, prev_freq, volt); prev->flags = CPUFREQ_BOOST_FREQ;
} else {
dev_warn(cpu_dev, "failed to update OPP for freq=%d\n",
freq);
}
} }
break; break;
...@@ -238,14 +250,38 @@ static void qcom_get_related_cpus(int index, struct cpumask *m) ...@@ -238,14 +250,38 @@ static void qcom_get_related_cpus(int index, struct cpumask *m)
} }
} }
static const struct qcom_cpufreq_soc_data qcom_soc_data = {
.reg_enable = 0x0,
.reg_freq_lut = 0x110,
.reg_volt_lut = 0x114,
.reg_perf_state = 0x920,
.lut_row_size = 32,
};
static const struct qcom_cpufreq_soc_data epss_soc_data = {
.reg_enable = 0x0,
.reg_freq_lut = 0x100,
.reg_volt_lut = 0x200,
.reg_perf_state = 0x320,
.lut_row_size = 4,
};
static const struct of_device_id qcom_cpufreq_hw_match[] = {
{ .compatible = "qcom,cpufreq-hw", .data = &qcom_soc_data },
{ .compatible = "qcom,cpufreq-epss", .data = &epss_soc_data },
{}
};
MODULE_DEVICE_TABLE(of, qcom_cpufreq_hw_match);
static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
{ {
struct device *dev = &global_pdev->dev; struct platform_device *pdev = cpufreq_get_driver_data();
struct device *dev = &pdev->dev;
struct of_phandle_args args; struct of_phandle_args args;
struct device_node *cpu_np; struct device_node *cpu_np;
struct device *cpu_dev; struct device *cpu_dev;
struct resource *res;
void __iomem *base; void __iomem *base;
struct qcom_cpufreq_data *data;
int ret, index; int ret, index;
cpu_dev = get_cpu_device(policy->cpu); cpu_dev = get_cpu_device(policy->cpu);
...@@ -267,16 +303,21 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) ...@@ -267,16 +303,21 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
index = args.args[0]; index = args.args[0];
res = platform_get_resource(global_pdev, IORESOURCE_MEM, index); base = devm_platform_ioremap_resource(pdev, index);
if (!res) if (IS_ERR(base))
return -ENODEV; return PTR_ERR(base);
base = devm_ioremap(dev, res->start, resource_size(res)); data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!base) if (!data) {
return -ENOMEM; ret = -ENOMEM;
goto error;
}
data->soc_data = of_device_get_match_data(&pdev->dev);
data->base = base;
/* HW should be in enabled state to proceed */ /* HW should be in enabled state to proceed */
if (!(readl_relaxed(base + REG_ENABLE) & 0x1)) { if (!(readl_relaxed(base + data->soc_data->reg_enable) & 0x1)) {
dev_err(dev, "Domain-%d cpufreq hardware not enabled\n", index); dev_err(dev, "Domain-%d cpufreq hardware not enabled\n", index);
ret = -ENODEV; ret = -ENODEV;
goto error; goto error;
...@@ -289,9 +330,9 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) ...@@ -289,9 +330,9 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
goto error; goto error;
} }
policy->driver_data = base + REG_PERF_STATE; policy->driver_data = data;
ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy, base); ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy);
if (ret) { if (ret) {
dev_err(dev, "Domain-%d failed to read LUT\n", index); dev_err(dev, "Domain-%d failed to read LUT\n", index);
goto error; goto error;
...@@ -315,12 +356,13 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) ...@@ -315,12 +356,13 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
{ {
struct device *cpu_dev = get_cpu_device(policy->cpu); struct device *cpu_dev = get_cpu_device(policy->cpu);
void __iomem *base = policy->driver_data - REG_PERF_STATE; struct qcom_cpufreq_data *data = policy->driver_data;
struct platform_device *pdev = cpufreq_get_driver_data();
dev_pm_opp_remove_all_dynamic(cpu_dev); dev_pm_opp_remove_all_dynamic(cpu_dev);
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
kfree(policy->freq_table); kfree(policy->freq_table);
devm_iounmap(&global_pdev->dev, base); devm_iounmap(&pdev->dev, data->base);
return 0; return 0;
} }
...@@ -365,7 +407,7 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev) ...@@ -365,7 +407,7 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
cpu_hw_rate = clk_get_rate(clk) / CLK_HW_DIV; cpu_hw_rate = clk_get_rate(clk) / CLK_HW_DIV;
clk_put(clk); clk_put(clk);
global_pdev = pdev; cpufreq_qcom_hw_driver.driver_data = pdev;
/* Check for optional interconnect paths on CPU0 */ /* Check for optional interconnect paths on CPU0 */
cpu_dev = get_cpu_device(0); cpu_dev = get_cpu_device(0);
...@@ -390,12 +432,6 @@ static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev) ...@@ -390,12 +432,6 @@ static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)
return cpufreq_unregister_driver(&cpufreq_qcom_hw_driver); return cpufreq_unregister_driver(&cpufreq_qcom_hw_driver);
} }
static const struct of_device_id qcom_cpufreq_hw_match[] = {
{ .compatible = "qcom,cpufreq-hw" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_cpufreq_hw_match);
static struct platform_driver qcom_cpufreq_hw_driver = { static struct platform_driver qcom_cpufreq_hw_driver = {
.probe = qcom_cpufreq_hw_driver_probe, .probe = qcom_cpufreq_hw_driver_probe,
.remove = qcom_cpufreq_hw_driver_remove, .remove = qcom_cpufreq_hw_driver_remove,
......
...@@ -590,6 +590,7 @@ static struct notifier_block s5pv210_cpufreq_reboot_notifier = { ...@@ -590,6 +590,7 @@ static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
static int s5pv210_cpufreq_probe(struct platform_device *pdev) static int s5pv210_cpufreq_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev;
struct device_node *np; struct device_node *np;
int id, result = 0; int id, result = 0;
...@@ -602,28 +603,20 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) ...@@ -602,28 +603,20 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
* cpufreq-dt driver. * cpufreq-dt driver.
*/ */
arm_regulator = regulator_get(NULL, "vddarm"); arm_regulator = regulator_get(NULL, "vddarm");
if (IS_ERR(arm_regulator)) { if (IS_ERR(arm_regulator))
if (PTR_ERR(arm_regulator) == -EPROBE_DEFER) return dev_err_probe(dev, PTR_ERR(arm_regulator),
pr_debug("vddarm regulator not ready, defer\n"); "failed to get regulator vddarm\n");
else
pr_err("failed to get regulator vddarm\n");
return PTR_ERR(arm_regulator);
}
int_regulator = regulator_get(NULL, "vddint"); int_regulator = regulator_get(NULL, "vddint");
if (IS_ERR(int_regulator)) { if (IS_ERR(int_regulator)) {
if (PTR_ERR(int_regulator) == -EPROBE_DEFER) result = dev_err_probe(dev, PTR_ERR(int_regulator),
pr_debug("vddint regulator not ready, defer\n"); "failed to get regulator vddint\n");
else
pr_err("failed to get regulator vddint\n");
result = PTR_ERR(int_regulator);
goto err_int_regulator; goto err_int_regulator;
} }
np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock"); np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock");
if (!np) { if (!np) {
pr_err("%s: failed to find clock controller DT node\n", dev_err(dev, "failed to find clock controller DT node\n");
__func__);
result = -ENODEV; result = -ENODEV;
goto err_clock; goto err_clock;
} }
...@@ -631,7 +624,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) ...@@ -631,7 +624,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
clk_base = of_iomap(np, 0); clk_base = of_iomap(np, 0);
of_node_put(np); of_node_put(np);
if (!clk_base) { if (!clk_base) {
pr_err("%s: failed to map clock registers\n", __func__); dev_err(dev, "failed to map clock registers\n");
result = -EFAULT; result = -EFAULT;
goto err_clock; goto err_clock;
} }
...@@ -639,8 +632,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) ...@@ -639,8 +632,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") { for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") {
id = of_alias_get_id(np, "dmc"); id = of_alias_get_id(np, "dmc");
if (id < 0 || id >= ARRAY_SIZE(dmc_base)) { if (id < 0 || id >= ARRAY_SIZE(dmc_base)) {
pr_err("%s: failed to get alias of dmc node '%pOFn'\n", dev_err(dev, "failed to get alias of dmc node '%pOFn'\n", np);
__func__, np);
of_node_put(np); of_node_put(np);
result = id; result = id;
goto err_clk_base; goto err_clk_base;
...@@ -648,8 +640,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) ...@@ -648,8 +640,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
dmc_base[id] = of_iomap(np, 0); dmc_base[id] = of_iomap(np, 0);
if (!dmc_base[id]) { if (!dmc_base[id]) {
pr_err("%s: failed to map dmc%d registers\n", dev_err(dev, "failed to map dmc%d registers\n", id);
__func__, id);
of_node_put(np); of_node_put(np);
result = -EFAULT; result = -EFAULT;
goto err_dmc; goto err_dmc;
...@@ -658,7 +649,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) ...@@ -658,7 +649,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) { for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) {
if (!dmc_base[id]) { if (!dmc_base[id]) {
pr_err("%s: failed to find dmc%d node\n", __func__, id); dev_err(dev, "failed to find dmc%d node\n", id);
result = -ENODEV; result = -ENODEV;
goto err_dmc; goto err_dmc;
} }
......
...@@ -48,16 +48,11 @@ static unsigned int scmi_cpufreq_get_rate(unsigned int cpu) ...@@ -48,16 +48,11 @@ static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
static int static int
scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
int ret;
struct scmi_data *priv = policy->driver_data; struct scmi_data *priv = policy->driver_data;
struct scmi_perf_ops *perf_ops = handle->perf_ops; struct scmi_perf_ops *perf_ops = handle->perf_ops;
u64 freq = policy->freq_table[index].frequency; u64 freq = policy->freq_table[index].frequency;
ret = perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false); return perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false);
if (!ret)
arch_set_freq_scale(policy->related_cpus, freq,
policy->cpuinfo.max_freq);
return ret;
} }
static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
...@@ -67,11 +62,8 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, ...@@ -67,11 +62,8 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
struct scmi_perf_ops *perf_ops = handle->perf_ops; struct scmi_perf_ops *perf_ops = handle->perf_ops;
if (!perf_ops->freq_set(handle, priv->domain_id, if (!perf_ops->freq_set(handle, priv->domain_id,
target_freq * 1000, true)) { target_freq * 1000, true))
arch_set_freq_scale(policy->related_cpus, target_freq,
policy->cpuinfo.max_freq);
return target_freq; return target_freq;
}
return 0; return 0;
} }
......
...@@ -47,9 +47,8 @@ static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) ...@@ -47,9 +47,8 @@ static unsigned int scpi_cpufreq_get_rate(unsigned int cpu)
static int static int
scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
unsigned long freq = policy->freq_table[index].frequency; u64 rate = policy->freq_table[index].frequency * 1000;
struct scpi_data *priv = policy->driver_data; struct scpi_data *priv = policy->driver_data;
u64 rate = freq * 1000;
int ret; int ret;
ret = clk_set_rate(priv->clk, rate); ret = clk_set_rate(priv->clk, rate);
...@@ -60,9 +59,6 @@ scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -60,9 +59,6 @@ scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
if (clk_get_rate(priv->clk) != rate) if (clk_get_rate(priv->clk) != rate)
return -EIO; return -EIO;
arch_set_freq_scale(policy->related_cpus, freq,
policy->cpuinfo.max_freq);
return 0; return 0;
} }
......
...@@ -141,7 +141,8 @@ static const struct reg_field sti_stih407_dvfs_regfields[DVFS_MAX_REGFIELDS] = { ...@@ -141,7 +141,8 @@ static const struct reg_field sti_stih407_dvfs_regfields[DVFS_MAX_REGFIELDS] = {
static const struct reg_field *sti_cpufreq_match(void) static const struct reg_field *sti_cpufreq_match(void)
{ {
if (of_machine_is_compatible("st,stih407") || if (of_machine_is_compatible("st,stih407") ||
of_machine_is_compatible("st,stih410")) of_machine_is_compatible("st,stih410") ||
of_machine_is_compatible("st,stih418"))
return sti_stih407_dvfs_regfields; return sti_stih407_dvfs_regfields;
return NULL; return NULL;
...@@ -258,7 +259,8 @@ static int sti_cpufreq_init(void) ...@@ -258,7 +259,8 @@ static int sti_cpufreq_init(void)
int ret; int ret;
if ((!of_machine_is_compatible("st,stih407")) && if ((!of_machine_is_compatible("st,stih407")) &&
(!of_machine_is_compatible("st,stih410"))) (!of_machine_is_compatible("st,stih410")) &&
(!of_machine_is_compatible("st,stih418")))
return -ENODEV; return -ENODEV;
ddata.cpu = get_cpu_device(0); ddata.cpu = get_cpu_device(0);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define EDVD_CORE_VOLT_FREQ(core) (0x20 + (core) * 0x4) #define EDVD_CORE_VOLT_FREQ(core) (0x20 + (core) * 0x4)
#define EDVD_CORE_VOLT_FREQ_F_SHIFT 0 #define EDVD_CORE_VOLT_FREQ_F_SHIFT 0
#define EDVD_CORE_VOLT_FREQ_F_MASK 0xffff
#define EDVD_CORE_VOLT_FREQ_V_SHIFT 16 #define EDVD_CORE_VOLT_FREQ_V_SHIFT 16
struct tegra186_cpufreq_cluster_info { struct tegra186_cpufreq_cluster_info {
...@@ -91,10 +92,39 @@ static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -91,10 +92,39 @@ static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy,
return 0; return 0;
} }
static unsigned int tegra186_cpufreq_get(unsigned int cpu)
{
struct cpufreq_frequency_table *tbl;
struct cpufreq_policy *policy;
void __iomem *edvd_reg;
unsigned int i, freq = 0;
u32 ndiv;
policy = cpufreq_cpu_get(cpu);
if (!policy)
return 0;
tbl = policy->freq_table;
edvd_reg = policy->driver_data;
ndiv = readl(edvd_reg) & EDVD_CORE_VOLT_FREQ_F_MASK;
for (i = 0; tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
if ((tbl[i].driver_data & EDVD_CORE_VOLT_FREQ_F_MASK) == ndiv) {
freq = tbl[i].frequency;
break;
}
}
cpufreq_cpu_put(policy);
return freq;
}
static struct cpufreq_driver tegra186_cpufreq_driver = { static struct cpufreq_driver tegra186_cpufreq_driver = {
.name = "tegra186", .name = "tegra186",
.flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
CPUFREQ_NEED_INITIAL_FREQ_CHECK, CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.get = tegra186_cpufreq_get,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = tegra186_cpufreq_set_target, .target_index = tegra186_cpufreq_set_target,
.init = tegra186_cpufreq_init, .init = tegra186_cpufreq_init,
......
...@@ -182,7 +182,6 @@ static int ve_spc_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -182,7 +182,6 @@ static int ve_spc_cpufreq_set_target(struct cpufreq_policy *policy,
{ {
u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster; u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster;
unsigned int freqs_new; unsigned int freqs_new;
int ret;
cur_cluster = cpu_to_cluster(cpu); cur_cluster = cpu_to_cluster(cpu);
new_cluster = actual_cluster = per_cpu(physical_cluster, cpu); new_cluster = actual_cluster = per_cpu(physical_cluster, cpu);
...@@ -197,15 +196,8 @@ static int ve_spc_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -197,15 +196,8 @@ static int ve_spc_cpufreq_set_target(struct cpufreq_policy *policy,
new_cluster = A15_CLUSTER; new_cluster = A15_CLUSTER;
} }
ret = ve_spc_cpufreq_set_rate(cpu, actual_cluster, new_cluster, return ve_spc_cpufreq_set_rate(cpu, actual_cluster, new_cluster,
freqs_new); freqs_new);
if (!ret) {
arch_set_freq_scale(policy->related_cpus, freqs_new,
policy->cpuinfo.max_freq);
}
return ret;
} }
static inline u32 get_table_count(struct cpufreq_frequency_table *table) static inline u32 get_table_count(struct cpufreq_frequency_table *table)
......
...@@ -30,7 +30,11 @@ static inline unsigned long topology_get_freq_scale(int cpu) ...@@ -30,7 +30,11 @@ static inline unsigned long topology_get_freq_scale(int cpu)
return per_cpu(freq_scale, cpu); return per_cpu(freq_scale, cpu);
} }
bool arch_freq_counters_available(struct cpumask *cpus); void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
unsigned long max_freq);
bool topology_scale_freq_invariant(void);
bool arch_freq_counters_available(const struct cpumask *cpus);
DECLARE_PER_CPU(unsigned long, thermal_pressure); DECLARE_PER_CPU(unsigned long, thermal_pressure);
......
...@@ -217,6 +217,7 @@ void refresh_frequency_limits(struct cpufreq_policy *policy); ...@@ -217,6 +217,7 @@ void refresh_frequency_limits(struct cpufreq_policy *policy);
void cpufreq_update_policy(unsigned int cpu); void cpufreq_update_policy(unsigned int cpu);
void cpufreq_update_limits(unsigned int cpu); void cpufreq_update_limits(unsigned int cpu);
bool have_governor_per_policy(void); bool have_governor_per_policy(void);
bool cpufreq_supports_freq_invariance(void);
struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy); struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy);
void cpufreq_enable_fast_switch(struct cpufreq_policy *policy); void cpufreq_enable_fast_switch(struct cpufreq_policy *policy);
void cpufreq_disable_fast_switch(struct cpufreq_policy *policy); void cpufreq_disable_fast_switch(struct cpufreq_policy *policy);
...@@ -237,6 +238,10 @@ static inline unsigned int cpufreq_get_hw_max_freq(unsigned int cpu) ...@@ -237,6 +238,10 @@ static inline unsigned int cpufreq_get_hw_max_freq(unsigned int cpu)
{ {
return 0; return 0;
} }
static inline bool cpufreq_supports_freq_invariance(void)
{
return false;
}
static inline void disable_cpufreq(void) { } static inline void disable_cpufreq(void) { }
#endif #endif
...@@ -1006,8 +1011,14 @@ static inline void sched_cpufreq_governor_change(struct cpufreq_policy *policy, ...@@ -1006,8 +1011,14 @@ static inline void sched_cpufreq_governor_change(struct cpufreq_policy *policy,
extern void arch_freq_prepare_all(void); extern void arch_freq_prepare_all(void);
extern unsigned int arch_freq_get_on_cpu(int cpu); extern unsigned int arch_freq_get_on_cpu(int cpu);
extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, #ifndef arch_set_freq_scale
unsigned long max_freq); static __always_inline
void arch_set_freq_scale(const struct cpumask *cpus,
unsigned long cur_freq,
unsigned long max_freq)
{
}
#endif
/* the following are really really optional */ /* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
......
...@@ -114,22 +114,8 @@ static bool sugov_update_next_freq(struct sugov_policy *sg_policy, u64 time, ...@@ -114,22 +114,8 @@ static bool sugov_update_next_freq(struct sugov_policy *sg_policy, u64 time,
static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time, static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time,
unsigned int next_freq) unsigned int next_freq)
{ {
struct cpufreq_policy *policy = sg_policy->policy; if (sugov_update_next_freq(sg_policy, time, next_freq))
int cpu; cpufreq_driver_fast_switch(sg_policy->policy, next_freq);
if (!sugov_update_next_freq(sg_policy, time, next_freq))
return;
next_freq = cpufreq_driver_fast_switch(policy, next_freq);
if (!next_freq)
return;
policy->cur = next_freq;
if (trace_cpu_frequency_enabled()) {
for_each_cpu(cpu, policy->cpus)
trace_cpu_frequency(next_freq, cpu);
}
} }
static void sugov_deferred_update(struct sugov_policy *sg_policy, u64 time, static void sugov_deferred_update(struct sugov_policy *sg_policy, u64 time,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment