2012-12-07 07:51:04 +04: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 .
*/
2018-03-29 12:49:03 +03:00
# define pr_fmt(fmt) "mips-gic-timer: " fmt
2015-02-24 05:28:34 +03:00
# include <linux/clk.h>
2014-10-20 23:03:59 +04:00
# include <linux/clockchips.h>
2014-10-20 23:04:04 +04:00
# include <linux/cpu.h>
2012-12-07 07:51:04 +04:00
# include <linux/init.h>
2014-10-20 23:03:59 +04:00
# include <linux/interrupt.h>
2014-10-20 23:04:04 +04:00
# include <linux/notifier.h>
2014-11-12 22:43:39 +03:00
# include <linux/of_irq.h>
2014-10-20 23:03:59 +04:00
# include <linux/percpu.h>
# include <linux/smp.h>
2013-04-11 01:28:36 +04:00
# include <linux/time.h>
2017-08-13 07:36:11 +03:00
# include <asm/mips-cps.h>
2012-12-07 07:51:04 +04:00
2014-10-20 23:04:00 +04:00
static DEFINE_PER_CPU ( struct clock_event_device , gic_clockevent_device ) ;
2014-10-20 23:04:04 +04:00
static int gic_timer_irq ;
2014-10-20 23:04:01 +04:00
static unsigned int gic_frequency ;
2014-10-20 23:03:59 +04:00
2017-08-13 07:36:11 +03:00
static u64 notrace gic_read_count ( void )
{
unsigned int hi , hi2 , lo ;
if ( mips_cm_is64 )
return read_gic_counter ( ) ;
do {
hi = read_gic_counter_32h ( ) ;
lo = read_gic_counter_32l ( ) ;
hi2 = read_gic_counter_32h ( ) ;
} while ( hi2 ! = hi ) ;
return ( ( ( u64 ) hi ) < < 32 ) + lo ;
}
2014-10-20 23:03:59 +04:00
static int gic_next_event ( unsigned long delta , struct clock_event_device * evt )
{
2017-10-19 14:55:35 +03:00
int cpu = cpumask_first ( evt - > cpumask ) ;
2014-10-20 23:03:59 +04:00
u64 cnt ;
int res ;
cnt = gic_read_count ( ) ;
cnt + = ( u64 ) delta ;
2017-10-19 14:55:35 +03:00
if ( cpu = = raw_smp_processor_id ( ) ) {
write_gic_vl_compare ( cnt ) ;
} else {
write_gic_vl_other ( mips_cm_vp_id ( cpu ) ) ;
write_gic_vo_compare ( cnt ) ;
}
2014-10-20 23:03:59 +04:00
res = ( ( int ) ( gic_read_count ( ) - cnt ) > = 0 ) ? - ETIME : 0 ;
return res ;
}
2014-10-20 23:04:00 +04:00
static irqreturn_t gic_compare_interrupt ( int irq , void * dev_id )
2014-10-20 23:03:59 +04:00
{
2014-10-20 23:04:03 +04:00
struct clock_event_device * cd = dev_id ;
2014-10-20 23:03:59 +04:00
2017-08-13 07:36:11 +03:00
write_gic_vl_compare ( read_gic_vl_compare ( ) ) ;
2014-10-20 23:03:59 +04:00
cd - > event_handler ( cd ) ;
return IRQ_HANDLED ;
}
2019-03-22 17:43:59 +03:00
static struct irqaction gic_compare_irqaction = {
2014-10-20 23:03:59 +04:00
. handler = gic_compare_interrupt ,
2014-10-20 23:04:03 +04:00
. percpu_dev_id = & gic_clockevent_device ,
2014-10-20 23:03:59 +04:00
. flags = IRQF_PERCPU | IRQF_TIMER ,
. name = " timer " ,
} ;
2016-07-13 20:16:44 +03:00
static void gic_clockevent_cpu_init ( unsigned int cpu ,
struct clock_event_device * cd )
2014-10-20 23:03:59 +04:00
{
cd - > name = " MIPS GIC " ;
cd - > features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_C3STOP ;
2014-10-20 23:04:06 +04:00
cd - > rating = 350 ;
2014-10-20 23:04:04 +04:00
cd - > irq = gic_timer_irq ;
2014-10-20 23:03:59 +04:00
cd - > cpumask = cpumask_of ( cpu ) ;
cd - > set_next_event = gic_next_event ;
2014-10-20 23:04:05 +04:00
clockevents_config_and_register ( cd , gic_frequency , 0x300 , 0x7fffffff ) ;
2014-10-20 23:03:59 +04:00
2014-10-20 23:04:04 +04: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 ) ;
}
2015-07-27 17:00:15 +03:00
static void gic_update_frequency ( void * data )
{
unsigned long rate = ( unsigned long ) data ;
clockevents_update_freq ( this_cpu_ptr ( & gic_clockevent_device ) , rate ) ;
}
2016-07-13 20:16:44 +03:00
static int gic_starting_cpu ( unsigned int cpu )
2014-10-20 23:04:04 +04:00
{
2016-07-13 20:16:44 +03:00
gic_clockevent_cpu_init ( cpu , this_cpu_ptr ( & gic_clockevent_device ) ) ;
return 0 ;
2014-10-20 23:04:04 +04:00
}
2015-07-27 17:00:15 +03:00
static int gic_clk_notifier ( struct notifier_block * nb , unsigned long action ,
void * data )
{
struct clk_notifier_data * cnd = data ;
if ( action = = POST_RATE_CHANGE )
on_each_cpu ( gic_update_frequency , ( void * ) cnd - > new_rate , 1 ) ;
return NOTIFY_OK ;
}
2016-07-13 20:16:44 +03:00
static int gic_dying_cpu ( unsigned int cpu )
{
gic_clockevent_cpu_exit ( this_cpu_ptr ( & gic_clockevent_device ) ) ;
return 0 ;
}
2014-10-20 23:04:04 +04:00
2015-07-27 17:00:15 +03:00
static struct notifier_block gic_clk_nb = {
. notifier_call = gic_clk_notifier ,
} ;
2014-10-20 23:04:04 +04:00
static int gic_clockevent_init ( void )
{
2015-07-27 17:00:13 +03:00
int ret ;
2016-09-13 19:56:44 +03:00
if ( ! gic_frequency )
2014-10-20 23:04:04 +04:00
return - ENXIO ;
2015-07-27 17:00:13 +03:00
ret = setup_percpu_irq ( gic_timer_irq , & gic_compare_irqaction ) ;
2016-09-13 19:56:43 +03:00
if ( ret < 0 ) {
2018-03-29 12:49:03 +03:00
pr_err ( " IRQ %d setup failed (%d) \n " , gic_timer_irq , ret ) ;
2015-07-27 17:00:13 +03:00
return ret ;
2016-09-13 19:56:43 +03:00
}
2014-10-20 23:04:04 +04:00
2016-07-13 20:16:44 +03:00
cpuhp_setup_state ( CPUHP_AP_MIPS_GIC_TIMER_STARTING ,
2016-12-21 22:19:54 +03:00
" clockevents/mips/gic/timer:starting " ,
gic_starting_cpu , gic_dying_cpu ) ;
2014-10-20 23:03:59 +04:00
return 0 ;
}
2016-12-21 22:32:01 +03:00
static u64 gic_hpt_read ( struct clocksource * cs )
2012-12-07 07:51:04 +04:00
{
2013-04-11 01:28:36 +04:00
return gic_read_count ( ) ;
2012-12-07 07:51:04 +04:00
}
static struct clocksource gic_clocksource = {
2020-02-07 15:38:57 +03:00
. name = " GIC " ,
. read = gic_hpt_read ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
. vdso_clock_mode = VDSO_CLOCKMODE_GIC ,
2012-12-07 07:51:04 +04:00
} ;
2016-06-06 18:57:25 +03:00
static int __init __gic_clocksource_init ( void )
2012-12-07 07:51:04 +04:00
{
2017-08-13 07:36:11 +03:00
unsigned int count_width ;
2015-07-27 17:00:13 +03:00
int ret ;
2012-12-07 07:51:04 +04:00
/* Set clocksource mask. */
2017-08-13 07:36:11 +03:00
count_width = read_gic_config ( ) & GIC_CONFIG_COUNTBITS ;
2018-02-28 12:56:10 +03:00
count_width > > = __ffs ( GIC_CONFIG_COUNTBITS ) ;
2017-08-13 07:36:11 +03:00
count_width * = 4 ;
count_width + = 32 ;
gic_clocksource . mask = CLOCKSOURCE_MASK ( count_width ) ;
2012-12-07 07:51:04 +04:00
/* Calculate a somewhat reasonable rating value. */
2014-11-12 22:43:39 +03:00
gic_clocksource . rating = 200 + gic_frequency / 10000000 ;
2012-12-07 07:51:04 +04:00
2015-07-27 17:00:13 +03:00
ret = clocksource_register_hz ( & gic_clocksource , gic_frequency ) ;
if ( ret < 0 )
2018-03-29 12:49:03 +03:00
pr_warn ( " Unable to register clocksource \n " ) ;
2016-06-06 18:57:25 +03:00
return ret ;
2012-12-07 07:51:04 +04:00
}
2014-11-12 22:43:39 +03:00
2016-08-17 13:21:35 +03:00
static int __init gic_clocksource_of_init ( struct device_node * node )
2014-11-12 22:43:39 +03:00
{
2015-02-24 05:28:34 +03:00
struct clk * clk ;
2015-07-27 17:00:15 +03:00
int ret ;
2015-02-24 05:28:34 +03:00
2017-08-13 07:36:11 +03:00
if ( ! mips_gic_present ( ) | | ! node - > parent | |
2016-06-06 18:57:25 +03:00
! of_device_is_compatible ( node - > parent , " mti,gic " ) ) {
2018-03-29 12:49:03 +03:00
pr_warn ( " No DT definition \n " ) ;
2016-06-06 18:57:25 +03:00
return - ENXIO ;
}
2014-11-12 22:43:39 +03:00
2015-02-24 05:28:34 +03:00
clk = of_clk_get ( node , 0 ) ;
if ( ! IS_ERR ( clk ) ) {
2017-06-23 22:55:10 +03:00
ret = clk_prepare_enable ( clk ) ;
if ( ret < 0 ) {
2018-03-29 12:49:03 +03:00
pr_err ( " Failed to enable clock \n " ) ;
2015-07-27 17:00:12 +03:00
clk_put ( clk ) ;
2017-06-23 22:55:10 +03:00
return ret ;
2015-07-27 17:00:12 +03:00
}
2015-02-24 05:28:34 +03:00
gic_frequency = clk_get_rate ( clk ) ;
} else if ( of_property_read_u32 ( node , " clock-frequency " ,
& gic_frequency ) ) {
2018-03-29 12:49:03 +03:00
pr_err ( " Frequency not specified \n " ) ;
2018-02-22 12:54:55 +03:00
return - EINVAL ;
2014-11-12 22:43:39 +03:00
}
gic_timer_irq = irq_of_parse_and_map ( node , 0 ) ;
if ( ! gic_timer_irq ) {
2018-03-29 12:49:03 +03:00
pr_err ( " IRQ not specified \n " ) ;
2018-02-22 12:54:55 +03:00
return - EINVAL ;
2014-11-12 22:43:39 +03:00
}
2016-06-06 18:57:25 +03:00
ret = __gic_clocksource_init ( ) ;
if ( ret )
return ret ;
2015-07-27 17:00:15 +03:00
ret = gic_clockevent_init ( ) ;
if ( ! ret & & ! IS_ERR ( clk ) ) {
if ( clk_notifier_register ( clk , & gic_clk_nb ) < 0 )
2018-03-29 12:49:03 +03:00
pr_warn ( " Unable to register clock notifier \n " ) ;
2015-07-27 17:00:15 +03:00
}
2015-07-27 17:00:14 +03:00
/* And finally start the counter */
2017-08-13 07:36:11 +03:00
clear_gic_config ( GIC_CONFIG_COUNTSTOP ) ;
2016-06-06 18:57:25 +03:00
return 0 ;
2014-11-12 22:43:39 +03:00
}
2017-05-26 17:56:11 +03:00
TIMER_OF_DECLARE ( mips_gic_timer , " mti,gic-timer " ,
2014-11-12 22:43:39 +03:00
gic_clocksource_of_init ) ;