mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-19 00:54:41 +08:00
7f4b04614a
Currently cpufreq frequency table has two fields: frequency and driver_data. driver_data is only for drivers' internal use and cpufreq core shouldn't use it at all. But with the introduction of BOOST frequencies, this assumption was broken and we started using it as a flag instead. There are two problems due to this: - It is against the description of this field, as driver's data is used by the core now. - if drivers fill it with -3 for any frequency, then those frequencies are never considered by cpufreq core as it is exactly same as value of CPUFREQ_BOOST_FREQ, i.e. ~2. The best way to get this fixed is by creating another field flags which will be used for such flags. This patch does that. Along with that various drivers need modifications due to the change of struct cpufreq_frequency_table. Reviewed-by: Gautham R Shenoy <ego@linux.vnet.ibm.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
170 lines
4.0 KiB
C
170 lines
4.0 KiB
C
/*
|
|
* cpufreq driver for the cell processor
|
|
*
|
|
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
|
|
*
|
|
* Author: Christian Krafft <krafft@de.ibm.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of_platform.h>
|
|
|
|
#include <asm/machdep.h>
|
|
#include <asm/prom.h>
|
|
#include <asm/cell-regs.h>
|
|
|
|
#include "ppc_cbe_cpufreq.h"
|
|
|
|
/* the CBE supports an 8 step frequency scaling */
|
|
static struct cpufreq_frequency_table cbe_freqs[] = {
|
|
{0, 1, 0},
|
|
{0, 2, 0},
|
|
{0, 3, 0},
|
|
{0, 4, 0},
|
|
{0, 5, 0},
|
|
{0, 6, 0},
|
|
{0, 8, 0},
|
|
{0, 10, 0},
|
|
{0, 0, CPUFREQ_TABLE_END},
|
|
};
|
|
|
|
/*
|
|
* hardware specific functions
|
|
*/
|
|
|
|
static int set_pmode(unsigned int cpu, unsigned int slow_mode)
|
|
{
|
|
int rc;
|
|
|
|
if (cbe_cpufreq_has_pmi)
|
|
rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
|
|
else
|
|
rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
|
|
|
|
pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* cpufreq functions
|
|
*/
|
|
|
|
static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|
{
|
|
const u32 *max_freqp;
|
|
u32 max_freq;
|
|
int i, cur_pmode;
|
|
struct device_node *cpu;
|
|
|
|
cpu = of_get_cpu_node(policy->cpu, NULL);
|
|
|
|
if (!cpu)
|
|
return -ENODEV;
|
|
|
|
pr_debug("init cpufreq on CPU %d\n", policy->cpu);
|
|
|
|
/*
|
|
* Let's check we can actually get to the CELL regs
|
|
*/
|
|
if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
|
|
!cbe_get_cpu_mic_tm_regs(policy->cpu)) {
|
|
pr_info("invalid CBE regs pointers for cpufreq\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
max_freqp = of_get_property(cpu, "clock-frequency", NULL);
|
|
|
|
of_node_put(cpu);
|
|
|
|
if (!max_freqp)
|
|
return -EINVAL;
|
|
|
|
/* we need the freq in kHz */
|
|
max_freq = *max_freqp / 1000;
|
|
|
|
pr_debug("max clock-frequency is at %u kHz\n", max_freq);
|
|
pr_debug("initializing frequency table\n");
|
|
|
|
/* initialize frequency table */
|
|
for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
|
|
cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
|
|
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
|
|
}
|
|
|
|
/* if DEBUG is enabled set_pmode() measures the latency
|
|
* of a transition */
|
|
policy->cpuinfo.transition_latency = 25000;
|
|
|
|
cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
|
|
pr_debug("current pmode is at %d\n",cur_pmode);
|
|
|
|
policy->cur = cbe_freqs[cur_pmode].frequency;
|
|
|
|
#ifdef CONFIG_SMP
|
|
cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
|
|
#endif
|
|
|
|
/* this ensures that policy->cpuinfo_min
|
|
* and policy->cpuinfo_max are set correctly */
|
|
return cpufreq_table_validate_and_show(policy, cbe_freqs);
|
|
}
|
|
|
|
static int cbe_cpufreq_target(struct cpufreq_policy *policy,
|
|
unsigned int cbe_pmode_new)
|
|
{
|
|
pr_debug("setting frequency for cpu %d to %d kHz, " \
|
|
"1/%d of max frequency\n",
|
|
policy->cpu,
|
|
cbe_freqs[cbe_pmode_new].frequency,
|
|
cbe_freqs[cbe_pmode_new].driver_data);
|
|
|
|
return set_pmode(policy->cpu, cbe_pmode_new);
|
|
}
|
|
|
|
static struct cpufreq_driver cbe_cpufreq_driver = {
|
|
.verify = cpufreq_generic_frequency_table_verify,
|
|
.target_index = cbe_cpufreq_target,
|
|
.init = cbe_cpufreq_cpu_init,
|
|
.name = "cbe-cpufreq",
|
|
.flags = CPUFREQ_CONST_LOOPS,
|
|
};
|
|
|
|
/*
|
|
* module init and destoy
|
|
*/
|
|
|
|
static int __init cbe_cpufreq_init(void)
|
|
{
|
|
if (!machine_is(cell))
|
|
return -ENODEV;
|
|
|
|
return cpufreq_register_driver(&cbe_cpufreq_driver);
|
|
}
|
|
|
|
static void __exit cbe_cpufreq_exit(void)
|
|
{
|
|
cpufreq_unregister_driver(&cbe_cpufreq_driver);
|
|
}
|
|
|
|
module_init(cbe_cpufreq_init);
|
|
module_exit(cbe_cpufreq_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
|