#include <soc/samsung/exynos-dm.h>
#include <soc/samsung/ect_parser.h>
#include <soc/samsung/exynos-cpu_hotplug.h>
+#include <soc/samsung/exynos-cpupm.h>
#include "exynos-acme.h"
/*********************************************************************
* FREQUENCY SCALING *
*********************************************************************/
+/*
+ * Depending on cluster structure, it cannot be possible to get/set
+ * cpu frequency while cluster is off. For this, disable cluster-wide
+ * power mode while getting/setting frequency.
+ */
static unsigned int get_freq(struct exynos_cpufreq_domain *domain)
{
- unsigned int freq = (unsigned int)cal_dfs_get_rate(domain->cal_id);
+ unsigned int freq;
+
+ disable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
- /* On changing state, CAL returns 0 */
- if (!freq)
- return domain->old;
+ freq = (unsigned int)cal_dfs_get_rate(domain->cal_id);
+ if (!freq) {
+ /* On changing state, CAL returns 0 */
+ freq = domain->old;
+ }
+
+ enable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
return freq;
}
{
int err;
+ disable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
+
exynos_ss_printk("ID %d: %d -> %d (%d)\n",
domain->id, domain->old, target_freq, ESS_FLAG_IN);
exynos_ss_printk("ID %d: %d -> %d (%d)\n",
domain->id, domain->old, target_freq, ESS_FLAG_OUT);
+ enable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
+
return err;
}
struct cpumask mask;
cpumask_and(&mask, cpus, cpu_online_mask);
- smp_call_function_many(&mask, do_nothing, NULL, 0);
+ smp_call_function_single(cpumask_any(&mask), do_nothing, NULL, 1);
}
/*
struct power_mode *mode;
int pos;
- spin_lock(&cpupm_lock);
pm = &per_cpu(cpupm, cpu);
for_each_mode(mode, pm->modes, pos) {
if (IS_NULL(mode))
break;
+ /*
+ * There are no entry allowed cpus, it means that mode is
+ * disabled, skip awaking cpus.
+ */
+ if (cpumask_empty(&mode->entry_allowed))
+ continue;
+
if (mode->type == type) {
/*
* The first mode disable request wakes the cpus to
awake_cpus(&mode->siblings);
}
}
- spin_unlock(&cpupm_lock);
}
void enable_power_mode(int cpu, int type)
struct power_mode *mode;
int pos;
- spin_lock(&cpupm_lock);
pm = &per_cpu(cpupm, cpu);
for_each_mode(mode, pm->modes, pos) {
if (mode->type == type)
atomic_dec(&mode->disable);
}
- spin_unlock(&cpupm_lock);
}
/* get sleep length of given cpu from tickless framework */
POWERMODE_TYPE_SYSTEM,
};
-extern void disable_mode(int cpu, int type);
-extern void enable_mode(int cpu, int type);
+extern void disable_power_mode(int cpu, int type);
+extern void enable_power_mode(int cpu, int type);
#ifdef CONFIG_CPU_IDLE
void exynos_update_ip_idle_status(int index, int idle);