2006-10-24 20:39:45 +04:00
/*
* cpufreq driver for the cell processor
*
2007-07-20 23:39:22 +04:00
* ( C ) Copyright IBM Deutschland Entwicklung GmbH 2005 - 2007
2006-10-24 20:39:45 +04:00
*
* 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 0213 9 , USA .
*/
# include <linux/cpufreq.h>
2011-05-27 21:23:32 +04:00
# include <linux/module.h>
2007-11-13 20:10:58 +03:00
# include <linux/of_platform.h>
2007-04-28 06:49:03 +04:00
# include <asm/machdep.h>
2007-07-20 23:39:22 +04:00
# include <asm/prom.h>
2007-10-04 09:40:42 +04:00
# include <asm/cell-regs.h>
2013-03-25 09:50:23 +04:00
# include "ppc_cbe_cpufreq.h"
2006-10-24 20:39:45 +04:00
static DEFINE_MUTEX ( cbe_switch_mutex ) ;
/* the CBE supports an 8 step frequency scaling */
static struct cpufreq_frequency_table cbe_freqs [ ] = {
{ 1 , 0 } ,
{ 2 , 0 } ,
{ 3 , 0 } ,
{ 4 , 0 } ,
{ 5 , 0 } ,
{ 6 , 0 } ,
{ 8 , 0 } ,
{ 10 , 0 } ,
{ 0 , CPUFREQ_TABLE_END } ,
} ;
/*
* hardware specific functions
*/
2007-07-20 23:39:22 +04:00
static int set_pmode ( unsigned int cpu , unsigned int slow_mode )
2007-07-20 23:39:18 +04:00
{
2007-07-20 23:39:21 +04:00
int rc ;
2007-07-20 23:39:22 +04:00
2007-07-20 23:39:18 +04:00
if ( cbe_cpufreq_has_pmi )
2007-07-20 23:39:22 +04:00
rc = cbe_cpufreq_set_pmode_pmi ( cpu , slow_mode ) ;
2007-07-20 23:39:21 +04:00
else
2007-07-20 23:39:22 +04:00
rc = cbe_cpufreq_set_pmode ( cpu , slow_mode ) ;
2007-07-20 23:39:21 +04:00
2007-07-20 23:39:22 +04:00
pr_debug ( " register contains slow mode %d \n " , cbe_cpufreq_get_pmode ( cpu ) ) ;
2007-07-20 23:39:21 +04:00
return rc ;
2007-04-23 23:35:42 +04:00
}
2006-10-24 20:39:45 +04:00
/*
* cpufreq functions
*/
2007-04-28 06:49:03 +04:00
static int cbe_cpufreq_cpu_init ( struct cpufreq_policy * policy )
2006-10-24 20:39:45 +04:00
{
2007-04-03 16:50:59 +04:00
const u32 * max_freqp ;
u32 max_freq ;
2006-10-24 20:39:45 +04:00
int i , cur_pmode ;
struct device_node * cpu ;
cpu = of_get_cpu_node ( policy - > cpu , NULL ) ;
2007-04-28 06:49:03 +04:00
if ( ! cpu )
2006-10-24 20:39:45 +04:00
return - ENODEV ;
pr_debug ( " init cpufreq on CPU %d \n " , policy - > cpu ) ;
2007-07-20 23:39:23 +04:00
/*
* 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 ;
}
2007-04-03 16:50:59 +04:00
max_freqp = of_get_property ( cpu , " clock-frequency " , NULL ) ;
2006-10-24 20:39:45 +04:00
2007-07-20 23:39:21 +04:00
of_node_put ( cpu ) ;
2007-04-03 16:50:59 +04:00
if ( ! max_freqp )
2006-10-24 20:39:45 +04:00
return - EINVAL ;
2007-04-28 06:49:03 +04:00
/* we need the freq in kHz */
2007-04-03 16:50:59 +04:00
max_freq = * max_freqp / 1000 ;
2006-10-24 20:39:45 +04:00
2007-04-03 16:50:59 +04:00
pr_debug ( " max clock-frequency is at %u kHz \n " , max_freq ) ;
2006-10-24 20:39:45 +04:00
pr_debug ( " initializing frequency table \n " ) ;
2007-04-28 06:49:03 +04:00
/* initialize frequency table */
2006-10-24 20:39:45 +04:00
for ( i = 0 ; cbe_freqs [ i ] . frequency ! = CPUFREQ_TABLE_END ; i + + ) {
2013-03-30 14:55:15 +04:00
cbe_freqs [ i ] . frequency = max_freq / cbe_freqs [ i ] . driver_data ;
2006-10-24 20:39:45 +04:00
pr_debug ( " %d: %d \n " , i , cbe_freqs [ i ] . frequency ) ;
}
2007-07-20 23:39:21 +04:00
/* if DEBUG is enabled set_pmode() measures the latency
* of a transition */
2006-10-24 20:39:45 +04:00
policy - > cpuinfo . transition_latency = 25000 ;
2007-07-20 23:39:22 +04:00
cur_pmode = cbe_cpufreq_get_pmode ( policy - > cpu ) ;
2006-10-24 20:39:45 +04:00
pr_debug ( " current pmode is at %d \n " , cur_pmode ) ;
policy - > cur = cbe_freqs [ cur_pmode ] . frequency ;
# ifdef CONFIG_SMP
2010-04-26 19:32:41 +04:00
cpumask_copy ( policy - > cpus , cpu_sibling_mask ( policy - > cpu ) ) ;
2006-10-24 20:39:45 +04:00
# endif
2007-04-28 06:49:03 +04:00
cpufreq_frequency_table_get_attr ( cbe_freqs , policy - > cpu ) ;
2006-10-24 20:39:45 +04:00
2007-07-20 23:39:21 +04:00
/* this ensures that policy->cpuinfo_min
* and policy - > cpuinfo_max are set correctly */
2007-04-28 06:49:03 +04:00
return cpufreq_frequency_table_cpuinfo ( policy , cbe_freqs ) ;
2006-10-24 20:39:45 +04:00
}
static int cbe_cpufreq_cpu_exit ( struct cpufreq_policy * policy )
{
cpufreq_frequency_table_put_attr ( policy - > cpu ) ;
return 0 ;
}
static int cbe_cpufreq_verify ( struct cpufreq_policy * policy )
{
return cpufreq_frequency_table_verify ( policy , cbe_freqs ) ;
}
2007-07-20 23:39:21 +04:00
static int cbe_cpufreq_target ( struct cpufreq_policy * policy ,
unsigned int target_freq ,
unsigned int relation )
2006-10-24 20:39:45 +04:00
{
int rc ;
struct cpufreq_freqs freqs ;
2007-07-20 23:39:21 +04:00
unsigned int cbe_pmode_new ;
2006-10-24 20:39:45 +04:00
cpufreq_frequency_table_target ( policy ,
cbe_freqs ,
target_freq ,
relation ,
& cbe_pmode_new ) ;
freqs . old = policy - > cur ;
freqs . new = cbe_freqs [ cbe_pmode_new ] . frequency ;
2007-04-28 06:49:03 +04:00
mutex_lock ( & cbe_switch_mutex ) ;
2013-03-24 10:26:43 +04:00
cpufreq_notify_transition ( policy , & freqs , CPUFREQ_PRECHANGE ) ;
2006-10-24 20:39:45 +04:00
2007-07-20 23:39:21 +04:00
pr_debug ( " setting frequency for cpu %d to %d kHz, " \
" 1/%d of max frequency \n " ,
2006-10-24 20:39:45 +04:00
policy - > cpu ,
cbe_freqs [ cbe_pmode_new ] . frequency ,
2013-03-30 14:55:15 +04:00
cbe_freqs [ cbe_pmode_new ] . driver_data ) ;
2006-10-24 20:39:45 +04:00
rc = set_pmode ( policy - > cpu , cbe_pmode_new ) ;
2007-07-20 23:39:21 +04:00
2013-03-24 10:26:43 +04:00
cpufreq_notify_transition ( policy , & freqs , CPUFREQ_POSTCHANGE ) ;
2006-10-24 20:39:45 +04:00
mutex_unlock ( & cbe_switch_mutex ) ;
return rc ;
}
static struct cpufreq_driver cbe_cpufreq_driver = {
. verify = cbe_cpufreq_verify ,
. target = cbe_cpufreq_target ,
. init = cbe_cpufreq_cpu_init ,
. exit = cbe_cpufreq_cpu_exit ,
. name = " cbe-cpufreq " ,
. flags = CPUFREQ_CONST_LOOPS ,
} ;
/*
* module init and destoy
*/
static int __init cbe_cpufreq_init ( void )
{
2007-04-28 06:49:03 +04:00
if ( ! machine_is ( cell ) )
return - ENODEV ;
2007-04-23 23:35:42 +04:00
2006-10-24 20:39:45 +04:00
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> " ) ;