2009-03-27 16:25:49 +03:00
/*
2013-08-27 14:02:54 +04:00
* Copyright ( C ) 2007 - 2013 Michal Simek < monstr @ monstr . eu >
* Copyright ( C ) 2012 - 2013 Xilinx , Inc .
2009-03-27 16:25:49 +03:00
* 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/interrupt.h>
# include <linux/delay.h>
# include <linux/sched.h>
# include <linux/clk.h>
# include <linux/clockchips.h>
2013-08-27 13:52:32 +04:00
# include <linux/of_address.h>
2013-09-07 23:05:10 +04:00
# include <linux/of_irq.h>
2009-03-27 16:25:49 +03:00
# include <asm/cpuinfo.h>
2010-06-10 18:04:05 +04:00
# include <linux/cnt32_to_63.h>
2009-03-27 16:25:49 +03:00
2013-08-27 13:52:32 +04:00
static void __iomem * timer_baseaddr ;
2009-03-27 16:25:49 +03:00
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)
2013-08-27 14:04:39 +04:00
static inline void xilinx_timer0_stop ( void )
2009-03-27 16:25:49 +03:00
{
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
}
2013-08-27 14:04:39 +04:00
static inline void xilinx_timer0_start_periodic ( unsigned long load_val )
2009-03-27 16:25:49 +03:00
{
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 ) ;
}
2013-08-27 14:04:39 +04:00
static inline void xilinx_timer0_start_oneshot ( unsigned long load_val )
2009-03-27 16:25:49 +03:00
{
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 ) ;
}
2013-08-27 14:04:39 +04:00
static int xilinx_timer_set_next_event ( unsigned long delta ,
2009-03-27 16:25:49 +03:00
struct clock_event_device * dev )
{
pr_debug ( " %s: next event, delta %x \n " , __func__ , ( u32 ) delta ) ;
2013-08-27 14:04:39 +04:00
xilinx_timer0_start_oneshot ( delta ) ;
2009-03-27 16:25:49 +03:00
return 0 ;
}
2013-08-27 14:04:39 +04:00
static void xilinx_timer_set_mode ( enum clock_event_mode mode ,
2009-03-27 16:25:49 +03:00
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__ ) ;
2013-08-27 14:04:39 +04:00
xilinx_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__ ) ;
2013-08-27 14:04:39 +04:00
xilinx_timer0_stop ( ) ;
2009-03-27 16:25:49 +03:00
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 ;
}
}
2013-08-27 14:04:39 +04:00
static struct clock_event_device clockevent_xilinx_timer = {
. name = " xilinx_clockevent " ,
2009-03-27 16:25:49 +03:00
. 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 ,
2013-08-27 14:04:39 +04:00
. set_next_event = xilinx_timer_set_next_event ,
. set_mode = xilinx_timer_set_mode ,
2009-03-27 16:25:49 +03:00
} ;
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 )
{
2013-08-27 14:04:39 +04:00
struct clock_event_device * evt = & clockevent_xilinx_timer ;
2009-03-27 16:25:49 +03:00
# 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 " ,
2013-08-27 14:04:39 +04:00
. dev_id = & clockevent_xilinx_timer ,
2009-03-27 16:25:49 +03:00
} ;
2013-08-27 14:04:39 +04:00
static __init void xilinx_clockevent_init ( void )
2009-03-27 16:25:49 +03:00
{
2013-08-27 14:04:39 +04:00
clockevent_xilinx_timer . mult =
2010-10-07 11:39:21 +04:00
div_sc ( timer_clock_freq , NSEC_PER_SEC ,
2013-08-27 14:04:39 +04:00
clockevent_xilinx_timer . shift ) ;
clockevent_xilinx_timer . max_delta_ns =
clockevent_delta2ns ( ( u32 ) ~ 0 , & clockevent_xilinx_timer ) ;
clockevent_xilinx_timer . min_delta_ns =
clockevent_delta2ns ( 1 , & clockevent_xilinx_timer ) ;
clockevent_xilinx_timer . cpumask = cpumask_of ( 0 ) ;
clockevents_register_device ( & clockevent_xilinx_timer ) ;
2009-03-27 16:25:49 +03:00
}
2013-08-27 14:04:39 +04:00
static cycle_t xilinx_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
}
2013-08-27 14:04:39 +04:00
static struct timecounter xilinx_tc = {
2009-11-06 14:31:00 +03:00
. cc = NULL ,
} ;
2013-08-27 14:04:39 +04:00
static cycle_t xilinx_cc_read ( const struct cyclecounter * cc )
2009-11-06 14:31:00 +03:00
{
2013-08-27 14:04:39 +04:00
return xilinx_read ( NULL ) ;
2009-11-06 14:31:00 +03:00
}
2013-08-27 14:04:39 +04:00
static struct cyclecounter xilinx_cc = {
. read = xilinx_cc_read ,
2009-11-06 14:31:00 +03:00
. mask = CLOCKSOURCE_MASK ( 32 ) ,
2010-06-10 18:04:05 +04:00
. shift = 8 ,
2009-11-06 14:31:00 +03:00
} ;
2013-08-27 14:04:39 +04:00
static int __init init_xilinx_timecounter ( void )
2009-11-06 14:31:00 +03:00
{
2013-08-27 14:04:39 +04:00
xilinx_cc . mult = div_sc ( timer_clock_freq , NSEC_PER_SEC ,
xilinx_cc . shift ) ;
2009-11-06 14:31:00 +03:00
2013-08-27 14:04:39 +04:00
timecounter_init ( & xilinx_tc , & xilinx_cc , sched_clock ( ) ) ;
2009-11-06 14:31:00 +03:00
return 0 ;
}
2009-03-27 16:25:49 +03:00
static struct clocksource clocksource_microblaze = {
2013-08-27 14:04:39 +04:00
. name = " xilinx_clocksource " ,
2009-03-27 16:25:49 +03:00
. rating = 300 ,
2013-08-27 14:04:39 +04:00
. read = xilinx_read ,
2009-03-27 16:25:49 +03:00
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2013-08-27 14:04:39 +04:00
static int __init xilinx_clocksource_init ( void )
2009-03-27 16:25:49 +03:00
{
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 */
2013-08-27 14:04:39 +04:00
init_xilinx_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 ;
2013-08-27 13:52:32 +04:00
int ret ;
timer_baseaddr = of_iomap ( timer , 0 ) ;
if ( ! timer_baseaddr ) {
pr_err ( " ERROR: invalid timer base address \n " ) ;
BUG ( ) ;
}
2013-08-27 11:57:52 +04:00
2011-12-09 13:46:52 +04:00
irq = irq_of_parse_and_map ( timer , 0 ) ;
2013-08-27 13:52:32 +04:00
of_property_read_u32 ( timer , " xlnx,one-timer-only " , & timer_num ) ;
2009-03-27 16:25:49 +03:00
if ( timer_num ) {
2013-08-27 13:52:32 +04:00
pr_emerg ( " Please enable two timers in HW \n " ) ;
2009-03-27 16:25:49 +03:00
BUG ( ) ;
}
2013-08-27 13:52:32 +04:00
pr_info ( " %s: irq=%d \n " , timer - > full_name , 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 */
2013-08-27 13:52:32 +04:00
ret = of_property_read_u32 ( timer , " clock-frequency " , & timer_clock_freq ) ;
if ( ret < 0 )
2010-10-07 11:39:21 +04:00
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
2013-08-27 14:04:39 +04:00
xilinx_clocksource_init ( ) ;
xilinx_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 ) ;