2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2009-07-02 22:06:47 +04:00
/*
* Copyright ( C ) 2008 STMicroelectronics
2010-03-05 14:38:51 +03:00
* Copyright ( C ) 2010 Alessandro Rubini
2010-11-19 12:16:05 +03:00
* Copyright ( C ) 2010 Linus Walleij for ST - Ericsson
2009-07-02 22:06:47 +04:00
*/
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/io.h>
# include <linux/clockchips.h>
2012-10-18 16:01:25 +04:00
# include <linux/clocksource.h>
2023-07-14 20:44:09 +03:00
# include <linux/of.h>
2013-04-03 15:28:26 +04:00
# include <linux/of_address.h>
# include <linux/of_irq.h>
2010-05-26 10:38:54 +04:00
# include <linux/clk.h>
2009-07-02 22:06:47 +04:00
# include <linux/jiffies.h>
2012-12-04 14:10:44 +04:00
# include <linux/delay.h>
2010-05-26 10:38:54 +04:00
# include <linux/err.h>
2013-06-02 10:39:40 +04:00
# include <linux/sched_clock.h>
2009-07-02 22:06:47 +04:00
# include <asm/mach/time.h>
2011-09-20 13:18:27 +04:00
/*
* The MTU device hosts four different counters , with 4 set of
* registers . These are register names .
*/
# define MTU_IMSC 0x00 /* Interrupt mask set/clear */
# define MTU_RIS 0x04 /* Raw interrupt status */
# define MTU_MIS 0x08 /* Masked interrupt status */
# define MTU_ICR 0x0C /* Interrupt clear register */
/* per-timer registers take 0..3 as argument */
# define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
# define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
# define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
# define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
/* bits for the control register */
# define MTU_CRn_ENA 0x80
# define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
# define MTU_CRn_PRESCALE_MASK 0x0c
# define MTU_CRn_PRESCALE_1 0x00
# define MTU_CRn_PRESCALE_16 0x04
# define MTU_CRn_PRESCALE_256 0x08
# define MTU_CRn_32BITS 0x02
# define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
/* Other registers are usual amba/primecell registers, currently not used */
# define MTU_ITCR 0xff0
# define MTU_ITOP 0xff4
# define MTU_PERIPH_ID0 0xfe0
# define MTU_PERIPH_ID1 0xfe4
# define MTU_PERIPH_ID2 0xfe8
# define MTU_PERIPH_ID3 0xfeC
# define MTU_PCELL0 0xff0
# define MTU_PCELL1 0xff4
# define MTU_PCELL2 0xff8
# define MTU_PCELL3 0xffC
2009-07-02 22:06:47 +04:00
2012-01-11 12:46:59 +04:00
static void __iomem * mtu_base ;
2011-09-14 12:32:51 +04:00
static bool clkevt_periodic ;
static u32 clk_prescale ;
static u32 nmdk_cycle ; /* write-once */
2012-12-04 14:10:44 +04:00
static struct delay_timer mtu_delay_timer ;
2011-09-14 12:32:51 +04:00
2010-05-07 13:03:02 +04:00
/*
* Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some
2010-11-19 12:16:05 +03:00
* better resolution when scheduling the kernel .
2010-05-07 13:03:02 +04:00
*/
2013-07-19 03:21:24 +04:00
static u64 notrace nomadik_read_sched_clock ( void )
2010-05-07 13:03:02 +04:00
{
2010-11-19 12:16:05 +03:00
if ( unlikely ( ! mtu_base ) )
return 0 ;
2011-12-15 15:19:23 +04:00
return - readl ( mtu_base + MTU_VAL ( 0 ) ) ;
2010-05-07 13:03:02 +04:00
}
2011-09-14 12:32:51 +04:00
2012-12-04 14:10:44 +04:00
static unsigned long nmdk_timer_read_current_timer ( void )
{
return ~ readl_relaxed ( mtu_base + MTU_VAL ( 0 ) ) ;
}
2010-03-05 14:38:51 +03:00
/* Clockevent device: use one-shot mode */
2011-09-14 12:32:51 +04:00
static int nmdk_clkevt_next ( unsigned long evt , struct clock_event_device * ev )
{
writel ( 1 < < 1 , mtu_base + MTU_IMSC ) ;
writel ( evt , mtu_base + MTU_LR ( 1 ) ) ;
/* Load highest value, enable device, enable interrupts */
writel ( MTU_CRn_ONESHOT | clk_prescale |
MTU_CRn_32BITS | MTU_CRn_ENA ,
mtu_base + MTU_CR ( 1 ) ) ;
return 0 ;
}
2013-11-20 01:23:21 +04:00
static void nmdk_clkevt_reset ( void )
2011-09-14 12:32:51 +04:00
{
if ( clkevt_periodic ) {
/* Timer: configure load and background-load, and fire it up */
writel ( nmdk_cycle , mtu_base + MTU_LR ( 1 ) ) ;
writel ( nmdk_cycle , mtu_base + MTU_BGLR ( 1 ) ) ;
writel ( MTU_CRn_PERIODIC | clk_prescale |
MTU_CRn_32BITS | MTU_CRn_ENA ,
mtu_base + MTU_CR ( 1 ) ) ;
writel ( 1 < < 1 , mtu_base + MTU_IMSC ) ;
} else {
/* Generate an interrupt to start the clockevent again */
( void ) nmdk_clkevt_next ( nmdk_cycle , NULL ) ;
}
}
2015-06-18 13:54:29 +03:00
static int nmdk_clkevt_shutdown ( struct clock_event_device * evt )
2009-07-02 22:06:47 +04:00
{
2015-06-18 13:54:29 +03:00
writel ( 0 , mtu_base + MTU_IMSC ) ;
/* disable timer */
writel ( 0 , mtu_base + MTU_CR ( 1 ) ) ;
/* load some high default value */
writel ( 0xffffffff , mtu_base + MTU_LR ( 1 ) ) ;
return 0 ;
}
static int nmdk_clkevt_set_oneshot ( struct clock_event_device * evt )
{
clkevt_periodic = false ;
return 0 ;
}
static int nmdk_clkevt_set_periodic ( struct clock_event_device * evt )
{
clkevt_periodic = true ;
nmdk_clkevt_reset ( ) ;
return 0 ;
2009-07-02 22:06:47 +04:00
}
2013-11-20 01:23:21 +04:00
static void nmdk_clksrc_reset ( void )
2012-11-08 04:07:45 +04:00
{
/* Disable */
writel ( 0 , mtu_base + MTU_CR ( 0 ) ) ;
/* ClockSource: configure load and background-load, and fire it up */
writel ( nmdk_cycle , mtu_base + MTU_LR ( 0 ) ) ;
writel ( nmdk_cycle , mtu_base + MTU_BGLR ( 0 ) ) ;
writel ( clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA ,
mtu_base + MTU_CR ( 0 ) ) ;
}
static void nmdk_clkevt_resume ( struct clock_event_device * cedev )
{
nmdk_clkevt_reset ( ) ;
nmdk_clksrc_reset ( ) ;
}
2009-07-02 22:06:47 +04:00
static struct clock_event_device nmdk_clkevt = {
2015-06-18 13:54:29 +03:00
. name = " mtu_1 " ,
. features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_DYNIRQ ,
. rating = 200 ,
. set_state_shutdown = nmdk_clkevt_shutdown ,
. set_state_periodic = nmdk_clkevt_set_periodic ,
. set_state_oneshot = nmdk_clkevt_set_oneshot ,
. set_next_event = nmdk_clkevt_next ,
. resume = nmdk_clkevt_resume ,
2009-07-02 22:06:47 +04:00
} ;
/*
2010-03-05 14:38:51 +03:00
* IRQ Handler for timer 1 of the MTU block .
2009-07-02 22:06:47 +04:00
*/
static irqreturn_t nmdk_timer_interrupt ( int irq , void * dev_id )
{
2010-03-05 14:38:51 +03:00
struct clock_event_device * evdev = dev_id ;
2009-07-02 22:06:47 +04:00
2010-03-05 14:38:51 +03:00
writel ( 1 < < 1 , mtu_base + MTU_ICR ) ; /* Interrupt clear reg */
evdev - > event_handler ( evdev ) ;
2009-07-02 22:06:47 +04:00
return IRQ_HANDLED ;
}
2016-06-06 18:58:15 +03:00
static int __init nmdk_timer_init ( void __iomem * base , int irq ,
2013-11-20 01:23:21 +04:00
struct clk * pclk , struct clk * clk )
2009-07-02 22:06:47 +04:00
{
unsigned long rate ;
2016-06-06 18:58:15 +03:00
int ret ;
2020-06-29 01:01:53 +03:00
int min_ticks ;
2010-05-26 10:38:54 +04:00
2012-01-11 12:46:59 +04:00
mtu_base = base ;
2012-10-24 16:13:41 +04:00
2013-04-03 15:28:26 +04:00
BUG_ON ( clk_prepare_enable ( pclk ) ) ;
BUG_ON ( clk_prepare_enable ( clk ) ) ;
2010-03-05 14:38:51 +03:00
/*
2010-09-13 16:40:04 +04:00
* Tick rate is 2.4 MHz for Nomadik and 2.4 Mhz , 100 MHz or 133 MHz
2020-06-29 01:01:53 +03:00
* for ux500 , and in one specific Ux500 case 32768 Hz .
*
2010-09-13 16:40:04 +04:00
* Use a divide - by - 16 counter if the tick rate is more than 32 MHz .
* At 32 MHz , the timer ( with 32 bit counter ) can be programmed
* to wake - up at a max 127 s a head in time . Dividing a 2.4 MHz timer
* with 16 gives too low timer resolution .
2010-03-05 14:38:51 +03:00
*/
2013-04-03 15:28:26 +04:00
rate = clk_get_rate ( clk ) ;
2010-09-13 16:40:04 +04:00
if ( rate > 32000000 ) {
2010-03-05 14:38:51 +03:00
rate / = 16 ;
2011-09-14 12:32:51 +04:00
clk_prescale = MTU_CRn_PRESCALE_16 ;
2010-03-05 14:38:51 +03:00
} else {
2011-09-14 12:32:51 +04:00
clk_prescale = MTU_CRn_PRESCALE_1 ;
2010-03-05 14:38:51 +03:00
}
2009-07-02 22:06:47 +04:00
2012-10-18 13:12:31 +04:00
/* Cycles for periodic mode */
nmdk_cycle = DIV_ROUND_CLOSEST ( rate , HZ ) ;
2011-09-14 12:32:51 +04:00
2010-03-05 14:38:51 +03:00
/* Timer 0 is the free running clocksource */
2011-09-14 12:32:51 +04:00
nmdk_clksrc_reset ( ) ;
2009-07-02 22:06:47 +04:00
2016-06-06 18:58:15 +03:00
ret = clocksource_mmio_init ( mtu_base + MTU_VAL ( 0 ) , " mtu_0 " ,
rate , 200 , 32 , clocksource_mmio_readl_down ) ;
if ( ret ) {
pr_err ( " timer: failed to initialize clock source %s \n " , " mtu_0 " ) ;
return ret ;
}
2011-12-15 15:19:23 +04:00
2013-07-19 03:21:24 +04:00
sched_clock_register ( nomadik_read_sched_clock , 32 , rate ) ;
2011-12-15 15:19:23 +04:00
2012-01-11 12:57:56 +04:00
/* Timer 1 is used for events, register irq and clockevents */
2020-02-27 13:59:02 +03:00
if ( request_irq ( irq , nmdk_timer_interrupt , IRQF_TIMER ,
" Nomadik Timer Tick " , & nmdk_clkevt ) )
pr_err ( " %s: request_irq() failed \n " , " Nomadik Timer Tick " ) ;
2012-01-11 12:57:56 +04:00
nmdk_clkevt . cpumask = cpumask_of ( 0 ) ;
2013-02-22 19:44:30 +04:00
nmdk_clkevt . irq = irq ;
2020-06-29 01:01:53 +03:00
if ( rate < 100000 )
min_ticks = 5 ;
else
min_ticks = 2 ;
clockevents_config_and_register ( & nmdk_clkevt , rate , min_ticks ,
0xffffffffU ) ;
2012-12-04 14:10:44 +04:00
mtu_delay_timer . read_current_timer = & nmdk_timer_read_current_timer ;
mtu_delay_timer . freq = rate ;
register_current_timer_delay ( & mtu_delay_timer ) ;
2016-06-06 18:58:15 +03:00
return 0 ;
2009-07-02 22:06:47 +04:00
}
2013-04-03 15:28:26 +04:00
2016-06-06 18:58:15 +03:00
static int __init nmdk_timer_of_init ( struct device_node * node )
2013-04-03 15:28:26 +04:00
{
struct clk * pclk ;
struct clk * clk ;
void __iomem * base ;
int irq ;
base = of_iomap ( node , 0 ) ;
2016-06-06 18:58:15 +03:00
if ( ! base ) {
2017-03-09 12:47:10 +03:00
pr_err ( " Can't remap registers \n " ) ;
2016-06-06 18:58:15 +03:00
return - ENXIO ;
}
2013-04-03 15:28:26 +04:00
pclk = of_clk_get_by_name ( node , " apb_pclk " ) ;
2016-06-06 18:58:15 +03:00
if ( IS_ERR ( pclk ) ) {
2017-03-09 12:47:10 +03:00
pr_err ( " could not get apb_pclk \n " ) ;
2016-06-06 18:58:15 +03:00
return PTR_ERR ( pclk ) ;
}
2013-04-03 15:28:26 +04:00
clk = of_clk_get_by_name ( node , " timclk " ) ;
2016-06-06 18:58:15 +03:00
if ( IS_ERR ( clk ) ) {
2017-03-09 12:47:10 +03:00
pr_err ( " could not get timclk \n " ) ;
2016-06-06 18:58:15 +03:00
return PTR_ERR ( clk ) ;
}
2013-04-03 15:28:26 +04:00
irq = irq_of_parse_and_map ( node , 0 ) ;
2016-06-06 18:58:15 +03:00
if ( irq < = 0 ) {
2017-03-09 12:47:10 +03:00
pr_err ( " Can't parse IRQ \n " ) ;
2016-06-06 18:58:15 +03:00
return - EINVAL ;
}
2013-04-03 15:28:26 +04:00
2016-06-06 18:58:15 +03:00
return nmdk_timer_init ( base , irq , pclk , clk ) ;
2013-04-03 15:28:26 +04:00
}
2017-05-26 17:56:11 +03:00
TIMER_OF_DECLARE ( nomadik_mtu , " st,nomadik-mtu " ,
2013-04-03 15:28:26 +04:00
nmdk_timer_of_init ) ;