2012-05-30 21:02:49 +00:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2012 MIPS Technologies , Inc . All rights reserved .
*/
# include <linux/init.h>
# include <asm/setup.h>
# include <asm/time.h>
# include <asm/irq.h>
# include <asm/mips-boards/generic.h>
# include <asm/mips-boards/prom.h>
unsigned long cpu_khz ;
static int mips_cpu_timer_irq ;
static int mips_cpu_perf_irq ;
static void mips_timer_dispatch ( void )
{
do_IRQ ( mips_cpu_timer_irq ) ;
}
static void mips_perf_dispatch ( void )
{
do_IRQ ( mips_cpu_perf_irq ) ;
}
static void __iomem * status_reg = ( void __iomem * ) 0xbf000410 ;
/*
* Estimate CPU frequency . Sets mips_hpt_frequency as a side - effect .
*/
static unsigned int __init estimate_cpu_frequency ( void )
{
unsigned int prid = read_c0_prid ( ) & 0xffff00 ;
unsigned int tick = 0 ;
unsigned int freq ;
unsigned int orig ;
unsigned long flags ;
local_irq_save ( flags ) ;
2013-01-22 12:59:30 +01:00
orig = readl ( status_reg ) & 0x2 ; /* get original sample */
2012-05-30 21:02:49 +00:00
/* wait for transition */
while ( ( readl ( status_reg ) & 0x2 ) = = orig )
;
2013-01-22 12:59:30 +01:00
orig = orig ^ 0x2 ; /* flip the bit */
2012-05-30 21:02:49 +00:00
write_c0_count ( 0 ) ;
/* wait 1 second (the sampling clock transitions every 10ms) */
while ( tick < 100 ) {
/* wait for transition */
while ( ( readl ( status_reg ) & 0x2 ) = = orig )
;
2013-01-22 12:59:30 +01:00
orig = orig ^ 0x2 ; /* flip the bit */
2012-05-30 21:02:49 +00:00
tick + + ;
}
freq = read_c0_count ( ) ;
local_irq_restore ( flags ) ;
mips_hpt_frequency = freq ;
/* Adjust for processor */
if ( ( prid ! = ( PRID_COMP_MIPS | PRID_IMP_20KC ) ) & &
( prid ! = ( PRID_COMP_MIPS | PRID_IMP_25KF ) ) )
freq * = 2 ;
2013-01-22 12:59:30 +01:00
freq + = 5000 ; /* rounding */
2012-05-30 21:02:49 +00:00
freq - = freq % 10000 ;
return freq ;
}
void read_persistent_clock ( struct timespec * ts )
{
ts - > tv_sec = 0 ;
ts - > tv_nsec = 0 ;
}
static void __init plat_perf_setup ( void )
{
if ( cp0_perfcount_irq > = 0 ) {
if ( cpu_has_vint )
set_vi_handler ( cp0_perfcount_irq , mips_perf_dispatch ) ;
mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq ;
}
}
unsigned int __cpuinit get_c0_compare_int ( void )
{
if ( cpu_has_vint )
set_vi_handler ( cp0_compare_irq , mips_timer_dispatch ) ;
mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq ;
return mips_cpu_timer_irq ;
}
void __init plat_time_init ( void )
{
unsigned int est_freq ;
est_freq = estimate_cpu_frequency ( ) ;
pr_debug ( " CPU frequency %d.%02d MHz \n " , ( est_freq / 1000000 ) ,
( est_freq % 1000000 ) * 100 / 1000000 ) ;
cpu_khz = est_freq / 1000 ;
mips_scroll_message ( ) ;
plat_perf_setup ( ) ;
}