2012-01-11 17:25:17 +00:00
/*
* linux / arch / arm / kernel / arch_timer . c
*
* Copyright ( C ) 2011 ARM Ltd .
* All Rights Reserved
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/smp.h>
# include <linux/cpu.h>
# include <linux/jiffies.h>
# include <linux/clockchips.h>
# include <linux/interrupt.h>
2012-01-19 13:53:50 +00:00
# include <linux/of_irq.h>
2012-01-11 17:25:17 +00:00
# include <linux/io.h>
# include <asm/cputype.h>
# include <asm/localtimer.h>
# include <asm/arch_timer.h>
# include <asm/system_info.h>
2011-01-14 15:32:36 +00:00
# include <asm/sched_clock.h>
2012-01-11 17:25:17 +00:00
static unsigned long arch_timer_rate ;
2012-09-07 18:09:57 +01:00
enum ppi_nr {
PHYS_SECURE_PPI ,
PHYS_NONSECURE_PPI ,
VIRT_PPI ,
HYP_PPI ,
MAX_TIMER_PPI
} ;
static int arch_timer_ppi [ MAX_TIMER_PPI ] ;
2012-01-11 17:25:17 +00:00
static struct clock_event_device __percpu * * arch_timer_evt ;
2012-07-06 15:47:17 +01:00
extern void init_current_timer_delay ( unsigned long freq ) ;
2012-09-07 18:09:57 +01:00
static bool arch_timer_use_virtual = true ;
2012-01-11 17:25:17 +00:00
/*
* Architected system timer support .
*/
# define ARCH_TIMER_CTRL_ENABLE (1 << 0)
# define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
# define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
# define ARCH_TIMER_REG_CTRL 0
# define ARCH_TIMER_REG_FREQ 1
# define ARCH_TIMER_REG_TVAL 2
2012-09-07 18:09:57 +01:00
# define ARCH_TIMER_PHYS_ACCESS 0
# define ARCH_TIMER_VIRT_ACCESS 1
/*
* These register accessors are marked inline so the compiler can
* nicely work out which register we want , and chuck away the rest of
* the code . At least it does so with a recent GCC ( 4.6 .3 ) .
*/
static inline void arch_timer_reg_write ( const int access , const int reg , u32 val )
2012-01-11 17:25:17 +00:00
{
2012-09-07 18:09:57 +01:00
if ( access = = ARCH_TIMER_PHYS_ACCESS ) {
switch ( reg ) {
case ARCH_TIMER_REG_CTRL :
asm volatile ( " mcr p15, 0, %0, c14, c2, 1 " : : " r " ( val ) ) ;
break ;
case ARCH_TIMER_REG_TVAL :
asm volatile ( " mcr p15, 0, %0, c14, c2, 0 " : : " r " ( val ) ) ;
break ;
}
}
if ( access = = ARCH_TIMER_VIRT_ACCESS ) {
switch ( reg ) {
case ARCH_TIMER_REG_CTRL :
asm volatile ( " mcr p15, 0, %0, c14, c3, 1 " : : " r " ( val ) ) ;
break ;
case ARCH_TIMER_REG_TVAL :
asm volatile ( " mcr p15, 0, %0, c14, c3, 0 " : : " r " ( val ) ) ;
break ;
}
2012-01-11 17:25:17 +00:00
}
isb ( ) ;
}
2012-09-07 18:09:57 +01:00
static inline u32 arch_timer_reg_read ( const int access , const int reg )
2012-01-11 17:25:17 +00:00
{
2012-09-07 18:09:57 +01:00
u32 val = 0 ;
if ( access = = ARCH_TIMER_PHYS_ACCESS ) {
switch ( reg ) {
case ARCH_TIMER_REG_CTRL :
asm volatile ( " mrc p15, 0, %0, c14, c2, 1 " : " =r " ( val ) ) ;
break ;
case ARCH_TIMER_REG_TVAL :
asm volatile ( " mrc p15, 0, %0, c14, c2, 0 " : " =r " ( val ) ) ;
break ;
case ARCH_TIMER_REG_FREQ :
asm volatile ( " mrc p15, 0, %0, c14, c0, 0 " : " =r " ( val ) ) ;
break ;
}
}
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
if ( access = = ARCH_TIMER_VIRT_ACCESS ) {
switch ( reg ) {
case ARCH_TIMER_REG_CTRL :
asm volatile ( " mrc p15, 0, %0, c14, c3, 1 " : " =r " ( val ) ) ;
break ;
case ARCH_TIMER_REG_TVAL :
asm volatile ( " mrc p15, 0, %0, c14, c3, 0 " : " =r " ( val ) ) ;
break ;
}
2012-01-11 17:25:17 +00:00
}
return val ;
}
2012-09-07 18:09:57 +01:00
static inline cycle_t arch_timer_counter_read ( const int access )
2012-01-11 17:25:17 +00:00
{
2012-09-07 18:09:57 +01:00
cycle_t cval = 0 ;
if ( access = = ARCH_TIMER_PHYS_ACCESS )
asm volatile ( " mrrc p15, 0, %Q0, %R0, c14 " : " =r " ( cval ) ) ;
if ( access = = ARCH_TIMER_VIRT_ACCESS )
asm volatile ( " mrrc p15, 1, %Q0, %R0, c14 " : " =r " ( cval ) ) ;
return cval ;
}
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
static inline cycle_t arch_counter_get_cntpct ( void )
{
return arch_timer_counter_read ( ARCH_TIMER_PHYS_ACCESS ) ;
}
static inline cycle_t arch_counter_get_cntvct ( void )
{
return arch_timer_counter_read ( ARCH_TIMER_VIRT_ACCESS ) ;
}
static irqreturn_t inline timer_handler ( const int access ,
struct clock_event_device * evt )
{
unsigned long ctrl ;
ctrl = arch_timer_reg_read ( access , ARCH_TIMER_REG_CTRL ) ;
2012-01-11 17:25:17 +00:00
if ( ctrl & ARCH_TIMER_CTRL_IT_STAT ) {
ctrl | = ARCH_TIMER_CTRL_IT_MASK ;
2012-09-07 18:09:57 +01:00
arch_timer_reg_write ( access , ARCH_TIMER_REG_CTRL , ctrl ) ;
2012-01-11 17:25:17 +00:00
evt - > event_handler ( evt ) ;
return IRQ_HANDLED ;
}
return IRQ_NONE ;
}
2012-09-07 18:09:57 +01:00
static irqreturn_t arch_timer_handler_virt ( int irq , void * dev_id )
2012-01-11 17:25:17 +00:00
{
2012-09-07 18:09:57 +01:00
struct clock_event_device * evt = * ( struct clock_event_device * * ) dev_id ;
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
return timer_handler ( ARCH_TIMER_VIRT_ACCESS , evt ) ;
2012-01-11 17:25:17 +00:00
}
2012-09-07 18:09:57 +01:00
static irqreturn_t arch_timer_handler_phys ( int irq , void * dev_id )
2012-01-11 17:25:17 +00:00
{
2012-09-07 18:09:57 +01:00
struct clock_event_device * evt = * ( struct clock_event_device * * ) dev_id ;
return timer_handler ( ARCH_TIMER_PHYS_ACCESS , evt ) ;
}
static inline void timer_set_mode ( const int access , int mode )
{
unsigned long ctrl ;
2012-01-11 17:25:17 +00:00
switch ( mode ) {
case CLOCK_EVT_MODE_UNUSED :
case CLOCK_EVT_MODE_SHUTDOWN :
2012-09-07 18:09:57 +01:00
ctrl = arch_timer_reg_read ( access , ARCH_TIMER_REG_CTRL ) ;
ctrl & = ~ ARCH_TIMER_CTRL_ENABLE ;
arch_timer_reg_write ( access , ARCH_TIMER_REG_CTRL , ctrl ) ;
2012-01-11 17:25:17 +00:00
break ;
default :
break ;
}
}
2012-09-07 18:09:57 +01:00
static void arch_timer_set_mode_virt ( enum clock_event_mode mode ,
struct clock_event_device * clk )
2012-01-11 17:25:17 +00:00
{
2012-09-07 18:09:57 +01:00
timer_set_mode ( ARCH_TIMER_VIRT_ACCESS , mode ) ;
}
static void arch_timer_set_mode_phys ( enum clock_event_mode mode ,
struct clock_event_device * clk )
{
timer_set_mode ( ARCH_TIMER_PHYS_ACCESS , mode ) ;
}
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
static inline void set_next_event ( const int access , unsigned long evt )
{
unsigned long ctrl ;
ctrl = arch_timer_reg_read ( access , ARCH_TIMER_REG_CTRL ) ;
2012-01-11 17:25:17 +00:00
ctrl | = ARCH_TIMER_CTRL_ENABLE ;
ctrl & = ~ ARCH_TIMER_CTRL_IT_MASK ;
2012-09-07 18:09:57 +01:00
arch_timer_reg_write ( access , ARCH_TIMER_REG_TVAL , evt ) ;
arch_timer_reg_write ( access , ARCH_TIMER_REG_CTRL , ctrl ) ;
}
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
static int arch_timer_set_next_event_virt ( unsigned long evt ,
struct clock_event_device * unused )
{
set_next_event ( ARCH_TIMER_VIRT_ACCESS , evt ) ;
return 0 ;
}
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
static int arch_timer_set_next_event_phys ( unsigned long evt ,
struct clock_event_device * unused )
{
set_next_event ( ARCH_TIMER_PHYS_ACCESS , evt ) ;
2012-01-11 17:25:17 +00:00
return 0 ;
}
static int __cpuinit arch_timer_setup ( struct clock_event_device * clk )
{
2012-07-06 11:06:49 +01:00
clk - > features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP ;
2012-01-11 17:25:17 +00:00
clk - > name = " arch_sys_timer " ;
clk - > rating = 450 ;
2012-09-07 18:09:57 +01:00
if ( arch_timer_use_virtual ) {
clk - > irq = arch_timer_ppi [ VIRT_PPI ] ;
clk - > set_mode = arch_timer_set_mode_virt ;
clk - > set_next_event = arch_timer_set_next_event_virt ;
} else {
clk - > irq = arch_timer_ppi [ PHYS_SECURE_PPI ] ;
clk - > set_mode = arch_timer_set_mode_phys ;
clk - > set_next_event = arch_timer_set_next_event_phys ;
}
clk - > set_mode ( CLOCK_EVT_MODE_SHUTDOWN , NULL ) ;
2012-01-11 17:25:17 +00:00
clockevents_config_and_register ( clk , arch_timer_rate ,
0xf , 0x7fffffff ) ;
* __this_cpu_ptr ( arch_timer_evt ) = clk ;
2012-09-07 18:09:57 +01:00
if ( arch_timer_use_virtual )
enable_percpu_irq ( arch_timer_ppi [ VIRT_PPI ] , 0 ) ;
else {
enable_percpu_irq ( arch_timer_ppi [ PHYS_SECURE_PPI ] , 0 ) ;
if ( arch_timer_ppi [ PHYS_NONSECURE_PPI ] )
enable_percpu_irq ( arch_timer_ppi [ PHYS_NONSECURE_PPI ] , 0 ) ;
}
2012-01-11 17:25:17 +00:00
return 0 ;
}
/* Is the optional system timer available? */
static int local_timer_is_architected ( void )
{
return ( cpu_architecture ( ) > = CPU_ARCH_ARMv7 ) & &
( ( read_cpuid_ext ( CPUID_EXT_PFR1 ) > > 16 ) & 0xf ) = = 1 ;
}
static int arch_timer_available ( void )
{
unsigned long freq ;
if ( ! local_timer_is_architected ( ) )
return - ENXIO ;
if ( arch_timer_rate = = 0 ) {
2012-09-07 18:09:57 +01:00
freq = arch_timer_reg_read ( ARCH_TIMER_PHYS_ACCESS ,
ARCH_TIMER_REG_FREQ ) ;
2012-01-11 17:25:17 +00:00
/* Check the timer frequency. */
if ( freq = = 0 ) {
pr_warn ( " Architected timer frequency not available \n " ) ;
return - EINVAL ;
}
arch_timer_rate = freq ;
}
2012-09-07 18:09:57 +01:00
pr_info_once ( " Architected local timer running at %lu.%02luMHz (%s). \n " ,
arch_timer_rate / 1000000 , ( arch_timer_rate / 10000 ) % 100 ,
arch_timer_use_virtual ? " virt " : " phys " ) ;
2012-01-11 17:25:17 +00:00
return 0 ;
}
2012-09-07 18:09:57 +01:00
static u32 notrace arch_counter_get_cntpct32 ( void )
2012-01-11 17:25:17 +00:00
{
2012-09-07 18:09:57 +01:00
cycle_t cnt = arch_counter_get_cntpct ( ) ;
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
/*
* The sched_clock infrastructure only knows about counters
* with at most 32 bits . Forget about the upper 24 bits for the
* time being . . .
*/
return ( u32 ) cnt ;
2012-01-11 17:25:17 +00:00
}
2011-01-14 15:32:36 +00:00
static u32 notrace arch_counter_get_cntvct32 ( void )
{
2012-09-07 18:09:57 +01:00
cycle_t cnt = arch_counter_get_cntvct ( ) ;
2011-01-14 15:32:36 +00:00
/*
* The sched_clock infrastructure only knows about counters
* with at most 32 bits . Forget about the upper 24 bits for the
* time being . . .
*/
2012-09-07 18:09:57 +01:00
return ( u32 ) cnt ;
2011-01-14 15:32:36 +00:00
}
2012-01-11 17:25:17 +00:00
static cycle_t arch_counter_read ( struct clocksource * cs )
{
2012-09-07 18:09:57 +01:00
/*
* Always use the physical counter for the clocksource .
* CNTHCTL . PL1PCTEN must be set to 1.
*/
2012-01-11 17:25:17 +00:00
return arch_counter_get_cntpct ( ) ;
}
2012-07-06 15:46:45 +01:00
int read_current_timer ( unsigned long * timer_val )
{
if ( ! arch_timer_rate )
return - ENXIO ;
* timer_val = arch_counter_get_cntpct ( ) ;
return 0 ;
}
2012-09-07 18:09:58 +01:00
static cycle_t arch_counter_read_cc ( const struct cyclecounter * cc )
{
/*
* Always use the physical counter for the clocksource .
* CNTHCTL . PL1PCTEN must be set to 1.
*/
return arch_counter_get_cntpct ( ) ;
}
2012-01-11 17:25:17 +00:00
static struct clocksource clocksource_counter = {
. name = " arch_sys_counter " ,
. rating = 400 ,
. read = arch_counter_read ,
. mask = CLOCKSOURCE_MASK ( 56 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2012-09-07 18:09:58 +01:00
static struct cyclecounter cyclecounter = {
. read = arch_counter_read_cc ,
. mask = CLOCKSOURCE_MASK ( 56 ) ,
} ;
static struct timecounter timecounter ;
struct timecounter * arch_timer_get_timecounter ( void )
{
return & timecounter ;
}
2012-01-11 17:25:17 +00:00
static void __cpuinit arch_timer_stop ( struct clock_event_device * clk )
{
pr_debug ( " arch_timer_teardown disable IRQ%d cpu #%d \n " ,
clk - > irq , smp_processor_id ( ) ) ;
2012-09-07 18:09:57 +01:00
if ( arch_timer_use_virtual )
disable_percpu_irq ( arch_timer_ppi [ VIRT_PPI ] ) ;
else {
disable_percpu_irq ( arch_timer_ppi [ PHYS_SECURE_PPI ] ) ;
if ( arch_timer_ppi [ PHYS_NONSECURE_PPI ] )
disable_percpu_irq ( arch_timer_ppi [ PHYS_NONSECURE_PPI ] ) ;
}
clk - > set_mode ( CLOCK_EVT_MODE_UNUSED , clk ) ;
2012-01-11 17:25:17 +00:00
}
static struct local_timer_ops arch_timer_ops __cpuinitdata = {
. setup = arch_timer_setup ,
. stop = arch_timer_stop ,
} ;
2012-01-20 10:47:00 +00:00
static struct clock_event_device arch_timer_global_evt ;
2012-04-27 13:18:42 +01:00
static int __init arch_timer_register ( void )
2012-01-11 17:25:17 +00:00
{
int err ;
2012-09-07 18:09:57 +01:00
int ppi ;
2012-01-11 17:25:17 +00:00
err = arch_timer_available ( ) ;
if ( err )
2012-09-07 18:09:57 +01:00
goto out ;
2012-01-11 17:25:17 +00:00
arch_timer_evt = alloc_percpu ( struct clock_event_device * ) ;
2012-09-07 18:09:57 +01:00
if ( ! arch_timer_evt ) {
err = - ENOMEM ;
goto out ;
}
2012-01-11 17:25:17 +00:00
clocksource_register_hz ( & clocksource_counter , arch_timer_rate ) ;
2012-09-07 18:09:58 +01:00
cyclecounter . mult = clocksource_counter . mult ;
cyclecounter . shift = clocksource_counter . shift ;
timecounter_init ( & timecounter , & cyclecounter ,
arch_counter_get_cntpct ( ) ) ;
2012-01-11 17:25:17 +00:00
2012-09-07 18:09:57 +01:00
if ( arch_timer_use_virtual ) {
ppi = arch_timer_ppi [ VIRT_PPI ] ;
err = request_percpu_irq ( ppi , arch_timer_handler_virt ,
" arch_timer " , arch_timer_evt ) ;
} else {
ppi = arch_timer_ppi [ PHYS_SECURE_PPI ] ;
err = request_percpu_irq ( ppi , arch_timer_handler_phys ,
" arch_timer " , arch_timer_evt ) ;
if ( ! err & & arch_timer_ppi [ PHYS_NONSECURE_PPI ] ) {
ppi = arch_timer_ppi [ PHYS_NONSECURE_PPI ] ;
err = request_percpu_irq ( ppi , arch_timer_handler_phys ,
" arch_timer " , arch_timer_evt ) ;
if ( err )
free_percpu_irq ( arch_timer_ppi [ PHYS_SECURE_PPI ] ,
arch_timer_evt ) ;
}
}
2012-01-11 17:25:17 +00:00
if ( err ) {
pr_err ( " arch_timer: can't register interrupt %d (%d) \n " ,
2012-09-07 18:09:57 +01:00
ppi , err ) ;
2012-01-11 17:25:17 +00:00
goto out_free ;
}
err = local_timer_register ( & arch_timer_ops ) ;
2012-01-20 10:47:00 +00:00
if ( err ) {
/*
* We couldn ' t register as a local timer ( could be
* because we ' re on a UP platform , or because some
* other local timer is already present . . . ) . Try as a
* global timer instead .
*/
arch_timer_global_evt . cpumask = cpumask_of ( 0 ) ;
err = arch_timer_setup ( & arch_timer_global_evt ) ;
}
2012-01-11 17:25:17 +00:00
if ( err )
goto out_free_irq ;
2012-07-06 15:47:17 +01:00
init_current_timer_delay ( arch_timer_rate ) ;
2012-01-11 17:25:17 +00:00
return 0 ;
out_free_irq :
2012-09-07 18:09:57 +01:00
if ( arch_timer_use_virtual )
free_percpu_irq ( arch_timer_ppi [ VIRT_PPI ] , arch_timer_evt ) ;
else {
free_percpu_irq ( arch_timer_ppi [ PHYS_SECURE_PPI ] ,
arch_timer_evt ) ;
if ( arch_timer_ppi [ PHYS_NONSECURE_PPI ] )
free_percpu_irq ( arch_timer_ppi [ PHYS_NONSECURE_PPI ] ,
arch_timer_evt ) ;
}
2012-01-11 17:25:17 +00:00
out_free :
free_percpu ( arch_timer_evt ) ;
2012-09-07 18:09:57 +01:00
out :
2012-01-11 17:25:17 +00:00
return err ;
}
2011-01-14 15:32:36 +00:00
2012-01-19 13:53:50 +00:00
static const struct of_device_id arch_timer_of_match [ ] __initconst = {
{ . compatible = " arm,armv7-timer " , } ,
{ } ,
} ;
int __init arch_timer_of_register ( void )
{
struct device_node * np ;
u32 freq ;
2012-09-07 18:09:57 +01:00
int i ;
2012-01-19 13:53:50 +00:00
np = of_find_matching_node ( NULL , arch_timer_of_match ) ;
if ( ! np ) {
pr_err ( " arch_timer: can't find DT node \n " ) ;
return - ENODEV ;
}
/* Try to determine the frequency from the device tree or CNTFRQ */
if ( ! of_property_read_u32 ( np , " clock-frequency " , & freq ) )
arch_timer_rate = freq ;
2012-09-07 18:09:57 +01:00
for ( i = PHYS_SECURE_PPI ; i < MAX_TIMER_PPI ; i + + )
arch_timer_ppi [ i ] = irq_of_parse_and_map ( np , i ) ;
/*
* If no interrupt provided for virtual timer , we ' ll have to
* stick to the physical timer . It ' d better be accessible . . .
*/
if ( ! arch_timer_ppi [ VIRT_PPI ] ) {
arch_timer_use_virtual = false ;
if ( ! arch_timer_ppi [ PHYS_SECURE_PPI ] | |
! arch_timer_ppi [ PHYS_NONSECURE_PPI ] ) {
pr_warn ( " arch_timer: No interrupt available, giving up \n " ) ;
return - EINVAL ;
}
}
2012-01-19 13:53:50 +00:00
2012-04-27 13:18:42 +01:00
return arch_timer_register ( ) ;
2012-01-19 13:53:50 +00:00
}
2011-01-14 15:32:36 +00:00
int __init arch_timer_sched_clock_init ( void )
{
2012-09-07 18:09:57 +01:00
u32 ( * cnt32 ) ( void ) ;
2011-01-14 15:32:36 +00:00
int err ;
err = arch_timer_available ( ) ;
if ( err )
return err ;
2012-09-07 18:09:57 +01:00
if ( arch_timer_use_virtual )
cnt32 = arch_counter_get_cntvct32 ;
else
cnt32 = arch_counter_get_cntpct32 ;
setup_sched_clock ( cnt32 , 32 , arch_timer_rate ) ;
2011-01-14 15:32:36 +00:00
return 0 ;
}