2012-12-07 03:51:04 +00:00
/*
* 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 .
*
* Copyright ( C ) 2012 MIPS Technologies , Inc . All rights reserved .
*/
2015-02-23 18:28:34 -08:00
# include <linux/clk.h>
2014-10-20 12:03:59 -07:00
# include <linux/clockchips.h>
2014-10-20 12:04:04 -07:00
# include <linux/cpu.h>
2012-12-07 03:51:04 +00:00
# include <linux/init.h>
2014-10-20 12:03:59 -07:00
# include <linux/interrupt.h>
2014-10-20 12:03:53 -07:00
# include <linux/irqchip/mips-gic.h>
2014-10-20 12:04:04 -07:00
# include <linux/notifier.h>
2014-11-12 11:43:39 -08:00
# include <linux/of_irq.h>
2014-10-20 12:03:59 -07:00
# include <linux/percpu.h>
# include <linux/smp.h>
2013-04-10 16:28:36 -05:00
# include <linux/time.h>
2012-12-07 03:51:04 +00:00
2014-10-20 12:04:00 -07:00
static DEFINE_PER_CPU ( struct clock_event_device , gic_clockevent_device ) ;
2014-10-20 12:04:04 -07:00
static int gic_timer_irq ;
2014-10-20 12:04:01 -07:00
static unsigned int gic_frequency ;
2014-10-20 12:03:59 -07:00
static int gic_next_event ( unsigned long delta , struct clock_event_device * evt )
{
u64 cnt ;
int res ;
cnt = gic_read_count ( ) ;
cnt + = ( u64 ) delta ;
gic_write_cpu_compare ( cnt , cpumask_first ( evt - > cpumask ) ) ;
res = ( ( int ) ( gic_read_count ( ) - cnt ) > = 0 ) ? - ETIME : 0 ;
return res ;
}
2014-10-20 12:04:00 -07:00
static void gic_set_clock_mode ( enum clock_event_mode mode ,
2014-10-20 12:03:59 -07:00
struct clock_event_device * evt )
{
/* Nothing to do ... */
}
2014-10-20 12:04:00 -07:00
static irqreturn_t gic_compare_interrupt ( int irq , void * dev_id )
2014-10-20 12:03:59 -07:00
{
2014-10-20 12:04:03 -07:00
struct clock_event_device * cd = dev_id ;
2014-10-20 12:03:59 -07:00
gic_write_compare ( gic_read_compare ( ) ) ;
cd - > event_handler ( cd ) ;
return IRQ_HANDLED ;
}
struct irqaction gic_compare_irqaction = {
. handler = gic_compare_interrupt ,
2014-10-20 12:04:03 -07:00
. percpu_dev_id = & gic_clockevent_device ,
2014-10-20 12:03:59 -07:00
. flags = IRQF_PERCPU | IRQF_TIMER ,
. name = " timer " ,
} ;
2014-10-20 12:04:04 -07:00
static void gic_clockevent_cpu_init ( struct clock_event_device * cd )
2014-10-20 12:03:59 -07:00
{
unsigned int cpu = smp_processor_id ( ) ;
cd - > name = " MIPS GIC " ;
cd - > features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_C3STOP ;
2014-10-20 12:04:06 -07:00
cd - > rating = 350 ;
2014-10-20 12:04:04 -07:00
cd - > irq = gic_timer_irq ;
2014-10-20 12:03:59 -07:00
cd - > cpumask = cpumask_of ( cpu ) ;
cd - > set_next_event = gic_next_event ;
cd - > set_mode = gic_set_clock_mode ;
2014-10-20 12:04:05 -07:00
clockevents_config_and_register ( cd , gic_frequency , 0x300 , 0x7fffffff ) ;
2014-10-20 12:03:59 -07:00
2014-10-20 12:04:04 -07:00
enable_percpu_irq ( gic_timer_irq , IRQ_TYPE_NONE ) ;
}
static void gic_clockevent_cpu_exit ( struct clock_event_device * cd )
{
disable_percpu_irq ( gic_timer_irq ) ;
}
static int gic_cpu_notifier ( struct notifier_block * nb , unsigned long action ,
void * data )
{
switch ( action & ~ CPU_TASKS_FROZEN ) {
case CPU_STARTING :
gic_clockevent_cpu_init ( this_cpu_ptr ( & gic_clockevent_device ) ) ;
break ;
case CPU_DYING :
gic_clockevent_cpu_exit ( this_cpu_ptr ( & gic_clockevent_device ) ) ;
break ;
2014-10-20 12:03:59 -07:00
}
2014-10-20 12:04:04 -07:00
return NOTIFY_OK ;
}
static struct notifier_block gic_cpu_nb = {
. notifier_call = gic_cpu_notifier ,
} ;
static int gic_clockevent_init ( void )
{
if ( ! cpu_has_counter | | ! gic_frequency )
return - ENXIO ;
setup_percpu_irq ( gic_timer_irq , & gic_compare_irqaction ) ;
register_cpu_notifier ( & gic_cpu_nb ) ;
gic_clockevent_cpu_init ( this_cpu_ptr ( & gic_clockevent_device ) ) ;
2014-10-20 12:03:59 -07:00
return 0 ;
}
2012-12-07 03:51:04 +00:00
static cycle_t gic_hpt_read ( struct clocksource * cs )
{
2013-04-10 16:28:36 -05:00
return gic_read_count ( ) ;
2012-12-07 03:51:04 +00:00
}
static struct clocksource gic_clocksource = {
. name = " GIC " ,
. read = gic_hpt_read ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2014-11-12 11:43:39 -08:00
static void __init __gic_clocksource_init ( void )
2012-12-07 03:51:04 +00:00
{
/* Set clocksource mask. */
2014-10-20 12:03:49 -07:00
gic_clocksource . mask = CLOCKSOURCE_MASK ( gic_get_count_width ( ) ) ;
2012-12-07 03:51:04 +00:00
/* Calculate a somewhat reasonable rating value. */
2014-11-12 11:43:39 -08:00
gic_clocksource . rating = 200 + gic_frequency / 10000000 ;
2012-12-07 03:51:04 +00:00
2014-11-12 11:43:39 -08:00
clocksource_register_hz ( & gic_clocksource , gic_frequency ) ;
2014-10-20 12:04:04 -07:00
gic_clockevent_init ( ) ;
2015-03-23 12:32:02 +00:00
/* And finally start the counter */
gic_start_count ( ) ;
2012-12-07 03:51:04 +00:00
}
2014-11-12 11:43:39 -08:00
void __init gic_clocksource_init ( unsigned int frequency )
{
gic_frequency = frequency ;
gic_timer_irq = MIPS_GIC_IRQ_BASE +
GIC_LOCAL_TO_HWIRQ ( GIC_LOCAL_INT_COMPARE ) ;
__gic_clocksource_init ( ) ;
}
static void __init gic_clocksource_of_init ( struct device_node * node )
{
2015-02-23 18:28:34 -08:00
struct clk * clk ;
2014-11-12 11:43:39 -08:00
if ( WARN_ON ( ! gic_present | | ! node - > parent | |
! of_device_is_compatible ( node - > parent , " mti,gic " ) ) )
return ;
2015-02-23 18:28:34 -08:00
clk = of_clk_get ( node , 0 ) ;
if ( ! IS_ERR ( clk ) ) {
gic_frequency = clk_get_rate ( clk ) ;
clk_put ( clk ) ;
} else if ( of_property_read_u32 ( node , " clock-frequency " ,
& gic_frequency ) ) {
2014-11-12 11:43:39 -08:00
pr_err ( " GIC frequency not specified. \n " ) ;
return ;
}
gic_timer_irq = irq_of_parse_and_map ( node , 0 ) ;
if ( ! gic_timer_irq ) {
pr_err ( " GIC timer IRQ not specified. \n " ) ;
return ;
}
__gic_clocksource_init ( ) ;
}
CLOCKSOURCE_OF_DECLARE ( mips_gic_timer , " mti,gic-timer " ,
gic_clocksource_of_init ) ;