Merge branch 'pm-cpufreq'
* pm-cpufreq: intel_pstate: fix PCT_TO_HWP macro intel_pstate: Fix user input of min/max to legal policy region cpufreq-dt: add suspend frequency support cpufreq: allow cpufreq_generic_suspend() to work without suspend frequency cpufreq: Use __func__ to print function's name cpufreq: staticize cpufreq_cpu_get_raw() cpufreq: Add ARM_MT8173_CPUFREQ dependency on THERMAL cpufreq: dt: Tolerance applies on both sides of target voltage cpufreq: dt: Print error on failing to mark OPPs as shared cpufreq: dt: Check OPP count before marking them shared
This commit is contained in:
commit
3e66c4b860
|
@ -133,6 +133,7 @@ config ARM_KIRKWOOD_CPUFREQ
|
|||
config ARM_MT8173_CPUFREQ
|
||||
bool "Mediatek MT8173 CPUFreq support"
|
||||
depends on ARCH_MEDIATEK && REGULATOR
|
||||
depends on !CPU_THERMAL || THERMAL=y
|
||||
select PM_OPP
|
||||
help
|
||||
This adds the CPUFreq driver support for Mediatek MT8173 SoC.
|
||||
|
|
|
@ -196,6 +196,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|||
struct device *cpu_dev;
|
||||
struct regulator *cpu_reg;
|
||||
struct clk *cpu_clk;
|
||||
struct dev_pm_opp *suspend_opp;
|
||||
unsigned long min_uV = ~0, max_uV = 0;
|
||||
unsigned int transition_latency;
|
||||
bool need_update = false;
|
||||
|
@ -239,6 +240,17 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|||
*/
|
||||
of_cpumask_init_opp_table(policy->cpus);
|
||||
|
||||
/*
|
||||
* But we need OPP table to function so if it is not there let's
|
||||
* give platform code chance to provide it for us.
|
||||
*/
|
||||
ret = dev_pm_opp_get_opp_count(cpu_dev);
|
||||
if (ret <= 0) {
|
||||
pr_debug("OPP table is not ready, deferring probe\n");
|
||||
ret = -EPROBE_DEFER;
|
||||
goto out_free_opp;
|
||||
}
|
||||
|
||||
if (need_update) {
|
||||
struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data();
|
||||
|
||||
|
@ -249,24 +261,16 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|||
* OPP tables are initialized only for policy->cpu, do it for
|
||||
* others as well.
|
||||
*/
|
||||
set_cpus_sharing_opps(cpu_dev, policy->cpus);
|
||||
ret = set_cpus_sharing_opps(cpu_dev, policy->cpus);
|
||||
if (ret)
|
||||
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
|
||||
__func__, ret);
|
||||
|
||||
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
|
||||
* give platform code chance to provide it for us.
|
||||
*/
|
||||
ret = dev_pm_opp_get_opp_count(cpu_dev);
|
||||
if (ret <= 0) {
|
||||
pr_debug("OPP table is not ready, deferring probe\n");
|
||||
ret = -EPROBE_DEFER;
|
||||
goto out_free_opp;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -300,7 +304,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|||
rcu_read_unlock();
|
||||
|
||||
tol_uV = opp_uV * priv->voltage_tolerance / 100;
|
||||
if (regulator_is_supported_voltage(cpu_reg, opp_uV,
|
||||
if (regulator_is_supported_voltage(cpu_reg,
|
||||
opp_uV - tol_uV,
|
||||
opp_uV + tol_uV)) {
|
||||
if (opp_uV < min_uV)
|
||||
min_uV = opp_uV;
|
||||
|
@ -329,6 +334,13 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|||
policy->driver_data = priv;
|
||||
|
||||
policy->clk = cpu_clk;
|
||||
|
||||
rcu_read_lock();
|
||||
suspend_opp = dev_pm_opp_get_suspend_opp(cpu_dev);
|
||||
if (suspend_opp)
|
||||
policy->suspend_freq = dev_pm_opp_get_freq(suspend_opp) / 1000;
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = cpufreq_table_validate_and_show(policy, freq_table);
|
||||
if (ret) {
|
||||
dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__,
|
||||
|
@ -419,6 +431,7 @@ static struct cpufreq_driver dt_cpufreq_driver = {
|
|||
.ready = cpufreq_ready,
|
||||
.name = "cpufreq-dt",
|
||||
.attr = cpufreq_dt_attr,
|
||||
.suspend = cpufreq_generic_suspend,
|
||||
};
|
||||
|
||||
static int dt_cpufreq_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -239,7 +239,7 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
|
|||
EXPORT_SYMBOL_GPL(cpufreq_generic_init);
|
||||
|
||||
/* Only for cpufreq core internal use */
|
||||
struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
|
||||
static struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
|
||||
|
@ -1626,8 +1626,8 @@ int cpufreq_generic_suspend(struct cpufreq_policy *policy)
|
|||
int ret;
|
||||
|
||||
if (!policy->suspend_freq) {
|
||||
pr_err("%s: suspend_freq can't be zero\n", __func__);
|
||||
return -EINVAL;
|
||||
pr_debug("%s: suspend_freq not defined\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_debug("%s: Setting suspend-freq: %u\n", __func__,
|
||||
|
@ -2031,8 +2031,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
|||
if (!try_module_get(policy->governor->owner))
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("__cpufreq_governor for CPU %u, event %u\n",
|
||||
policy->cpu, event);
|
||||
pr_debug("%s: for CPU %u, event %u\n", __func__, policy->cpu, event);
|
||||
|
||||
mutex_lock(&cpufreq_governor_lock);
|
||||
if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
|
||||
|
|
|
@ -260,24 +260,31 @@ static inline void update_turbo_state(void)
|
|||
cpu->pstate.max_pstate == cpu->pstate.turbo_pstate);
|
||||
}
|
||||
|
||||
#define PCT_TO_HWP(x) (x * 255 / 100)
|
||||
static void intel_pstate_hwp_set(void)
|
||||
{
|
||||
int min, max, cpu;
|
||||
u64 value, freq;
|
||||
int min, hw_min, max, hw_max, cpu, range, adj_range;
|
||||
u64 value, cap;
|
||||
|
||||
rdmsrl(MSR_HWP_CAPABILITIES, cap);
|
||||
hw_min = HWP_LOWEST_PERF(cap);
|
||||
hw_max = HWP_HIGHEST_PERF(cap);
|
||||
range = hw_max - hw_min;
|
||||
|
||||
get_online_cpus();
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
|
||||
min = PCT_TO_HWP(limits.min_perf_pct);
|
||||
adj_range = limits.min_perf_pct * range / 100;
|
||||
min = hw_min + adj_range;
|
||||
value &= ~HWP_MIN_PERF(~0L);
|
||||
value |= HWP_MIN_PERF(min);
|
||||
|
||||
max = PCT_TO_HWP(limits.max_perf_pct);
|
||||
adj_range = limits.max_perf_pct * range / 100;
|
||||
max = hw_min + adj_range;
|
||||
if (limits.no_turbo) {
|
||||
rdmsrl( MSR_HWP_CAPABILITIES, freq);
|
||||
max = HWP_GUARANTEED_PERF(freq);
|
||||
hw_max = HWP_GUARANTEED_PERF(cap);
|
||||
if (hw_max < max)
|
||||
max = hw_max;
|
||||
}
|
||||
|
||||
value &= ~HWP_MAX_PERF(~0L);
|
||||
|
@ -423,6 +430,8 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
|
|||
|
||||
limits.max_sysfs_pct = clamp_t(int, input, 0 , 100);
|
||||
limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
|
||||
limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct);
|
||||
limits.max_perf_pct = max(limits.min_perf_pct, limits.max_perf_pct);
|
||||
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
|
||||
|
||||
if (hwp_active)
|
||||
|
@ -442,6 +451,8 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
|
|||
|
||||
limits.min_sysfs_pct = clamp_t(int, input, 0 , 100);
|
||||
limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
|
||||
limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct);
|
||||
limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct);
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
|
||||
if (hwp_active)
|
||||
|
@ -989,12 +1000,19 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
|
|||
|
||||
limits.min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||
limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100);
|
||||
limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
|
||||
limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
|
||||
limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100);
|
||||
|
||||
/* Normalize user input to [min_policy_pct, max_policy_pct] */
|
||||
limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
|
||||
limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct);
|
||||
limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
|
||||
limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct);
|
||||
|
||||
/* Make sure min_perf_pct <= max_perf_pct */
|
||||
limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct);
|
||||
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
|
||||
|
||||
if (hwp_active)
|
||||
|
|
Loading…
Reference in New Issue