2005-04-16 15:20:36 -07:00
/***************************************************************************/
/*
* timers . c - - generic ColdFire hardware timer support .
*
2008-02-01 17:40:26 +10:00
* Copyright ( C ) 1999 - 2008 , Greg Ungerer < gerg @ snapgear . com >
2005-04-16 15:20:36 -07:00
*/
/***************************************************************************/
# include <linux/kernel.h>
2007-10-23 14:37:54 +10:00
# include <linux/init.h>
2005-04-16 15:20:36 -07:00
# include <linux/sched.h>
# include <linux/interrupt.h>
2007-07-27 01:09:00 +10:00
# include <linux/irq.h>
2008-02-01 17:40:26 +10:00
# include <linux/profile.h>
# include <linux/clocksource.h>
2006-06-26 10:33:10 +10:00
# include <asm/io.h>
2005-04-16 15:20:36 -07:00
# include <asm/traps.h>
# include <asm/machdep.h>
# include <asm/coldfire.h>
# include <asm/mcftimer.h>
# include <asm/mcfsim.h>
/***************************************************************************/
2006-06-26 10:33:10 +10:00
/*
* By default use timer1 as the system clock timer .
*/
2008-02-01 17:40:26 +10:00
# define FREQ (MCF_BUSCLK / 16)
2011-03-09 09:57:14 +10:00
# define TA(a) (MCFTIMER_BASE1 + (a))
2006-06-26 10:33:10 +10:00
2005-04-16 15:20:36 -07:00
/*
* These provide the underlying interrupt vector support .
* Unfortunately it is a little different on each ColdFire .
*/
2008-02-01 17:40:26 +10:00
void coldfire_profile_init ( void ) ;
2005-04-16 15:20:36 -07:00
2012-11-05 12:01:38 +10:00
# if defined(CONFIG_M53xx) || defined(CONFIG_M5441x)
2006-12-06 11:36:59 +10:00
# define __raw_readtrr __raw_readl
# define __raw_writetrr __raw_writel
# else
# define __raw_readtrr __raw_readw
# define __raw_writetrr __raw_writew
# endif
2008-02-01 17:40:26 +10:00
static u32 mcftmr_cycles_per_jiffy ;
static u32 mcftmr_cnt ;
2012-01-23 15:34:58 +10:00
static irq_handler_t timer_interrupt ;
2005-04-16 15:20:36 -07:00
/***************************************************************************/
2011-12-24 14:36:27 +10:00
static void init_timer_irq ( void )
{
# ifdef MCFSIM_ICR_AUTOVEC
/* Timer1 is always used as system timer */
writeb ( MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3 ,
2012-08-17 16:48:16 +10:00
MCFSIM_TIMER1ICR ) ;
2011-12-24 14:36:27 +10:00
mcf_mapirq2imr ( MCF_IRQ_TIMER , MCFINTC_TIMER1 ) ;
# ifdef CONFIG_HIGHPROFILE
/* Timer2 is to be used as a high speed profile timer */
writeb ( MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3 ,
2012-08-17 16:48:16 +10:00
MCFSIM_TIMER2ICR ) ;
2011-12-24 14:36:27 +10:00
mcf_mapirq2imr ( MCF_IRQ_PROFILER , MCFINTC_TIMER2 ) ;
# endif
# endif /* MCFSIM_ICR_AUTOVEC */
}
/***************************************************************************/
2008-02-01 17:40:26 +10:00
static irqreturn_t mcftmr_tick ( int irq , void * dummy )
2005-04-16 15:20:36 -07:00
{
/* Reset the ColdFire timer */
2006-06-26 10:33:10 +10:00
__raw_writeb ( MCFTIMER_TER_CAP | MCFTIMER_TER_REF , TA ( MCFTIMER_TER ) ) ;
2007-10-23 14:37:54 +10:00
2008-02-01 17:40:26 +10:00
mcftmr_cnt + = mcftmr_cycles_per_jiffy ;
2012-01-23 15:34:58 +10:00
return timer_interrupt ( irq , dummy ) ;
2005-04-16 15:20:36 -07:00
}
/***************************************************************************/
2008-02-01 17:40:26 +10:00
static struct irqaction mcftmr_timer_irq = {
2007-10-23 14:37:54 +10:00
. name = " timer " ,
2013-09-07 07:43:08 +02:00
. flags = IRQF_TIMER ,
2008-02-01 17:40:26 +10:00
. handler = mcftmr_tick ,
2007-07-27 01:09:00 +10:00
} ;
2007-10-23 14:37:54 +10:00
/***************************************************************************/
2016-12-21 20:32:01 +01:00
static u64 mcftmr_read_clk ( struct clocksource * cs )
2008-02-01 17:40:26 +10:00
{
unsigned long flags ;
u32 cycles ;
u16 tcn ;
local_irq_save ( flags ) ;
tcn = __raw_readw ( TA ( MCFTIMER_TCN ) ) ;
cycles = mcftmr_cnt ;
local_irq_restore ( flags ) ;
return cycles + tcn ;
}
/***************************************************************************/
static struct clocksource mcftmr_clk = {
. name = " tmr " ,
. rating = 250 ,
. read = mcftmr_read_clk ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
/***************************************************************************/
2007-06-08 13:46:39 -07:00
2012-01-23 15:34:58 +10:00
void hw_timer_init ( irq_handler_t handler )
2005-04-16 15:20:36 -07:00
{
2006-06-26 10:33:10 +10:00
__raw_writew ( MCFTIMER_TMR_DISABLE , TA ( MCFTIMER_TMR ) ) ;
2008-02-01 17:40:26 +10:00
mcftmr_cycles_per_jiffy = FREQ / HZ ;
2008-06-12 15:21:36 -07:00
/*
* The coldfire timer runs from 0 to TRR included , then 0
* again and so on . It counts thus actually TRR + 1 steps
* for 1 tick , not TRR . So if you want n cycles ,
* initialize TRR with n - 1.
*/
__raw_writetrr ( mcftmr_cycles_per_jiffy - 1 , TA ( MCFTIMER_TRR ) ) ;
2006-06-26 10:33:10 +10:00
__raw_writew ( MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE , TA ( MCFTIMER_TMR ) ) ;
2005-04-16 15:20:36 -07:00
2010-04-26 20:21:52 -07:00
clocksource_register_hz ( & mcftmr_clk , FREQ ) ;
2008-02-01 17:40:26 +10:00
2012-01-23 15:34:58 +10:00
timer_interrupt = handler ;
2011-12-24 14:36:27 +10:00
init_timer_irq ( ) ;
2009-05-22 13:50:53 +10:00
setup_irq ( MCF_IRQ_TIMER , & mcftmr_timer_irq ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_HIGHPROFILE
coldfire_profile_init ( ) ;
# endif
}
/***************************************************************************/
# ifdef CONFIG_HIGHPROFILE
/***************************************************************************/
2006-06-26 10:33:10 +10:00
/*
* By default use timer2 as the profiler clock timer .
*/
2011-03-09 09:57:14 +10:00
# define PA(a) (MCFTIMER_BASE2 + (a))
2006-06-26 10:33:10 +10:00
2005-04-16 15:20:36 -07:00
/*
* Choose a reasonably fast profile timer . Make it an odd value to
2007-02-17 19:07:33 +01:00
* try and get good coverage of kernel operations .
2005-04-16 15:20:36 -07:00
*/
# define PROFILEHZ 1013
/*
* Use the other timer to provide high accuracy profiling info .
*/
2007-02-07 12:03:01 +10:00
irqreturn_t coldfire_profile_tick ( int irq , void * dummy )
2005-04-16 15:20:36 -07:00
{
/* Reset ColdFire timer2 */
2006-06-26 10:33:10 +10:00
__raw_writeb ( MCFTIMER_TER_CAP | MCFTIMER_TER_REF , PA ( MCFTIMER_TER ) ) ;
2005-04-16 15:20:36 -07:00
if ( current - > pid )
2008-02-14 19:31:27 -08:00
profile_tick ( CPU_PROFILING ) ;
2007-02-07 12:03:01 +10:00
return IRQ_HANDLED ;
2005-04-16 15:20:36 -07:00
}
/***************************************************************************/
2008-02-14 19:31:27 -08:00
static struct irqaction coldfire_profile_irq = {
. name = " profile timer " ,
2013-09-07 07:43:08 +02:00
. flags = IRQF_TIMER ,
2008-02-14 19:31:27 -08:00
. handler = coldfire_profile_tick ,
} ;
2005-04-16 15:20:36 -07:00
void coldfire_profile_init ( void )
{
2008-02-14 19:31:27 -08:00
printk ( KERN_INFO " PROFILE: lodging TIMER2 @ %dHz as profile timer \n " ,
PROFILEHZ ) ;
2005-04-16 15:20:36 -07:00
/* Set up TIMER 2 as high speed profile clock */
2006-06-26 10:33:10 +10:00
__raw_writew ( MCFTIMER_TMR_DISABLE , PA ( MCFTIMER_TMR ) ) ;
2005-04-16 15:20:36 -07:00
2008-02-14 19:31:27 -08:00
__raw_writetrr ( ( ( MCF_BUSCLK / 16 ) / PROFILEHZ ) , PA ( MCFTIMER_TRR ) ) ;
2006-06-26 10:33:10 +10:00
__raw_writew ( MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE , PA ( MCFTIMER_TMR ) ) ;
2005-04-16 15:20:36 -07:00
2009-05-22 13:50:53 +10:00
setup_irq ( MCF_IRQ_PROFILER , & coldfire_profile_irq ) ;
2005-04-16 15:20:36 -07:00
}
/***************************************************************************/
# endif /* CONFIG_HIGHPROFILE */
/***************************************************************************/