2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-12-14 16:30:14 +03:00
/*
* Copyright ( C ) 2002 , 2003 Intrinsyc Software
*
* History :
* 31 - Jul - 2002 : Initial version [ FB ]
* 29 - Jan - 2003 : added PXA255 support [ FB ]
* 20 - Apr - 2003 : ported to v2 .5 ( Dustin McIntire , Sensoria Corp . )
*
* Note :
* This driver may change the memory bus clock rate , but will not do any
* platform specific access timing changes . . . for example if you have flash
* memory connected to CS0 , you will need to register a platform specific
* notifier which will adjust the memory access strobes to maintain a
* minimum strobe width .
*/
2016-04-05 23:28:25 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2007-12-14 16:30:14 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/init.h>
# include <linux/cpufreq.h>
2009-05-18 01:03:55 +04:00
# include <linux/err.h>
# include <linux/regulator/consumer.h>
2010-11-03 18:29:35 +03:00
# include <linux/io.h>
2007-12-14 16:30:14 +03:00
2008-08-05 19:14:15 +04:00
# include <mach/pxa2xx-regs.h>
2010-11-03 18:29:35 +03:00
# include <mach/smemc.h>
2007-12-14 16:30:14 +03:00
# ifdef DEBUG
static unsigned int freq_debug ;
2008-02-27 23:11:16 +03:00
module_param ( freq_debug , uint , 0 ) ;
2007-12-14 16:30:14 +03:00
MODULE_PARM_DESC ( freq_debug , " Set the debug messages to on=1/off=0 " ) ;
# else
# define freq_debug 0
# endif
2009-05-18 01:03:55 +04:00
static struct regulator * vcc_core ;
2008-05-07 23:39:06 +04:00
static unsigned int pxa27x_maxfreq ;
module_param ( pxa27x_maxfreq , uint , 0 ) ;
MODULE_PARM_DESC ( pxa27x_maxfreq , " Set the pxa27x maxfreq in MHz "
" (typically 624=>pxa270, 416=>pxa271, 520=>pxa272) " ) ;
2017-10-15 00:51:02 +03:00
struct pxa_cpufreq_data {
struct clk * clk_core ;
} ;
static struct pxa_cpufreq_data pxa_cpufreq_data ;
2015-05-01 11:34:00 +03:00
struct pxa_freqs {
2007-12-14 16:30:14 +03:00
unsigned int khz ;
2009-05-18 01:03:55 +04:00
int vmin ;
int vmax ;
2015-05-01 11:34:00 +03:00
} ;
2007-12-14 16:30:14 +03:00
2008-05-07 23:39:06 +04:00
/*
* PXA255 definitions
*/
2015-05-01 11:34:01 +03:00
static const struct pxa_freqs pxa255_run_freqs [ ] =
2007-12-14 16:30:14 +03:00
{
2017-10-15 00:51:02 +03:00
/* CPU MEMBUS run turbo PXbus SDRAM */
{ 99500 , - 1 , - 1 } , /* 99, 99, 50, 50 */
{ 132700 , - 1 , - 1 } , /* 133, 133, 66, 66 */
{ 199100 , - 1 , - 1 } , /* 199, 199, 99, 99 */
{ 265400 , - 1 , - 1 } , /* 265, 265, 133, 66 */
{ 331800 , - 1 , - 1 } , /* 331, 331, 166, 83 */
{ 398100 , - 1 , - 1 } , /* 398, 398, 196, 99 */
2007-12-14 16:30:14 +03:00
} ;
/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
2015-05-01 11:34:01 +03:00
static const struct pxa_freqs pxa255_turbo_freqs [ ] =
2007-12-14 16:30:14 +03:00
{
2017-10-15 00:51:02 +03:00
/* CPU run turbo PXbus SDRAM */
{ 99500 , - 1 , - 1 } , /* 99, 99, 50, 50 */
{ 199100 , - 1 , - 1 } , /* 99, 199, 50, 99 */
{ 298500 , - 1 , - 1 } , /* 99, 287, 50, 99 */
{ 298600 , - 1 , - 1 } , /* 199, 287, 99, 99 */
{ 398100 , - 1 , - 1 } , /* 199, 398, 99, 99 */
2007-12-14 16:30:14 +03:00
} ;
2008-05-07 23:39:06 +04:00
# define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
# define NUM_PXA25x_TURBO_FREQS ARRAY_SIZE(pxa255_turbo_freqs)
static struct cpufreq_frequency_table
pxa255_run_freq_table [ NUM_PXA25x_RUN_FREQS + 1 ] ;
2008-05-07 23:36:34 +04:00
static struct cpufreq_frequency_table
2008-05-07 23:39:06 +04:00
pxa255_turbo_freq_table [ NUM_PXA25x_TURBO_FREQS + 1 ] ;
2008-11-04 15:33:25 +03:00
static unsigned int pxa255_turbo_table ;
module_param ( pxa255_turbo_table , uint , 0 ) ;
MODULE_PARM_DESC ( pxa255_turbo_table , " Selects the frequency table (0 = run table, !0 = turbo table) " ) ;
2015-05-01 11:34:00 +03:00
static struct pxa_freqs pxa27x_freqs [ ] = {
2017-10-15 00:51:02 +03:00
{ 104000 , 900000 , 1705000 } ,
{ 156000 , 1000000 , 1705000 } ,
{ 208000 , 1180000 , 1705000 } ,
{ 312000 , 1250000 , 1705000 } ,
{ 416000 , 1350000 , 1705000 } ,
{ 520000 , 1450000 , 1705000 } ,
{ 624000 , 1550000 , 1705000 }
2008-05-07 23:39:06 +04:00
} ;
# define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs)
static struct cpufreq_frequency_table
pxa27x_freq_table [ NUM_PXA27x_FREQS + 1 ] ;
2007-12-14 16:30:14 +03:00
extern unsigned get_clk_frequency_khz ( int info ) ;
2009-05-18 01:03:55 +04:00
# ifdef CONFIG_REGULATOR
2015-05-01 11:34:01 +03:00
static int pxa_cpufreq_change_voltage ( const struct pxa_freqs * pxa_freq )
2009-05-18 01:03:55 +04:00
{
int ret = 0 ;
int vmin , vmax ;
if ( ! cpu_is_pxa27x ( ) )
return 0 ;
vmin = pxa_freq - > vmin ;
vmax = pxa_freq - > vmax ;
if ( ( vmin = = - 1 ) | | ( vmax = = - 1 ) )
return 0 ;
ret = regulator_set_voltage ( vcc_core , vmin , vmax ) ;
if ( ret )
2016-04-05 23:28:25 +03:00
pr_err ( " Failed to set vcc_core in [%dmV..%dmV] \n " , vmin , vmax ) ;
2009-05-18 01:03:55 +04:00
return ret ;
}
2019-03-07 13:22:41 +03:00
static void pxa_cpufreq_init_voltages ( void )
2009-05-18 01:03:55 +04:00
{
vcc_core = regulator_get ( NULL , " vcc_core " ) ;
if ( IS_ERR ( vcc_core ) ) {
2016-04-05 23:28:25 +03:00
pr_info ( " Didn't find vcc_core regulator \n " ) ;
2009-05-18 01:03:55 +04:00
vcc_core = NULL ;
} else {
2016-04-05 23:28:25 +03:00
pr_info ( " Found vcc_core regulator \n " ) ;
2009-05-18 01:03:55 +04:00
}
}
# else
2016-01-25 18:44:38 +03:00
static int pxa_cpufreq_change_voltage ( const struct pxa_freqs * pxa_freq )
2009-05-18 01:03:55 +04:00
{
return 0 ;
}
2019-03-07 13:22:41 +03:00
static void pxa_cpufreq_init_voltages ( void ) { }
2009-05-18 01:03:55 +04:00
# endif
2008-11-04 15:33:25 +03:00
static void find_freq_tables ( struct cpufreq_frequency_table * * freq_table ,
2015-05-01 11:34:01 +03:00
const struct pxa_freqs * * pxa_freqs )
2008-05-07 23:39:06 +04:00
{
if ( cpu_is_pxa25x ( ) ) {
2008-11-04 15:33:25 +03:00
if ( ! pxa255_turbo_table ) {
2008-05-07 23:39:06 +04:00
* pxa_freqs = pxa255_run_freqs ;
* freq_table = pxa255_run_freq_table ;
2008-11-04 15:33:25 +03:00
} else {
2008-05-07 23:39:06 +04:00
* pxa_freqs = pxa255_turbo_freqs ;
* freq_table = pxa255_turbo_freq_table ;
}
2013-04-25 21:28:57 +04:00
} else if ( cpu_is_pxa27x ( ) ) {
2008-05-07 23:39:06 +04:00
* pxa_freqs = pxa27x_freqs ;
* freq_table = pxa27x_freq_table ;
2013-04-25 21:28:57 +04:00
} else {
BUG ( ) ;
2008-05-07 23:39:06 +04:00
}
}
static void pxa27x_guess_max_freq ( void )
{
if ( ! pxa27x_maxfreq ) {
pxa27x_maxfreq = 416000 ;
2016-04-05 23:28:24 +03:00
pr_info ( " PXA CPU 27x max frequency not defined (pxa27x_maxfreq), assuming pxa271 with %dkHz maxfreq \n " ,
pxa27x_maxfreq ) ;
2008-05-07 23:39:06 +04:00
} else {
pxa27x_maxfreq * = 1000 ;
}
}
static unsigned int pxa_cpufreq_get ( unsigned int cpu )
{
2017-10-15 00:51:02 +03:00
struct pxa_cpufreq_data * data = cpufreq_get_driver_data ( ) ;
return ( unsigned int ) clk_get_rate ( data - > clk_core ) / 1000 ;
2008-05-07 23:39:06 +04:00
}
2013-10-25 18:15:48 +04:00
static int pxa_set_target ( struct cpufreq_policy * policy , unsigned int idx )
2007-12-14 16:30:14 +03:00
{
struct cpufreq_frequency_table * pxa_freqs_table ;
2015-05-01 11:34:01 +03:00
const struct pxa_freqs * pxa_freq_settings ;
2017-10-15 00:51:02 +03:00
struct pxa_cpufreq_data * data = cpufreq_get_driver_data ( ) ;
unsigned int new_freq_cpu ;
2009-05-18 01:03:55 +04:00
int ret = 0 ;
2007-12-14 16:30:14 +03:00
/* Get the current policy */
2008-11-04 15:33:25 +03:00
find_freq_tables ( & pxa_freqs_table , & pxa_freq_settings ) ;
2007-12-14 16:30:14 +03:00
2008-05-07 23:39:06 +04:00
new_freq_cpu = pxa_freq_settings [ idx ] . khz ;
2007-12-14 16:30:14 +03:00
if ( freq_debug )
2017-10-15 00:51:02 +03:00
pr_debug ( " Changing CPU frequency from %d Mhz to %d Mhz \n " ,
policy - > cur / 1000 , new_freq_cpu / 1000 ) ;
2007-12-14 16:30:14 +03:00
2013-08-14 18:08:24 +04:00
if ( vcc_core & & new_freq_cpu > policy - > cur ) {
2009-05-18 01:03:55 +04:00
ret = pxa_cpufreq_change_voltage ( & pxa_freq_settings [ idx ] ) ;
2013-08-14 18:08:24 +04:00
if ( ret )
return ret ;
}
2007-12-14 16:30:14 +03:00
2017-10-15 00:51:02 +03:00
clk_set_rate ( data - > clk_core , new_freq_cpu * 1000 ) ;
2007-12-14 16:30:14 +03:00
2009-05-18 01:03:55 +04:00
/*
* Even if voltage setting fails , we don ' t report it , as the frequency
* change succeeded . The voltage reduction is not a critical failure ,
* only power savings will suffer from this .
*
* Note : if the voltage change fails , and a return value is returned , a
* bug is triggered ( seems a deadlock ) . Should anybody find out where ,
* the " return 0 " should become a " return ret " .
*/
2013-08-14 18:08:24 +04:00
if ( vcc_core & & new_freq_cpu < policy - > cur )
2009-05-18 01:03:55 +04:00
ret = pxa_cpufreq_change_voltage ( & pxa_freq_settings [ idx ] ) ;
2007-12-14 16:30:14 +03:00
return 0 ;
}
2010-08-18 07:51:13 +04:00
static int pxa_cpufreq_init ( struct cpufreq_policy * policy )
2007-12-14 16:30:14 +03:00
{
int i ;
2008-05-07 23:39:06 +04:00
unsigned int freq ;
2008-11-04 15:33:25 +03:00
struct cpufreq_frequency_table * pxa255_freq_table ;
2015-05-01 11:34:01 +03:00
const struct pxa_freqs * pxa255_freqs ;
2008-05-07 23:39:06 +04:00
/* try to guess pxa27x cpu */
if ( cpu_is_pxa27x ( ) )
pxa27x_guess_max_freq ( ) ;
2007-12-14 16:30:14 +03:00
2009-05-18 01:03:55 +04:00
pxa_cpufreq_init_voltages ( ) ;
2007-12-14 16:30:14 +03:00
/* set default policy and cpuinfo */
policy - > cpuinfo . transition_latency = 1000 ; /* FIXME: 1 ms, assumed */
2008-05-07 23:39:06 +04:00
/* Generate pxa25x the run cpufreq_frequency_table struct */
for ( i = 0 ; i < NUM_PXA25x_RUN_FREQS ; i + + ) {
2007-12-14 16:30:14 +03:00
pxa255_run_freq_table [ i ] . frequency = pxa255_run_freqs [ i ] . khz ;
2013-03-30 14:55:15 +04:00
pxa255_run_freq_table [ i ] . driver_data = i ;
2007-12-14 16:30:14 +03:00
}
pxa255_run_freq_table [ i ] . frequency = CPUFREQ_TABLE_END ;
2008-05-07 23:39:06 +04:00
/* Generate pxa25x the turbo cpufreq_frequency_table struct */
for ( i = 0 ; i < NUM_PXA25x_TURBO_FREQS ; i + + ) {
2008-05-07 23:36:34 +04:00
pxa255_turbo_freq_table [ i ] . frequency =
pxa255_turbo_freqs [ i ] . khz ;
2013-03-30 14:55:15 +04:00
pxa255_turbo_freq_table [ i ] . driver_data = i ;
2007-12-14 16:30:14 +03:00
}
pxa255_turbo_freq_table [ i ] . frequency = CPUFREQ_TABLE_END ;
2008-11-04 15:33:25 +03:00
pxa255_turbo_table = ! ! pxa255_turbo_table ;
2008-05-07 23:39:06 +04:00
/* Generate the pxa27x cpufreq_frequency_table struct */
for ( i = 0 ; i < NUM_PXA27x_FREQS ; i + + ) {
freq = pxa27x_freqs [ i ] . khz ;
if ( freq > pxa27x_maxfreq )
break ;
pxa27x_freq_table [ i ] . frequency = freq ;
2013-03-30 14:55:15 +04:00
pxa27x_freq_table [ i ] . driver_data = i ;
2008-05-07 23:39:06 +04:00
}
2013-03-30 14:55:15 +04:00
pxa27x_freq_table [ i ] . driver_data = i ;
2008-05-07 23:39:06 +04:00
pxa27x_freq_table [ i ] . frequency = CPUFREQ_TABLE_END ;
/*
* Set the policy ' s minimum and maximum frequencies from the tables
* just constructed . This sets cpuinfo . mxx_freq , min and max .
*/
2008-11-04 15:33:25 +03:00
if ( cpu_is_pxa25x ( ) ) {
find_freq_tables ( & pxa255_freq_table , & pxa255_freqs ) ;
2016-04-05 23:28:25 +03:00
pr_info ( " using %s frequency table \n " ,
2008-11-04 15:33:25 +03:00
pxa255_turbo_table ? " turbo " : " run " ) ;
2013-09-16 17:26:04 +04:00
2018-02-26 08:09:00 +03:00
policy - > freq_table = pxa255_freq_table ;
2008-11-04 15:33:25 +03:00
}
2013-09-16 17:26:04 +04:00
else if ( cpu_is_pxa27x ( ) ) {
2018-02-26 08:09:00 +03:00
policy - > freq_table = pxa27x_freq_table ;
2013-09-16 17:26:04 +04:00
}
2008-05-07 23:39:06 +04:00
2016-04-05 23:28:25 +03:00
pr_info ( " frequency change support initialized \n " ) ;
2007-12-14 16:30:14 +03:00
return 0 ;
}
static struct cpufreq_driver pxa_cpufreq_driver = {
2013-12-03 09:50:45 +04:00
. flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK ,
2013-10-03 18:58:20 +04:00
. verify = cpufreq_generic_frequency_table_verify ,
2013-10-25 18:15:48 +04:00
. target_index = pxa_set_target ,
2007-12-14 16:30:14 +03:00
. init = pxa_cpufreq_init ,
2008-02-11 18:53:15 +03:00
. get = pxa_cpufreq_get ,
2008-05-07 23:39:06 +04:00
. name = " PXA2xx " ,
2017-10-15 00:51:02 +03:00
. driver_data = & pxa_cpufreq_data ,
2007-12-14 16:30:14 +03:00
} ;
static int __init pxa_cpu_init ( void )
{
int ret = - ENODEV ;
2017-10-15 00:51:02 +03:00
pxa_cpufreq_data . clk_core = clk_get_sys ( NULL , " core " ) ;
if ( IS_ERR ( pxa_cpufreq_data . clk_core ) )
return PTR_ERR ( pxa_cpufreq_data . clk_core ) ;
2008-05-07 23:39:06 +04:00
if ( cpu_is_pxa25x ( ) | | cpu_is_pxa27x ( ) )
2007-12-14 16:30:14 +03:00
ret = cpufreq_register_driver ( & pxa_cpufreq_driver ) ;
return ret ;
}
static void __exit pxa_cpu_exit ( void )
{
2008-05-07 23:39:06 +04:00
cpufreq_unregister_driver ( & pxa_cpufreq_driver ) ;
2007-12-14 16:30:14 +03:00
}
2008-05-07 23:36:34 +04:00
MODULE_AUTHOR ( " Intrinsyc Software Inc. " ) ;
MODULE_DESCRIPTION ( " CPU frequency changing driver for the PXA architecture " ) ;
2007-12-14 16:30:14 +03:00
MODULE_LICENSE ( " GPL " ) ;
module_init ( pxa_cpu_init ) ;
module_exit ( pxa_cpu_exit ) ;