2005-09-26 10:04:21 +04:00
/*
* Copyright ( C ) 2002 - 2005 Benjamin Herrenschmidt < benh @ kernel . crashing . org >
* Copyright ( C ) 2004 John Steele Scott < toojays @ toojays . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* TODO : Need a big cleanup here . Basically , we need to have different
* cpufreq_driver structures for the different type of HW instead of the
* current mess . We also need to better deal with the detection of the
* type of machine .
*
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/sched.h>
# include <linux/adb.h>
# include <linux/pmu.h>
# include <linux/cpufreq.h>
# include <linux/init.h>
2011-12-22 04:26:03 +04:00
# include <linux/device.h>
2005-09-26 10:04:21 +04:00
# include <linux/hardirq.h>
2013-07-17 16:52:17 +04:00
# include <linux/of_device.h>
2005-09-26 10:04:21 +04:00
# include <asm/prom.h>
# include <asm/machdep.h>
# include <asm/irq.h>
# include <asm/pmac_feature.h>
# include <asm/mmu_context.h>
# include <asm/sections.h>
# include <asm/cputable.h>
# include <asm/time.h>
# include <asm/mpic.h>
# include <asm/keylargo.h>
2012-03-28 21:30:02 +04:00
# include <asm/switch_to.h>
2005-09-26 10:04:21 +04:00
/* WARNING !!! This will cause calibrate_delay() to be called,
* but this is an __init function ! So you MUST go edit
* init / main . c to make it non - init before enabling DEBUG_FREQ
*/
# undef DEBUG_FREQ
extern void low_choose_7447a_dfs ( int dfs ) ;
extern void low_choose_750fx_pll ( int pll ) ;
extern void low_sleep_handler ( void ) ;
/*
* Currently , PowerMac cpufreq supports only high & low frequencies
* that are set by the firmware
*/
static unsigned int low_freq ;
static unsigned int hi_freq ;
static unsigned int cur_freq ;
static unsigned int sleep_freq ;
2012-10-29 03:15:14 +04:00
static unsigned long transition_latency ;
2005-09-26 10:04:21 +04:00
/*
2006-06-30 20:20:44 +04:00
* Different models uses different mechanisms to switch the frequency
2005-09-26 10:04:21 +04:00
*/
static int ( * set_speed_proc ) ( int low_speed ) ;
static unsigned int ( * get_speed_proc ) ( void ) ;
/*
* Some definitions used by the various speedprocs
*/
static u32 voltage_gpio ;
static u32 frequency_gpio ;
static u32 slew_done_gpio ;
static int no_schedule ;
static int has_cpu_l2lve ;
static int is_pmu_based ;
/* There are only two frequency states for each processor. Values
* are in kHz for the time being .
*/
# define CPUFREQ_HIGH 0
# define CPUFREQ_LOW 1
static struct cpufreq_frequency_table pmac_cpu_freqs [ ] = {
{ CPUFREQ_HIGH , 0 } ,
{ CPUFREQ_LOW , 0 } ,
{ 0 , CPUFREQ_TABLE_END } ,
} ;
static inline void local_delay ( unsigned long ms )
{
if ( no_schedule )
mdelay ( ms ) ;
else
msleep ( ms ) ;
}
# ifdef DEBUG_FREQ
static inline void debug_calc_bogomips ( void )
{
/* This will cause a recalc of bogomips and display the
* result . We backup / restore the value to avoid affecting the
* core cpufreq framework ' s own calculation .
*/
unsigned long save_lpj = loops_per_jiffy ;
calibrate_delay ( ) ;
loops_per_jiffy = save_lpj ;
}
# endif /* DEBUG_FREQ */
/* Switch CPU speed under 750FX CPU control
*/
static int cpu_750fx_cpu_speed ( int low_speed )
{
u32 hid2 ;
if ( low_speed = = 0 ) {
/* ramping up, set voltage first */
pmac_call_feature ( PMAC_FTR_WRITE_GPIO , NULL , voltage_gpio , 0x05 ) ;
/* Make sure we sleep for at least 1ms */
local_delay ( 10 ) ;
/* tweak L2 for high voltage */
if ( has_cpu_l2lve ) {
hid2 = mfspr ( SPRN_HID2 ) ;
hid2 & = ~ 0x2000 ;
mtspr ( SPRN_HID2 , hid2 ) ;
}
}
# ifdef CONFIG_6xx
low_choose_750fx_pll ( low_speed ) ;
# endif
if ( low_speed = = 1 ) {
/* tweak L2 for low voltage */
if ( has_cpu_l2lve ) {
hid2 = mfspr ( SPRN_HID2 ) ;
hid2 | = 0x2000 ;
mtspr ( SPRN_HID2 , hid2 ) ;
}
/* ramping down, set voltage last */
pmac_call_feature ( PMAC_FTR_WRITE_GPIO , NULL , voltage_gpio , 0x04 ) ;
local_delay ( 10 ) ;
}
return 0 ;
}
static unsigned int cpu_750fx_get_cpu_speed ( void )
{
if ( mfspr ( SPRN_HID1 ) & HID1_PS )
return low_freq ;
else
return hi_freq ;
}
/* Switch CPU speed using DFS */
static int dfs_set_cpu_speed ( int low_speed )
{
if ( low_speed = = 0 ) {
/* ramping up, set voltage first */
pmac_call_feature ( PMAC_FTR_WRITE_GPIO , NULL , voltage_gpio , 0x05 ) ;
/* Make sure we sleep for at least 1ms */
local_delay ( 1 ) ;
}
/* set frequency */
# ifdef CONFIG_6xx
low_choose_7447a_dfs ( low_speed ) ;
# endif
udelay ( 100 ) ;
if ( low_speed = = 1 ) {
/* ramping down, set voltage last */
pmac_call_feature ( PMAC_FTR_WRITE_GPIO , NULL , voltage_gpio , 0x04 ) ;
local_delay ( 1 ) ;
}
return 0 ;
}
static unsigned int dfs_get_cpu_speed ( void )
{
if ( mfspr ( SPRN_HID1 ) & HID1_DFS )
return low_freq ;
else
return hi_freq ;
}
/* Switch CPU speed using slewing GPIOs
*/
static int gpios_set_cpu_speed ( int low_speed )
{
int gpio , timeout = 0 ;
/* If ramping up, set voltage first */
if ( low_speed = = 0 ) {
pmac_call_feature ( PMAC_FTR_WRITE_GPIO , NULL , voltage_gpio , 0x05 ) ;
/* Delay is way too big but it's ok, we schedule */
local_delay ( 10 ) ;
}
/* Set frequency */
gpio = pmac_call_feature ( PMAC_FTR_READ_GPIO , NULL , frequency_gpio , 0 ) ;
if ( low_speed = = ( ( gpio & 0x01 ) = = 0 ) )
goto skip ;
pmac_call_feature ( PMAC_FTR_WRITE_GPIO , NULL , frequency_gpio ,
low_speed ? 0x04 : 0x05 ) ;
udelay ( 200 ) ;
do {
if ( + + timeout > 100 )
break ;
local_delay ( 1 ) ;
gpio = pmac_call_feature ( PMAC_FTR_READ_GPIO , NULL , slew_done_gpio , 0 ) ;
} while ( ( gpio & 0x02 ) = = 0 ) ;
skip :
/* If ramping down, set voltage last */
if ( low_speed = = 1 ) {
pmac_call_feature ( PMAC_FTR_WRITE_GPIO , NULL , voltage_gpio , 0x04 ) ;
/* Delay is way too big but it's ok, we schedule */
local_delay ( 10 ) ;
}
# ifdef DEBUG_FREQ
debug_calc_bogomips ( ) ;
# endif
return 0 ;
}
/* Switch CPU speed under PMU control
*/
static int pmu_set_cpu_speed ( int low_speed )
{
struct adb_request req ;
unsigned long save_l2cr ;
unsigned long save_l3cr ;
unsigned int pic_prio ;
unsigned long flags ;
preempt_disable ( ) ;
# ifdef DEBUG_FREQ
printk ( KERN_DEBUG " HID1, before: %x \n " , mfspr ( SPRN_HID1 ) ) ;
# endif
pmu_suspend ( ) ;
/* Disable all interrupt sources on openpic */
pic_prio = mpic_cpu_get_priority ( ) ;
mpic_cpu_set_priority ( 0xf ) ;
/* Make sure the decrementer won't interrupt us */
asm volatile ( " mtdec %0 " : : " r " ( 0x7fffffff ) ) ;
2006-06-30 20:27:16 +04:00
/* Make sure any pending DEC interrupt occurring while we did
2005-09-26 10:04:21 +04:00
* the above didn ' t re - enable the DEC */
mb ( ) ;
asm volatile ( " mtdec %0 " : : " r " ( 0x7fffffff ) ) ;
/* We can now disable MSR_EE */
local_irq_save ( flags ) ;
/* Giveup the FPU & vec */
enable_kernel_fp ( ) ;
# ifdef CONFIG_ALTIVEC
if ( cpu_has_feature ( CPU_FTR_ALTIVEC ) )
enable_kernel_altivec ( ) ;
# endif /* CONFIG_ALTIVEC */
/* Save & disable L2 and L3 caches */
save_l3cr = _get_L3CR ( ) ; /* (returns -1 if not available) */
save_l2cr = _get_L2CR ( ) ; /* (returns -1 if not available) */
/* Send the new speed command. My assumption is that this command
* will cause PLL_CFG [ 0. .3 ] to be changed next time CPU goes to sleep
*/
pmu_request ( & req , NULL , 6 , PMU_CPU_SPEED , ' W ' , ' O ' , ' O ' , ' F ' , low_speed ) ;
while ( ! req . complete )
pmu_poll ( ) ;
/* Prepare the northbridge for the speed transition */
pmac_call_feature ( PMAC_FTR_SLEEP_STATE , NULL , 1 , 1 ) ;
/* Call low level code to backup CPU state and recover from
* hardware reset
*/
low_sleep_handler ( ) ;
/* Restore the northbridge */
pmac_call_feature ( PMAC_FTR_SLEEP_STATE , NULL , 1 , 0 ) ;
/* Restore L2 cache */
if ( save_l2cr ! = 0xffffffff & & ( save_l2cr & L2CR_L2E ) ! = 0 )
_set_L2CR ( save_l2cr ) ;
/* Restore L3 cache */
if ( save_l3cr ! = 0xffffffff & & ( save_l3cr & L3CR_L3E ) ! = 0 )
_set_L3CR ( save_l3cr ) ;
/* Restore userland MMU context */
2008-12-18 22:13:24 +03:00
switch_mmu_context ( NULL , current - > active_mm ) ;
2005-09-26 10:04:21 +04:00
# ifdef DEBUG_FREQ
printk ( KERN_DEBUG " HID1, after: %x \n " , mfspr ( SPRN_HID1 ) ) ;
# endif
/* Restore low level PMU operations */
pmu_unlock ( ) ;
2010-06-20 23:04:14 +04:00
/*
* Restore decrementer ; we ' ll take a decrementer interrupt
* as soon as interrupts are re - enabled and the generic
* clockevents code will reprogram it with the right value .
*/
set_dec ( 1 ) ;
2005-09-26 10:04:21 +04:00
/* Restore interrupts */
mpic_cpu_set_priority ( pic_prio ) ;
/* Let interrupts flow again ... */
local_irq_restore ( flags ) ;
# ifdef DEBUG_FREQ
debug_calc_bogomips ( ) ;
# endif
pmu_resume ( ) ;
preempt_enable ( ) ;
return 0 ;
}
2013-03-24 10:26:43 +04:00
static int do_set_cpu_speed ( struct cpufreq_policy * policy , int speed_mode ,
int notify )
2005-09-26 10:04:21 +04:00
{
struct cpufreq_freqs freqs ;
unsigned long l3cr ;
static unsigned long prev_l3cr ;
freqs . old = cur_freq ;
freqs . new = ( speed_mode = = CPUFREQ_HIGH ) ? hi_freq : low_freq ;
if ( freqs . old = = freqs . new )
return 0 ;
if ( notify )
2013-03-24 10:26:43 +04:00
cpufreq_notify_transition ( policy , & freqs , CPUFREQ_PRECHANGE ) ;
2005-09-26 10:04:21 +04:00
if ( speed_mode = = CPUFREQ_LOW & &
cpu_has_feature ( CPU_FTR_L3CR ) ) {
l3cr = _get_L3CR ( ) ;
if ( l3cr & L3CR_L3E ) {
prev_l3cr = l3cr ;
_set_L3CR ( 0 ) ;
}
}
set_speed_proc ( speed_mode = = CPUFREQ_LOW ) ;
if ( speed_mode = = CPUFREQ_HIGH & &
cpu_has_feature ( CPU_FTR_L3CR ) ) {
l3cr = _get_L3CR ( ) ;
if ( ( prev_l3cr & L3CR_L3E ) & & l3cr ! = prev_l3cr )
_set_L3CR ( prev_l3cr ) ;
}
if ( notify )
2013-03-24 10:26:43 +04:00
cpufreq_notify_transition ( policy , & freqs , CPUFREQ_POSTCHANGE ) ;
2005-09-26 10:04:21 +04:00
cur_freq = ( speed_mode = = CPUFREQ_HIGH ) ? hi_freq : low_freq ;
return 0 ;
}
static unsigned int pmac_cpufreq_get_speed ( unsigned int cpu )
{
return cur_freq ;
}
static int pmac_cpufreq_target ( struct cpufreq_policy * policy ,
2013-10-25 18:15:48 +04:00
unsigned int index )
2005-09-26 10:04:21 +04:00
{
2005-11-07 06:27:33 +03:00
int rc ;
2005-09-26 10:04:21 +04:00
2013-10-25 18:15:48 +04:00
rc = do_set_cpu_speed ( policy , index , 1 ) ;
2005-09-26 10:04:21 +04:00
2005-11-07 06:27:33 +03:00
ppc_proc_freq = cur_freq * 1000ul ;
return rc ;
2005-09-26 10:04:21 +04:00
}
static int pmac_cpufreq_cpu_init ( struct cpufreq_policy * policy )
{
2013-10-03 18:59:20 +04:00
return cpufreq_generic_init ( policy , pmac_cpu_freqs , transition_latency ) ;
2005-09-26 10:04:21 +04:00
}
static u32 read_gpio ( struct device_node * np )
{
2007-04-03 16:26:41 +04:00
const u32 * reg = of_get_property ( np , " reg " , NULL ) ;
2005-09-26 10:04:21 +04:00
u32 offset ;
if ( reg = = NULL )
return 0 ;
/* That works for all keylargos but shall be fixed properly
* some day . . . The problem is that it seems we can ' t rely
* on the " reg " property of the GPIO nodes , they are either
* relative to the base of KeyLargo or to the base of the
* GPIO space , and the device - tree doesn ' t help .
*/
offset = * reg ;
if ( offset < KEYLARGO_GPIO_LEVELS0 )
offset + = KEYLARGO_GPIO_LEVELS0 ;
return offset ;
}
2011-03-10 23:13:05 +03:00
static int pmac_cpufreq_suspend ( struct cpufreq_policy * policy )
2005-09-26 10:04:21 +04:00
{
/* Ok, this could be made a bit smarter, but let's be robust for now. We
* always force a speed change to high speed before sleep , to make sure
* we have appropriate voltage and / or bus speed for the wakeup process ,
* and to make sure our loops_per_jiffies are " good enough " , that is will
* not cause too short delays if we sleep in low speed and wake in high
* speed . .
*/
no_schedule = 1 ;
sleep_freq = cur_freq ;
if ( cur_freq = = low_freq & & ! is_pmu_based )
2013-03-24 10:26:43 +04:00
do_set_cpu_speed ( policy , CPUFREQ_HIGH , 0 ) ;
2005-09-26 10:04:21 +04:00
return 0 ;
}
static int pmac_cpufreq_resume ( struct cpufreq_policy * policy )
{
/* If we resume, first check if we have a get() function */
if ( get_speed_proc )
cur_freq = get_speed_proc ( ) ;
2005-11-08 04:13:38 +03:00
else
2005-09-26 10:04:21 +04:00
cur_freq = 0 ;
/* We don't, hrm... we don't really know our speed here, best
* is that we force a switch to whatever it was , which is
* probably high speed due to our suspend ( ) routine
*/
2013-03-24 10:26:43 +04:00
do_set_cpu_speed ( policy , sleep_freq = = low_freq ?
2005-09-26 10:04:21 +04:00
CPUFREQ_LOW : CPUFREQ_HIGH , 0 ) ;
2005-11-07 06:27:33 +03:00
ppc_proc_freq = cur_freq * 1000ul ;
2005-09-26 10:04:21 +04:00
no_schedule = 0 ;
return 0 ;
}
static struct cpufreq_driver pmac_cpufreq_driver = {
2013-10-03 18:58:16 +04:00
. verify = cpufreq_generic_frequency_table_verify ,
2013-10-25 18:15:48 +04:00
. target_index = pmac_cpufreq_target ,
2005-09-26 10:04:21 +04:00
. get = pmac_cpufreq_get_speed ,
. init = pmac_cpufreq_cpu_init ,
. suspend = pmac_cpufreq_suspend ,
. resume = pmac_cpufreq_resume ,
. flags = CPUFREQ_PM_NO_WARN ,
2013-10-03 18:58:16 +04:00
. attr = cpufreq_generic_attr ,
2005-09-26 10:04:21 +04:00
. name = " powermac " ,
} ;
static int pmac_cpufreq_init_MacRISC3 ( struct device_node * cpunode )
{
struct device_node * volt_gpio_np = of_find_node_by_name ( NULL ,
" voltage-gpio " ) ;
struct device_node * freq_gpio_np = of_find_node_by_name ( NULL ,
" frequency-gpio " ) ;
struct device_node * slew_done_gpio_np = of_find_node_by_name ( NULL ,
" slewing-done " ) ;
2006-07-12 09:40:29 +04:00
const u32 * value ;
2005-09-26 10:04:21 +04:00
/*
* Check to see if it ' s GPIO driven or PMU only
*
* The way we extract the GPIO address is slightly hackish , but it
* works well enough for now . We need to abstract the whole GPIO
* stuff sooner or later anyway
*/
if ( volt_gpio_np )
voltage_gpio = read_gpio ( volt_gpio_np ) ;
if ( freq_gpio_np )
frequency_gpio = read_gpio ( freq_gpio_np ) ;
if ( slew_done_gpio_np )
slew_done_gpio = read_gpio ( slew_done_gpio_np ) ;
/* If we use the frequency GPIOs, calculate the min/max speeds based
* on the bus frequencies
*/
if ( frequency_gpio & & slew_done_gpio ) {
int lenp , rc ;
2006-07-12 09:40:29 +04:00
const u32 * freqs , * ratio ;
2005-09-26 10:04:21 +04:00
2007-04-03 16:26:41 +04:00
freqs = of_get_property ( cpunode , " bus-frequencies " , & lenp ) ;
2005-09-26 10:04:21 +04:00
lenp / = sizeof ( u32 ) ;
if ( freqs = = NULL | | lenp ! = 2 ) {
printk ( KERN_ERR " cpufreq: bus-frequencies incorrect or missing \n " ) ;
return 1 ;
}
2007-04-03 16:26:41 +04:00
ratio = of_get_property ( cpunode , " processor-to-bus-ratio*2 " ,
NULL ) ;
2005-09-26 10:04:21 +04:00
if ( ratio = = NULL ) {
printk ( KERN_ERR " cpufreq: processor-to-bus-ratio*2 missing \n " ) ;
return 1 ;
}
/* Get the min/max bus frequencies */
low_freq = min ( freqs [ 0 ] , freqs [ 1 ] ) ;
hi_freq = max ( freqs [ 0 ] , freqs [ 1 ] ) ;
/* Grrrr.. It _seems_ that the device-tree is lying on the low bus
* frequency , it claims it to be around 84 Mhz on some models while
* it appears to be approx . 101 Mhz on all . Let ' s hack around here . . .
* fortunately , we don ' t need to be too precise
*/
if ( low_freq < 98000000 )
low_freq = 101000000 ;
2005-11-07 06:27:33 +03:00
2005-09-26 10:04:21 +04:00
/* Convert those to CPU core clocks */
low_freq = ( low_freq * ( * ratio ) ) / 2000 ;
hi_freq = ( hi_freq * ( * ratio ) ) / 2000 ;
/* Now we get the frequencies, we read the GPIO to see what is out current
* speed
*/
rc = pmac_call_feature ( PMAC_FTR_READ_GPIO , NULL , frequency_gpio , 0 ) ;
cur_freq = ( rc & 0x01 ) ? hi_freq : low_freq ;
set_speed_proc = gpios_set_cpu_speed ;
return 1 ;
}
/* If we use the PMU, look for the min & max frequencies in the
* device - tree
*/
2007-04-03 16:26:41 +04:00
value = of_get_property ( cpunode , " min-clock-frequency " , NULL ) ;
2005-09-26 10:04:21 +04:00
if ( ! value )
return 1 ;
low_freq = ( * value ) / 1000 ;
/* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree
* here */
if ( low_freq < 100000 )
low_freq * = 10 ;
2007-04-03 16:26:41 +04:00
value = of_get_property ( cpunode , " max-clock-frequency " , NULL ) ;
2005-09-26 10:04:21 +04:00
if ( ! value )
return 1 ;
hi_freq = ( * value ) / 1000 ;
set_speed_proc = pmu_set_cpu_speed ;
is_pmu_based = 1 ;
return 0 ;
}
static int pmac_cpufreq_init_7447A ( struct device_node * cpunode )
{
struct device_node * volt_gpio_np ;
2007-04-03 16:26:41 +04:00
if ( of_get_property ( cpunode , " dynamic-power-step " , NULL ) = = NULL )
2005-09-26 10:04:21 +04:00
return 1 ;
volt_gpio_np = of_find_node_by_name ( NULL , " cpu-vcore-select " ) ;
if ( volt_gpio_np )
voltage_gpio = read_gpio ( volt_gpio_np ) ;
if ( ! voltage_gpio ) {
printk ( KERN_ERR " cpufreq: missing cpu-vcore-select gpio \n " ) ;
return 1 ;
}
/* OF only reports the high frequency */
hi_freq = cur_freq ;
low_freq = cur_freq / 2 ;
/* Read actual frequency from CPU */
cur_freq = dfs_get_cpu_speed ( ) ;
set_speed_proc = dfs_set_cpu_speed ;
get_speed_proc = dfs_get_cpu_speed ;
return 0 ;
}
static int pmac_cpufreq_init_750FX ( struct device_node * cpunode )
{
struct device_node * volt_gpio_np ;
2006-07-12 09:40:29 +04:00
u32 pvr ;
const u32 * value ;
2005-09-26 10:04:21 +04:00
2007-04-03 16:26:41 +04:00
if ( of_get_property ( cpunode , " dynamic-power-step " , NULL ) = = NULL )
2005-09-26 10:04:21 +04:00
return 1 ;
hi_freq = cur_freq ;
2007-04-03 16:26:41 +04:00
value = of_get_property ( cpunode , " reduced-clock-frequency " , NULL ) ;
2005-09-26 10:04:21 +04:00
if ( ! value )
return 1 ;
low_freq = ( * value ) / 1000 ;
volt_gpio_np = of_find_node_by_name ( NULL , " cpu-vcore-select " ) ;
if ( volt_gpio_np )
voltage_gpio = read_gpio ( volt_gpio_np ) ;
pvr = mfspr ( SPRN_PVR ) ;
has_cpu_l2lve = ! ( ( pvr & 0xf00 ) = = 0x100 ) ;
set_speed_proc = cpu_750fx_cpu_speed ;
get_speed_proc = cpu_750fx_get_cpu_speed ;
cur_freq = cpu_750fx_get_cpu_speed ( ) ;
return 0 ;
}
/* Currently, we support the following machines:
*
* - Titanium PowerBook 1 Ghz ( PMU based , 667 Mhz & 1 Ghz )
* - Titanium PowerBook 800 ( PMU based , 667 Mhz & 800 Mhz )
* - Titanium PowerBook 400 ( PMU based , 300 Mhz & 400 Mhz )
* - Titanium PowerBook 500 ( PMU based , 300 Mhz & 500 Mhz )
* - iBook2 500 / 600 ( PMU based , 400 Mhz & 500 / 600 Mhz )
* - iBook2 700 ( CPU based , 400 Mhz & 700 Mhz , support low voltage )
* - Recent MacRISC3 laptops
* - All new machines with 7447 A CPUs
*/
static int __init pmac_cpufreq_setup ( void )
{
struct device_node * cpunode ;
2006-07-12 09:40:29 +04:00
const u32 * value ;
2005-09-26 10:04:21 +04:00
if ( strstr ( cmd_line , " nocpufreq " ) )
return 0 ;
2013-07-17 16:52:17 +04:00
/* Get first CPU node */
cpunode = of_cpu_device_node_get ( 0 ) ;
2005-09-26 10:04:21 +04:00
if ( ! cpunode )
goto out ;
/* Get current cpu clock freq */
2007-04-03 16:26:41 +04:00
value = of_get_property ( cpunode , " clock-frequency " , NULL ) ;
2005-09-26 10:04:21 +04:00
if ( ! value )
goto out ;
cur_freq = ( * value ) / 1000 ;
2012-10-29 03:15:14 +04:00
transition_latency = CPUFREQ_ETERNAL ;
2005-09-26 10:04:21 +04:00
/* Check for 7447A based MacRISC3 */
2010-02-02 07:34:14 +03:00
if ( of_machine_is_compatible ( " MacRISC3 " ) & &
2007-04-03 16:26:41 +04:00
of_get_property ( cpunode , " dynamic-power-step " , NULL ) & &
2005-09-26 10:04:21 +04:00
PVR_VER ( mfspr ( SPRN_PVR ) ) = = 0x8003 ) {
pmac_cpufreq_init_7447A ( cpunode ) ;
2012-10-29 03:15:14 +04:00
transition_latency = 8000000 ;
2005-09-26 10:04:21 +04:00
/* Check for other MacRISC3 machines */
2010-02-02 07:34:14 +03:00
} else if ( of_machine_is_compatible ( " PowerBook3,4 " ) | |
of_machine_is_compatible ( " PowerBook3,5 " ) | |
of_machine_is_compatible ( " MacRISC3 " ) ) {
2005-09-26 10:04:21 +04:00
pmac_cpufreq_init_MacRISC3 ( cpunode ) ;
/* Else check for iBook2 500/600 */
2010-02-02 07:34:14 +03:00
} else if ( of_machine_is_compatible ( " PowerBook4,1 " ) ) {
2005-09-26 10:04:21 +04:00
hi_freq = cur_freq ;
low_freq = 400000 ;
set_speed_proc = pmu_set_cpu_speed ;
is_pmu_based = 1 ;
}
2005-10-12 11:01:50 +04:00
/* Else check for TiPb 550 */
2010-02-02 07:34:14 +03:00
else if ( of_machine_is_compatible ( " PowerBook3,3 " ) & & cur_freq = = 550000 ) {
2005-10-12 11:01:50 +04:00
hi_freq = cur_freq ;
low_freq = 500000 ;
set_speed_proc = pmu_set_cpu_speed ;
is_pmu_based = 1 ;
}
2005-09-26 10:04:21 +04:00
/* Else check for TiPb 400 & 500 */
2010-02-02 07:34:14 +03:00
else if ( of_machine_is_compatible ( " PowerBook3,2 " ) ) {
2005-09-26 10:04:21 +04:00
/* We only know about the 400 MHz and the 500Mhz model
* they both have 300 MHz as low frequency
*/
if ( cur_freq < 350000 | | cur_freq > 550000 )
goto out ;
hi_freq = cur_freq ;
low_freq = 300000 ;
set_speed_proc = pmu_set_cpu_speed ;
is_pmu_based = 1 ;
}
/* Else check for 750FX */
else if ( PVR_VER ( mfspr ( SPRN_PVR ) ) = = 0x7000 )
pmac_cpufreq_init_750FX ( cpunode ) ;
out :
2007-04-24 07:51:59 +04:00
of_node_put ( cpunode ) ;
2005-09-26 10:04:21 +04:00
if ( set_speed_proc = = NULL )
return - ENODEV ;
pmac_cpu_freqs [ CPUFREQ_LOW ] . frequency = low_freq ;
pmac_cpu_freqs [ CPUFREQ_HIGH ] . frequency = hi_freq ;
2005-11-07 06:27:33 +03:00
ppc_proc_freq = cur_freq * 1000ul ;
2005-09-26 10:04:21 +04:00
printk ( KERN_INFO " Registering PowerMac CPU frequency driver \n " ) ;
printk ( KERN_INFO " Low: %d Mhz, High: %d Mhz, Boot: %d Mhz \n " ,
low_freq / 1000 , hi_freq / 1000 , cur_freq / 1000 ) ;
return cpufreq_register_driver ( & pmac_cpufreq_driver ) ;
}
module_init ( pmac_cpufreq_setup ) ;