2005-04-16 15:20:36 -07:00
/*
* Carsten Langgaard , carstenl @ mips . com
* Copyright ( C ) 1999 , 2000 MIPS Technologies , Inc . All rights reserved .
*
* This program is free software ; you can distribute it and / or modify it
* under the terms of the GNU General Public License ( Version 2 ) as
* published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston MA 02111 - 1307 , USA .
*
* Setting up the clock on the MIPS boards .
*/
# include <linux/types.h>
# include <linux/init.h>
# include <linux/kernel_stat.h>
# include <linux/sched.h>
# include <linux/spinlock.h>
# include <linux/interrupt.h>
# include <linux/time.h>
# include <linux/timex.h>
# include <linux/mc146818rtc.h>
# include <asm/mipsregs.h>
2006-04-05 09:45:45 +01:00
# include <asm/mipsmtregs.h>
2005-07-14 15:57:16 +00:00
# include <asm/hardirq.h>
2007-10-11 23:46:10 +01:00
# include <asm/i8253.h>
2005-07-14 15:57:16 +00:00
# include <asm/irq.h>
2005-04-16 15:20:36 -07:00
# include <asm/div64.h>
# include <asm/cpu.h>
# include <asm/time.h>
# include <asm/mc146818-time.h>
2005-07-14 15:57:16 +00:00
# include <asm/msc01_ic.h>
2005-04-16 15:20:36 -07:00
# include <asm/mips-boards/generic.h>
# include <asm/mips-boards/prom.h>
2006-09-12 19:12:18 +01:00
# ifdef CONFIG_MIPS_ATLAS
# include <asm/mips-boards/atlasint.h>
# endif
# ifdef CONFIG_MIPS_MALTA
2005-07-14 15:57:16 +00:00
# include <asm/mips-boards/maltaint.h>
2006-09-12 19:12:18 +01:00
# endif
2007-01-08 01:27:40 +09:00
# ifdef CONFIG_MIPS_SEAD
# include <asm/mips-boards/seadint.h>
# endif
2005-04-16 15:20:36 -07:00
unsigned long cpu_khz ;
2005-07-14 15:57:16 +00:00
static int mips_cpu_timer_irq ;
2007-06-20 22:27:10 +01:00
extern int cp0_perfcount_irq ;
2005-04-16 15:20:36 -07:00
2006-10-07 19:44:33 +01:00
static void mips_timer_dispatch ( void )
2005-04-16 15:20:36 -07:00
{
2006-10-07 19:44:33 +01:00
do_IRQ ( mips_cpu_timer_irq ) ;
2005-07-14 15:57:16 +00:00
}
2007-05-24 22:24:20 +01:00
static void mips_perf_dispatch ( void )
{
2007-06-20 22:27:10 +01:00
do_IRQ ( cp0_perfcount_irq ) ;
2007-05-24 22:24:20 +01:00
}
2005-04-16 15:20:36 -07:00
/*
2006-10-21 02:05:20 +01:00
* Estimate CPU frequency . Sets mips_hpt_frequency as a side - effect
2005-04-16 15:20:36 -07:00
*/
static unsigned int __init estimate_cpu_frequency ( void )
{
unsigned int prid = read_c0_prid ( ) & 0xffff00 ;
unsigned int count ;
2006-04-05 09:45:45 +01:00
# if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_SIM)
2005-04-16 15:20:36 -07:00
/*
* The SEAD board doesn ' t have a real time clock , so we can ' t
* really calculate the timer frequency
* For now we hardwire the SEAD board frequency to 12 MHz .
*/
2005-09-03 15:56:17 -07:00
2005-04-16 15:20:36 -07:00
if ( ( prid = = ( PRID_COMP_MIPS | PRID_IMP_20KC ) ) | |
( prid = = ( PRID_COMP_MIPS | PRID_IMP_25KF ) ) )
count = 12000000 ;
else
count = 6000000 ;
# endif
# if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA)
2006-10-31 19:53:15 +00:00
unsigned long flags ;
2006-10-31 18:33:09 +00:00
unsigned int start ;
2005-04-16 15:20:36 -07:00
local_irq_save ( flags ) ;
/* Start counter exactly on falling edge of update flag */
while ( CMOS_READ ( RTC_REG_A ) & RTC_UIP ) ;
while ( ! ( CMOS_READ ( RTC_REG_A ) & RTC_UIP ) ) ;
/* Start r4k counter. */
2006-10-31 18:33:09 +00:00
start = read_c0_count ( ) ;
2005-04-16 15:20:36 -07:00
/* Read counter exactly on falling edge of update flag */
while ( CMOS_READ ( RTC_REG_A ) & RTC_UIP ) ;
while ( ! ( CMOS_READ ( RTC_REG_A ) & RTC_UIP ) ) ;
2006-10-31 18:33:09 +00:00
count = read_c0_count ( ) - start ;
2005-04-16 15:20:36 -07:00
/* restore interrupts */
local_irq_restore ( flags ) ;
# endif
mips_hpt_frequency = count ;
if ( ( prid ! = ( PRID_COMP_MIPS | PRID_IMP_20KC ) ) & &
( prid ! = ( PRID_COMP_MIPS | PRID_IMP_25KF ) ) )
count * = 2 ;
count + = 5000 ; /* round */
count - = count % 10000 ;
return count ;
}
2007-10-11 23:46:08 +01:00
unsigned long read_persistent_clock ( void )
2005-04-16 15:20:36 -07:00
{
return mc146818_get_cmos_time ( ) ;
}
2007-10-11 23:46:09 +01:00
void __init plat_perf_setup ( void )
2007-05-24 22:24:20 +01:00
{
2007-06-20 22:27:10 +01:00
cp0_perfcount_irq = - 1 ;
2007-05-24 22:24:20 +01:00
2007-01-08 01:27:40 +09:00
# ifdef MSC01E_INT_BASE
2005-07-14 15:57:16 +00:00
if ( cpu_has_veic ) {
2007-10-11 23:46:15 +01:00
set_vi_handler ( MSC01E_INT_PERFCTR , mips_perf_dispatch ) ;
2007-06-20 22:27:10 +01:00
cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR ;
2007-01-08 01:27:40 +09:00
} else
# endif
2007-06-20 22:27:10 +01:00
if ( cp0_perfcount_irq > = 0 ) {
if ( cpu_has_vint )
set_vi_handler ( cp0_perfcount_irq , mips_perf_dispatch ) ;
2007-05-24 22:24:20 +01:00
# ifdef CONFIG_SMP
2007-06-20 22:27:10 +01:00
set_irq_handler ( cp0_perfcount_irq , handle_percpu_irq ) ;
2007-05-24 22:24:20 +01:00
# endif
2005-07-14 15:57:16 +00:00
}
2007-05-24 22:24:20 +01:00
}
2005-07-14 15:57:16 +00:00
2007-10-29 14:23:43 +00:00
unsigned int __init get_c0_compare_int ( void )
2007-05-24 22:24:20 +01:00
{
2007-05-24 22:46:25 +01:00
# ifdef MSC01E_INT_BASE
2007-05-24 22:24:20 +01:00
if ( cpu_has_veic ) {
2007-10-11 23:46:15 +01:00
set_vi_handler ( MSC01E_INT_CPUCTR , mips_timer_dispatch ) ;
2007-05-24 22:24:20 +01:00
mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR ;
2007-10-29 14:23:43 +00:00
} else
2007-05-24 22:46:25 +01:00
# endif
{
2007-05-24 22:24:20 +01:00
if ( cpu_has_vint )
2007-06-20 22:27:10 +01:00
set_vi_handler ( cp0_compare_irq , mips_timer_dispatch ) ;
mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq ;
2007-05-24 22:24:20 +01:00
}
2005-07-14 15:57:16 +00:00
2007-10-29 14:23:43 +00:00
return mips_cpu_timer_irq ;
}
void __init plat_time_init ( void )
{
unsigned int est_freq ;
/* Set Data mode - binary. */
CMOS_WRITE ( CMOS_READ ( RTC_CONTROL ) | RTC_DM_BINARY , RTC_CONTROL ) ;
est_freq = estimate_cpu_frequency ( ) ;
printk ( " CPU frequency %d.%02d MHz \n " , est_freq / 1000000 ,
( est_freq % 1000000 ) * 100 / 1000000 ) ;
cpu_khz = est_freq / 1000 ;
mips_scroll_message ( ) ;
# ifdef CONFIG_I8253 /* Only Malta has a PIT */
setup_pit_timer ( ) ;
2005-08-17 17:44:08 +00:00
# endif
2007-05-24 22:24:20 +01:00
2007-10-11 23:46:09 +01:00
plat_perf_setup ( ) ;
2005-04-16 15:20:36 -07:00
}