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
/* the CBE supports an 8 step frequency scaling */
static struct cpufreq_frequency_table cbe_freqs [ ] = {
2014-03-28 17:41:47 +04:00
{ 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 } ,
2006-10-24 20:39:45 +04:00
} ;
/*
* 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
{
2014-04-26 00:15:38 +04:00
struct cpufreq_frequency_table * pos ;
2007-04-03 16:50:59 +04:00
const u32 * max_freqp ;
u32 max_freq ;
2014-04-26 00:15:38 +04:00
int cur_pmode ;
2006-10-24 20:39:45 +04:00
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 */
2014-04-26 00:15:38 +04:00
cpufreq_for_each_entry ( pos , cbe_freqs ) {
pos - > frequency = max_freq / pos - > driver_data ;
pr_debug ( " %d: %d \n " , ( int ) ( pos - cbe_freqs ) , pos - > frequency ) ;
2006-10-24 20:39:45 +04:00
}
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-07-20 23:39:21 +04:00
/* this ensures that policy->cpuinfo_min
* and policy - > cpuinfo_max are set correctly */
2013-09-16 17:26:28 +04:00
return cpufreq_table_validate_and_show ( policy , cbe_freqs ) ;
2006-10-24 20:39:45 +04:00
}
2007-07-20 23:39:21 +04:00
static int cbe_cpufreq_target ( struct cpufreq_policy * policy ,
2013-10-25 18:15:48 +04:00
unsigned int cbe_pmode_new )
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
2013-08-14 18:08:24 +04:00
return set_pmode ( policy - > cpu , cbe_pmode_new ) ;
2006-10-24 20:39:45 +04:00
}
static struct cpufreq_driver cbe_cpufreq_driver = {
2013-10-03 18:58:19 +04:00
. verify = cpufreq_generic_frequency_table_verify ,
2013-10-25 18:15:48 +04:00
. target_index = cbe_cpufreq_target ,
2006-10-24 20:39:45 +04:00
. init = cbe_cpufreq_cpu_init ,
. 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> " ) ;