2019-05-27 09:55:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
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 >
*/
# 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 " ) ;
2019-04-01 04:37:54 +03:00
of_node_put ( cpu ) ;
2007-07-20 23:39:23 +04:00
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
2018-02-26 08:08:59 +03:00
policy - > freq_table = cbe_freqs ;
2019-07-05 13:19:48 +03:00
cbe_cpufreq_pmi_policy_init ( policy ) ;
return 0 ;
}
static int cbe_cpufreq_cpu_exit ( struct cpufreq_policy * policy )
{
cbe_cpufreq_pmi_policy_exit ( policy ) ;
2018-02-26 08:08:59 +03:00
return 0 ;
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 ,
2019-07-05 13:19:48 +03:00
. exit = cbe_cpufreq_cpu_exit ,
2006-10-24 20:39:45 +04:00
. name = " cbe-cpufreq " ,
. flags = CPUFREQ_CONST_LOOPS ,
} ;
/*
* module init and destoy
*/
static int __init cbe_cpufreq_init ( void )
{
2019-07-05 13:19:48 +03:00
int ret ;
2007-04-28 06:49:03 +04:00
if ( ! machine_is ( cell ) )
return - ENODEV ;
2007-04-23 23:35:42 +04:00
2019-07-05 13:19:48 +03:00
cbe_cpufreq_pmi_init ( ) ;
ret = cpufreq_register_driver ( & cbe_cpufreq_driver ) ;
if ( ret )
cbe_cpufreq_pmi_exit ( ) ;
return ret ;
2006-10-24 20:39:45 +04:00
}
static void __exit cbe_cpufreq_exit ( void )
{
cpufreq_unregister_driver ( & cbe_cpufreq_driver ) ;
2019-07-05 13:19:48 +03:00
cbe_cpufreq_pmi_exit ( ) ;
2006-10-24 20:39:45 +04:00
}
module_init ( cbe_cpufreq_init ) ;
module_exit ( cbe_cpufreq_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Christian Krafft <krafft@de.ibm.com> " ) ;