2009-03-27 16:25:49 +03:00
/*
* Copyright ( C ) 2007 - 2009 Michal Simek < monstr @ monstr . eu >
* Copyright ( C ) 2007 - 2009 PetaLogix
* Copyright ( C ) 2006 Atmark Techno , Inc .
*
* 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 .
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/param.h>
# include <linux/interrupt.h>
# include <linux/profile.h>
# include <linux/irq.h>
# include <linux/delay.h>
# include <linux/sched.h>
# include <linux/spinlock.h>
# include <linux/err.h>
# include <linux/clk.h>
# include <linux/clocksource.h>
# include <linux/clockchips.h>
# include <linux/io.h>
2009-07-29 16:08:40 +04:00
# include <linux/bug.h>
2009-03-27 16:25:49 +03:00
# include <asm/cpuinfo.h>
# include <asm/setup.h>
# include <asm/prom.h>
# include <asm/irq.h>
2010-06-10 18:04:05 +04:00
# include <linux/cnt32_to_63.h>
2009-03-27 16:25:49 +03:00
static unsigned int timer_baseaddr ;
2011-02-07 13:33:47 +03:00
static unsigned int freq_div_hz ;
static unsigned int timer_clock_freq ;
2010-10-07 11:39:21 +04:00
2009-03-27 16:25:49 +03:00
# define TCSR0 (0x00)
# define TLR0 (0x04)
# define TCR0 (0x08)
# define TCSR1 (0x10)
# define TLR1 (0x14)
# define TCR1 (0x18)
# define TCSR_MDT (1<<0)
# define TCSR_UDT (1<<1)
# define TCSR_GENT (1<<2)
# define TCSR_CAPT (1<<3)
# define TCSR_ARHT (1<<4)
# define TCSR_LOAD (1<<5)
# define TCSR_ENIT (1<<6)
# define TCSR_ENT (1<<7)
# define TCSR_TINT (1<<8)
# define TCSR_PWMA (1<<9)
# define TCSR_ENALL (1<<10)
static inline void microblaze_timer0_stop ( void )
{
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR0 ,
in_be32 ( timer_baseaddr + TCSR0 ) & ~ TCSR_ENT ) ;
2009-03-27 16:25:49 +03:00
}
static inline void microblaze_timer0_start_periodic ( unsigned long load_val )
{
if ( ! load_val )
load_val = 1 ;
2013-08-27 11:57:52 +04:00
/* loading value to timer reg */
out_be32 ( timer_baseaddr + TLR0 , load_val ) ;
2009-03-27 16:25:49 +03:00
/* load the initial value */
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR0 , TCSR_LOAD ) ;
2009-03-27 16:25:49 +03:00
/* see timer data sheet for detail
* ! ENALL - don ' t enable ' em all
* ! PWMA - disable pwm
* TINT - clear interrupt status
* ENT - enable timer itself
2011-04-05 17:49:22 +04:00
* ENIT - enable interrupt
2009-03-27 16:25:49 +03:00
* ! LOAD - clear the bit to let go
* ARHT - auto reload
* ! CAPT - no external trigger
* ! GENT - no external signal
* UDT - set the timer as down counter
* ! MDT0 - generate mode
*/
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR0 ,
2009-03-27 16:25:49 +03:00
TCSR_TINT | TCSR_ENIT | TCSR_ENT | TCSR_ARHT | TCSR_UDT ) ;
}
static inline void microblaze_timer0_start_oneshot ( unsigned long load_val )
{
if ( ! load_val )
load_val = 1 ;
2013-08-27 11:57:52 +04:00
/* loading value to timer reg */
out_be32 ( timer_baseaddr + TLR0 , load_val ) ;
2009-03-27 16:25:49 +03:00
/* load the initial value */
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR0 , TCSR_LOAD ) ;
2009-03-27 16:25:49 +03:00
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR0 ,
2009-03-27 16:25:49 +03:00
TCSR_TINT | TCSR_ENIT | TCSR_ENT | TCSR_ARHT | TCSR_UDT ) ;
}
static int microblaze_timer_set_next_event ( unsigned long delta ,
struct clock_event_device * dev )
{
pr_debug ( " %s: next event, delta %x \n " , __func__ , ( u32 ) delta ) ;
microblaze_timer0_start_oneshot ( delta ) ;
return 0 ;
}
static void microblaze_timer_set_mode ( enum clock_event_mode mode ,
struct clock_event_device * evt )
{
switch ( mode ) {
case CLOCK_EVT_MODE_PERIODIC :
2012-10-04 16:24:58 +04:00
pr_info ( " %s: periodic \n " , __func__ ) ;
2010-10-07 11:39:21 +04:00
microblaze_timer0_start_periodic ( freq_div_hz ) ;
2009-03-27 16:25:49 +03:00
break ;
case CLOCK_EVT_MODE_ONESHOT :
2012-10-04 16:24:58 +04:00
pr_info ( " %s: oneshot \n " , __func__ ) ;
2009-03-27 16:25:49 +03:00
break ;
case CLOCK_EVT_MODE_UNUSED :
2012-10-04 16:24:58 +04:00
pr_info ( " %s: unused \n " , __func__ ) ;
2009-03-27 16:25:49 +03:00
break ;
case CLOCK_EVT_MODE_SHUTDOWN :
2012-10-04 16:24:58 +04:00
pr_info ( " %s: shutdown \n " , __func__ ) ;
2009-03-27 16:25:49 +03:00
microblaze_timer0_stop ( ) ;
break ;
case CLOCK_EVT_MODE_RESUME :
2012-10-04 16:24:58 +04:00
pr_info ( " %s: resume \n " , __func__ ) ;
2009-03-27 16:25:49 +03:00
break ;
}
}
static struct clock_event_device clockevent_microblaze_timer = {
. name = " microblaze_clockevent " ,
. features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC ,
2010-06-10 18:04:05 +04:00
. shift = 8 ,
2009-03-27 16:25:49 +03:00
. rating = 300 ,
. set_next_event = microblaze_timer_set_next_event ,
. set_mode = microblaze_timer_set_mode ,
} ;
static inline void timer_ack ( void )
{
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR0 , in_be32 ( timer_baseaddr + TCSR0 ) ) ;
2009-03-27 16:25:49 +03:00
}
static irqreturn_t timer_interrupt ( int irq , void * dev_id )
{
struct clock_event_device * evt = & clockevent_microblaze_timer ;
# ifdef CONFIG_HEART_BEAT
heartbeat ( ) ;
# endif
timer_ack ( ) ;
evt - > event_handler ( evt ) ;
return IRQ_HANDLED ;
}
static struct irqaction timer_irqaction = {
. handler = timer_interrupt ,
. flags = IRQF_DISABLED | IRQF_TIMER ,
. name = " timer " ,
. dev_id = & clockevent_microblaze_timer ,
} ;
static __init void microblaze_clockevent_init ( void )
{
clockevent_microblaze_timer . mult =
2010-10-07 11:39:21 +04:00
div_sc ( timer_clock_freq , NSEC_PER_SEC ,
2009-03-27 16:25:49 +03:00
clockevent_microblaze_timer . shift ) ;
clockevent_microblaze_timer . max_delta_ns =
clockevent_delta2ns ( ( u32 ) ~ 0 , & clockevent_microblaze_timer ) ;
clockevent_microblaze_timer . min_delta_ns =
clockevent_delta2ns ( 1 , & clockevent_microblaze_timer ) ;
clockevent_microblaze_timer . cpumask = cpumask_of ( 0 ) ;
clockevents_register_device ( & clockevent_microblaze_timer ) ;
}
2009-04-22 23:05:31 +04:00
static cycle_t microblaze_read ( struct clocksource * cs )
2009-03-27 16:25:49 +03:00
{
/* reading actual value of timer 1 */
2013-08-27 11:57:52 +04:00
return ( cycle_t ) ( in_be32 ( timer_baseaddr + TCR1 ) ) ;
2009-03-27 16:25:49 +03:00
}
2009-11-06 14:31:00 +03:00
static struct timecounter microblaze_tc = {
. cc = NULL ,
} ;
static cycle_t microblaze_cc_read ( const struct cyclecounter * cc )
{
return microblaze_read ( NULL ) ;
}
static struct cyclecounter microblaze_cc = {
. read = microblaze_cc_read ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
2010-06-10 18:04:05 +04:00
. shift = 8 ,
2009-11-06 14:31:00 +03:00
} ;
2011-02-07 13:33:47 +03:00
static int __init init_microblaze_timecounter ( void )
2009-11-06 14:31:00 +03:00
{
2010-10-07 11:39:21 +04:00
microblaze_cc . mult = div_sc ( timer_clock_freq , NSEC_PER_SEC ,
2009-11-06 14:31:00 +03:00
microblaze_cc . shift ) ;
timecounter_init ( & microblaze_tc , & microblaze_cc , sched_clock ( ) ) ;
return 0 ;
}
2009-03-27 16:25:49 +03:00
static struct clocksource clocksource_microblaze = {
. name = " microblaze_clocksource " ,
. rating = 300 ,
. read = microblaze_read ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
static int __init microblaze_clocksource_init ( void )
{
2010-04-27 07:22:23 +04:00
if ( clocksource_register_hz ( & clocksource_microblaze , timer_clock_freq ) )
2009-03-27 16:25:49 +03:00
panic ( " failed to register clocksource " ) ;
/* stop timer1 */
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR1 ,
in_be32 ( timer_baseaddr + TCSR1 ) & ~ TCSR_ENT ) ;
2009-03-27 16:25:49 +03:00
/* start timer1 - up counting without interrupt */
2013-08-27 11:57:52 +04:00
out_be32 ( timer_baseaddr + TCSR1 , TCSR_TINT | TCSR_ENT | TCSR_ARHT ) ;
2009-11-06 14:31:00 +03:00
/* register timecounter - for ftrace support */
init_microblaze_timecounter ( ) ;
2009-03-27 16:25:49 +03:00
return 0 ;
}
2010-04-16 11:50:13 +04:00
/*
* We have to protect accesses before timer initialization
* and return 0 for sched_clock function below .
*/
static int timer_initialized ;
2013-08-27 13:13:29 +04:00
static void __init xilinx_timer_init ( struct device_node * timer )
2009-03-27 16:25:49 +03:00
{
2011-12-09 15:26:16 +04:00
u32 irq ;
2009-03-27 16:25:49 +03:00
u32 timer_num = 1 ;
2010-10-07 11:39:21 +04:00
const void * prop ;
2013-08-27 11:57:52 +04:00
2010-09-28 10:04:14 +04:00
timer_baseaddr = be32_to_cpup ( of_get_property ( timer , " reg " , NULL ) ) ;
2009-03-27 16:25:49 +03:00
timer_baseaddr = ( unsigned long ) ioremap ( timer_baseaddr , PAGE_SIZE ) ;
2011-12-09 13:46:52 +04:00
irq = irq_of_parse_and_map ( timer , 0 ) ;
2010-09-28 10:04:14 +04:00
timer_num = be32_to_cpup ( of_get_property ( timer ,
" xlnx,one-timer-only " , NULL ) ) ;
2009-03-27 16:25:49 +03:00
if ( timer_num ) {
2012-10-04 16:24:58 +04:00
pr_emerg ( " Please enable two timers in HW \n " ) ;
2009-03-27 16:25:49 +03:00
BUG ( ) ;
}
2012-10-04 16:24:58 +04:00
pr_info ( " %s #0 at 0x%08x, irq=%d \n " ,
2011-11-07 16:42:12 +04:00
timer - > name , timer_baseaddr , irq ) ;
2009-03-27 16:25:49 +03:00
2010-10-07 11:39:21 +04:00
/* If there is clock-frequency property than use it */
prop = of_get_property ( timer , " clock-frequency " , NULL ) ;
if ( prop )
timer_clock_freq = be32_to_cpup ( prop ) ;
else
timer_clock_freq = cpuinfo . cpu_clock_freq ;
freq_div_hz = timer_clock_freq / HZ ;
2009-03-27 16:25:49 +03:00
setup_irq ( irq , & timer_irqaction ) ;
# ifdef CONFIG_HEART_BEAT
setup_heartbeat ( ) ;
# endif
microblaze_clocksource_init ( ) ;
microblaze_clockevent_init ( ) ;
2010-04-16 11:50:13 +04:00
timer_initialized = 1 ;
}
unsigned long long notrace sched_clock ( void )
{
if ( timer_initialized ) {
struct clocksource * cs = & clocksource_microblaze ;
2011-09-23 11:52:24 +04:00
cycle_t cyc = cnt32_to_63 ( cs - > read ( NULL ) ) & LLONG_MAX ;
2010-04-16 11:50:13 +04:00
return clocksource_cyc2ns ( cyc , cs - > mult , cs - > shift ) ;
}
return 0 ;
2009-03-27 16:25:49 +03:00
}
2013-08-27 13:13:29 +04:00
CLOCKSOURCE_OF_DECLARE ( xilinx_timer , " xlnx,xps-timer-1.00.a " ,
xilinx_timer_init ) ;