2019-05-27 09:55:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-07-20 23:39:22 +04:00
/*
* pmi backend for the cbe_cpufreq driver
*
* ( C ) Copyright IBM Deutschland Entwicklung GmbH 2005 - 2007
*
* Author : Christian Krafft < krafft @ de . ibm . com >
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/timer.h>
2016-03-28 01:08:17 +03:00
# include <linux/init.h>
2007-11-13 20:10:58 +03:00
# include <linux/of_platform.h>
2007-07-20 23:39:22 +04:00
# include <asm/processor.h>
# include <asm/prom.h>
# include <asm/pmi.h>
2007-10-04 09:40:42 +04:00
# include <asm/cell-regs.h>
2007-07-20 23:39:22 +04:00
# ifdef DEBUG
# include <asm/time.h>
# endif
2013-03-25 09:50:23 +04:00
# include "ppc_cbe_cpufreq.h"
2007-07-20 23:39:22 +04:00
static u8 pmi_slow_mode_limit [ MAX_CBE ] ;
bool cbe_cpufreq_has_pmi = false ;
EXPORT_SYMBOL_GPL ( cbe_cpufreq_has_pmi ) ;
/*
* hardware specific functions
*/
int cbe_cpufreq_set_pmode_pmi ( int cpu , unsigned int pmode )
{
int ret ;
pmi_message_t pmi_msg ;
# ifdef DEBUG
long time ;
# endif
pmi_msg . type = PMI_TYPE_FREQ_CHANGE ;
pmi_msg . data1 = cbe_cpu_to_node ( cpu ) ;
pmi_msg . data2 = pmode ;
# ifdef DEBUG
time = jiffies ;
# endif
pmi_send_message ( pmi_msg ) ;
# ifdef DEBUG
time = jiffies - time ;
time = jiffies_to_msecs ( time ) ;
pr_debug ( " had to wait %lu ms for a transition using " \
" PMI \n " , time ) ;
# endif
ret = pmi_msg . data2 ;
pr_debug ( " PMI returned slow mode %d \n " , ret ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( cbe_cpufreq_set_pmode_pmi ) ;
static void cbe_cpufreq_handle_pmi ( pmi_message_t pmi_msg )
{
u8 node , slow_mode ;
BUG_ON ( pmi_msg . type ! = PMI_TYPE_FREQ_CHANGE ) ;
node = pmi_msg . data1 ;
slow_mode = pmi_msg . data2 ;
pmi_slow_mode_limit [ node ] = slow_mode ;
pr_debug ( " cbe_handle_pmi: node: %d max_freq: %d \n " , node , slow_mode ) ;
}
static int pmi_notifier ( struct notifier_block * nb ,
unsigned long event , void * data )
{
struct cpufreq_policy * policy = data ;
2016-06-03 08:28:47 +03:00
struct cpufreq_frequency_table * cbe_freqs = policy - > freq_table ;
2007-07-20 23:39:22 +04:00
u8 node ;
2015-08-03 06:06:14 +03:00
/* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY
* policy events ? )
2008-07-30 09:32:58 +04:00
*/
2007-07-20 23:39:22 +04:00
node = cbe_cpu_to_node ( policy - > cpu ) ;
pr_debug ( " got notified, event=%lu, node=%u \n " , event , node ) ;
if ( pmi_slow_mode_limit [ node ] ! = 0 ) {
pr_debug ( " limiting node %d to slow mode %d \n " ,
node , pmi_slow_mode_limit [ node ] ) ;
cpufreq_verify_within_limits ( policy , 0 ,
cbe_freqs [ pmi_slow_mode_limit [ node ] ] . frequency ) ;
}
return 0 ;
}
static struct notifier_block pmi_notifier_block = {
. notifier_call = pmi_notifier ,
} ;
static struct pmi_handler cbe_pmi_handler = {
. type = PMI_TYPE_FREQ_CHANGE ,
. handle_pmi_message = cbe_cpufreq_handle_pmi ,
} ;
static int __init cbe_cpufreq_pmi_init ( void )
{
cbe_cpufreq_has_pmi = pmi_register_handler ( & cbe_pmi_handler ) = = 0 ;
if ( ! cbe_cpufreq_has_pmi )
return - ENODEV ;
cpufreq_register_notifier ( & pmi_notifier_block , CPUFREQ_POLICY_NOTIFIER ) ;
return 0 ;
}
2016-03-28 01:08:17 +03:00
device_initcall ( cbe_cpufreq_pmi_init ) ;