2019-05-19 16:51:34 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2012-12-20 15:37:32 +04:00
/*
* System timer for CSR SiRFprimaII
*
* Copyright ( c ) 2011 Cambridge Silicon Radio Limited , a CSR plc group company .
*/
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/clockchips.h>
# include <linux/clocksource.h>
2013-02-16 05:02:16 +04:00
# include <linux/cpu.h>
2012-12-20 15:37:32 +04:00
# include <linux/bitops.h>
# include <linux/irq.h>
# include <linux/clk.h>
# include <linux/slab.h>
# include <linux/of.h>
# include <linux/of_irq.h>
# include <linux/of_address.h>
2013-06-02 10:39:40 +04:00
# include <linux/sched_clock.h>
2013-11-12 00:06:11 +04:00
2012-12-20 15:37:32 +04:00
# define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000
# define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004
# define SIRFSOC_TIMER_MATCH_0 0x0018
# define SIRFSOC_TIMER_MATCH_1 0x001c
# define SIRFSOC_TIMER_COUNTER_0 0x0048
# define SIRFSOC_TIMER_COUNTER_1 0x004c
# define SIRFSOC_TIMER_INTR_STATUS 0x0060
# define SIRFSOC_TIMER_WATCHDOG_EN 0x0064
# define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068
# define SIRFSOC_TIMER_64COUNTER_LO 0x006c
# define SIRFSOC_TIMER_64COUNTER_HI 0x0070
# define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074
# define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078
# define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c
# define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080
# define SIRFSOC_TIMER_REG_CNT 6
2015-01-11 19:04:43 +03:00
static unsigned long atlas7_timer_rate ;
2014-11-11 15:42:52 +03:00
2012-12-20 15:37:32 +04:00
static const u32 sirfsoc_timer_reg_list [ SIRFSOC_TIMER_REG_CNT ] = {
SIRFSOC_TIMER_WATCHDOG_EN ,
SIRFSOC_TIMER_32COUNTER_0_CTRL ,
SIRFSOC_TIMER_32COUNTER_1_CTRL ,
SIRFSOC_TIMER_64COUNTER_CTRL ,
SIRFSOC_TIMER_64COUNTER_RLATCHED_LO ,
SIRFSOC_TIMER_64COUNTER_RLATCHED_HI ,
} ;
static u32 sirfsoc_timer_reg_val [ SIRFSOC_TIMER_REG_CNT ] ;
static void __iomem * sirfsoc_timer_base ;
/* disable count and interrupt */
static inline void sirfsoc_timer_count_disable ( int idx )
{
writel_relaxed ( readl_relaxed ( sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx ) & ~ 0x7 ,
sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx ) ;
}
/* enable count and interrupt */
static inline void sirfsoc_timer_count_enable ( int idx )
{
2014-09-29 03:50:06 +04:00
writel_relaxed ( readl_relaxed ( sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx ) | 0x3 ,
2012-12-20 15:37:32 +04:00
sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx ) ;
}
/* timer interrupt handler */
static irqreturn_t sirfsoc_timer_interrupt ( int irq , void * dev_id )
{
struct clock_event_device * ce = dev_id ;
int cpu = smp_processor_id ( ) ;
/* clear timer interrupt */
writel_relaxed ( BIT ( cpu ) , sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS ) ;
2015-06-18 13:54:43 +03:00
if ( clockevent_state_oneshot ( ce ) )
2012-12-20 15:37:32 +04:00
sirfsoc_timer_count_disable ( cpu ) ;
ce - > event_handler ( ce ) ;
return IRQ_HANDLED ;
}
/* read 64-bit timer counter */
2016-12-21 22:32:01 +03:00
static u64 sirfsoc_timer_read ( struct clocksource * cs )
2012-12-20 15:37:32 +04:00
{
u64 cycles ;
writel_relaxed ( ( readl_relaxed ( sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL ) |
BIT ( 0 ) ) & ~ BIT ( 1 ) , sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL ) ;
cycles = readl_relaxed ( sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI ) ;
cycles = ( cycles < < 32 ) | readl_relaxed ( sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO ) ;
return cycles ;
}
static int sirfsoc_timer_set_next_event ( unsigned long delta ,
struct clock_event_device * ce )
{
int cpu = smp_processor_id ( ) ;
2014-09-29 03:50:06 +04:00
/* disable timer first, then modify the related registers */
sirfsoc_timer_count_disable ( cpu ) ;
2012-12-20 15:37:32 +04:00
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
4 * cpu ) ;
writel_relaxed ( delta , sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
4 * cpu ) ;
/* enable the tick */
sirfsoc_timer_count_enable ( cpu ) ;
return 0 ;
}
2015-06-18 13:54:43 +03:00
/* Oneshot is enabled in set_next_event */
static int sirfsoc_timer_shutdown ( struct clock_event_device * evt )
2012-12-20 15:37:32 +04:00
{
sirfsoc_timer_count_disable ( smp_processor_id ( ) ) ;
2015-06-18 13:54:43 +03:00
return 0 ;
2012-12-20 15:37:32 +04:00
}
static void sirfsoc_clocksource_suspend ( struct clocksource * cs )
{
int i ;
for ( i = 0 ; i < SIRFSOC_TIMER_REG_CNT ; i + + )
sirfsoc_timer_reg_val [ i ] = readl_relaxed ( sirfsoc_timer_base + sirfsoc_timer_reg_list [ i ] ) ;
}
static void sirfsoc_clocksource_resume ( struct clocksource * cs )
{
int i ;
for ( i = 0 ; i < SIRFSOC_TIMER_REG_CNT - 2 ; i + + )
writel_relaxed ( sirfsoc_timer_reg_val [ i ] , sirfsoc_timer_base + sirfsoc_timer_reg_list [ i ] ) ;
writel_relaxed ( sirfsoc_timer_reg_val [ SIRFSOC_TIMER_REG_CNT - 2 ] ,
sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO ) ;
writel_relaxed ( sirfsoc_timer_reg_val [ SIRFSOC_TIMER_REG_CNT - 1 ] ,
sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI ) ;
writel_relaxed ( readl_relaxed ( sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL ) |
BIT ( 1 ) | BIT ( 0 ) , sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL ) ;
}
2013-02-16 05:02:16 +04:00
static struct clock_event_device __percpu * sirfsoc_clockevent ;
2012-12-20 15:37:32 +04:00
static struct clocksource sirfsoc_clocksource = {
. name = " sirfsoc_clocksource " ,
. rating = 200 ,
. mask = CLOCKSOURCE_MASK ( 64 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
. read = sirfsoc_timer_read ,
. suspend = sirfsoc_clocksource_suspend ,
. resume = sirfsoc_clocksource_resume ,
} ;
static struct irqaction sirfsoc_timer_irq = {
. name = " sirfsoc_timer0 " ,
. flags = IRQF_TIMER | IRQF_NOBALANCING ,
. handler = sirfsoc_timer_interrupt ,
} ;
static struct irqaction sirfsoc_timer1_irq = {
. name = " sirfsoc_timer1 " ,
. flags = IRQF_TIMER | IRQF_NOBALANCING ,
. handler = sirfsoc_timer_interrupt ,
} ;
2016-07-13 20:17:07 +03:00
static int sirfsoc_local_timer_starting_cpu ( unsigned int cpu )
2012-12-20 15:37:32 +04:00
{
2016-07-13 20:17:07 +03:00
struct clock_event_device * ce = per_cpu_ptr ( sirfsoc_clockevent , cpu ) ;
2013-02-16 05:02:16 +04:00
struct irqaction * action ;
if ( cpu = = 0 )
action = & sirfsoc_timer_irq ;
else
action = & sirfsoc_timer1_irq ;
2012-12-20 15:37:32 +04:00
2013-02-16 05:02:16 +04:00
ce - > irq = action - > irq ;
2012-12-20 15:37:32 +04:00
ce - > name = " local_timer " ;
2013-02-16 05:02:16 +04:00
ce - > features = CLOCK_EVT_FEAT_ONESHOT ;
ce - > rating = 200 ;
2015-06-18 13:54:43 +03:00
ce - > set_state_shutdown = sirfsoc_timer_shutdown ;
ce - > set_state_oneshot = sirfsoc_timer_shutdown ;
ce - > tick_resume = sirfsoc_timer_shutdown ;
2012-12-20 15:37:32 +04:00
ce - > set_next_event = sirfsoc_timer_set_next_event ;
2015-01-11 19:04:43 +03:00
clockevents_calc_mult_shift ( ce , atlas7_timer_rate , 60 ) ;
2013-02-16 05:02:16 +04:00
ce - > max_delta_ns = clockevent_delta2ns ( - 2 , ce ) ;
2017-03-30 23:10:21 +03:00
ce - > max_delta_ticks = ( unsigned long ) - 2 ;
2013-02-16 05:02:16 +04:00
ce - > min_delta_ns = clockevent_delta2ns ( 2 , ce ) ;
2017-03-30 23:10:21 +03:00
ce - > min_delta_ticks = 2 ;
2013-02-16 05:02:16 +04:00
ce - > cpumask = cpumask_of ( cpu ) ;
2012-12-20 15:37:32 +04:00
2013-02-16 05:02:16 +04:00
action - > dev_id = ce ;
BUG_ON ( setup_irq ( ce - > irq , action ) ) ;
2014-05-07 10:46:44 +04:00
irq_force_affinity ( action - > irq , cpumask_of ( cpu ) ) ;
2012-12-20 15:37:32 +04:00
clockevents_register_device ( ce ) ;
return 0 ;
}
2016-07-13 20:17:07 +03:00
static int sirfsoc_local_timer_dying_cpu ( unsigned int cpu )
2012-12-20 15:37:32 +04:00
{
sirfsoc_timer_count_disable ( 1 ) ;
2013-02-16 05:02:16 +04:00
if ( cpu = = 0 )
remove_irq ( sirfsoc_timer_irq . irq , & sirfsoc_timer_irq ) ;
else
remove_irq ( sirfsoc_timer1_irq . irq , & sirfsoc_timer1_irq ) ;
2016-07-13 20:17:07 +03:00
return 0 ;
2012-12-20 15:37:32 +04:00
}
2016-06-06 19:01:09 +03:00
static int __init sirfsoc_clockevent_init ( void )
2012-12-20 15:37:32 +04:00
{
2013-02-16 05:02:16 +04:00
sirfsoc_clockevent = alloc_percpu ( struct clock_event_device ) ;
BUG_ON ( ! sirfsoc_clockevent ) ;
2016-07-13 20:17:07 +03:00
/* Install and invoke hotplug callbacks */
return cpuhp_setup_state ( CPUHP_AP_MARCO_TIMER_STARTING ,
2016-12-21 22:19:54 +03:00
" clockevents/marco:starting " ,
2016-07-13 20:17:07 +03:00
sirfsoc_local_timer_starting_cpu ,
sirfsoc_local_timer_dying_cpu ) ;
2012-12-20 15:37:32 +04:00
}
/* initialize the kernel jiffy timer source */
2016-06-06 19:01:09 +03:00
static int __init sirfsoc_atlas7_timer_init ( struct device_node * np )
2012-12-20 15:37:32 +04:00
{
struct clk * clk ;
2014-05-05 15:30:04 +04:00
clk = of_clk_get ( np , 0 ) ;
2012-12-20 15:37:32 +04:00
BUG_ON ( IS_ERR ( clk ) ) ;
2014-07-03 16:52:51 +04:00
BUG_ON ( clk_prepare_enable ( clk ) ) ;
2015-01-11 19:04:43 +03:00
atlas7_timer_rate = clk_get_rate ( clk ) ;
2012-12-20 15:37:32 +04:00
2014-11-11 15:42:52 +03:00
/* timer dividers: 0, not divided */
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL ) ;
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL ) ;
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL ) ;
2012-12-20 15:37:32 +04:00
/* Initialize timer counters to 0 */
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO ) ;
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI ) ;
writel_relaxed ( readl_relaxed ( sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL ) |
BIT ( 1 ) | BIT ( 0 ) , sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL ) ;
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 ) ;
writel_relaxed ( 0 , sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1 ) ;
/* Clear all interrupts */
writel_relaxed ( 0xFFFF , sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS ) ;
2015-01-11 19:04:43 +03:00
BUG_ON ( clocksource_register_hz ( & sirfsoc_clocksource , atlas7_timer_rate ) ) ;
2012-12-20 15:37:32 +04:00
2016-06-06 19:01:09 +03:00
return sirfsoc_clockevent_init ( ) ;
2012-12-20 15:37:32 +04:00
}
2016-06-06 19:01:09 +03:00
static int __init sirfsoc_of_timer_init ( struct device_node * np )
2012-12-20 15:37:32 +04:00
{
sirfsoc_timer_base = of_iomap ( np , 0 ) ;
2016-06-06 19:01:09 +03:00
if ( ! sirfsoc_timer_base ) {
pr_err ( " unable to map timer cpu registers \n " ) ;
return - ENXIO ;
}
2012-12-20 15:37:32 +04:00
sirfsoc_timer_irq . irq = irq_of_parse_and_map ( np , 0 ) ;
2016-06-06 19:01:09 +03:00
if ( ! sirfsoc_timer_irq . irq ) {
pr_err ( " No irq passed for timer0 via DT \n " ) ;
return - EINVAL ;
}
2012-12-20 15:37:32 +04:00
sirfsoc_timer1_irq . irq = irq_of_parse_and_map ( np , 1 ) ;
2016-06-06 19:01:09 +03:00
if ( ! sirfsoc_timer1_irq . irq ) {
pr_err ( " No irq passed for timer1 via DT \n " ) ;
return - EINVAL ;
}
2012-12-20 15:37:32 +04:00
2016-06-06 19:01:09 +03:00
return sirfsoc_atlas7_timer_init ( np ) ;
2012-12-20 15:37:32 +04:00
}
2017-05-26 17:56:11 +03:00
TIMER_OF_DECLARE ( sirfsoc_atlas7_timer , " sirf,atlas7-tick " , sirfsoc_of_timer_init ) ;