2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-17 02:20:36 +04:00
/*
* arch / arm / mach - pxa / time . c
*
2007-07-21 06:39:36 +04:00
* PXA clocksource , clockevents , and OST interrupt handlers .
* Copyright ( c ) 2007 by Bill Gatliff < bgat @ billgatliff . com > .
*
* Derived from Nicolas Pitre ' s PXA timer handler Copyright ( c ) 2001
* by MontaVista Software , Inc . ( Nico , your code rocks ! )
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/interrupt.h>
2014-07-14 20:52:02 +04:00
# include <linux/clk.h>
2007-07-21 06:39:36 +04:00
# include <linux/clockchips.h>
2014-07-14 20:52:02 +04:00
# include <linux/of_address.h>
# include <linux/of_irq.h>
2017-02-01 18:36:40 +03:00
# include <linux/sched/clock.h>
2013-06-02 10:39:40 +04:00
# include <linux/sched_clock.h>
2007-07-21 06:39:36 +04:00
2016-08-23 18:19:29 +03:00
# include <clocksource/pxa.h>
2007-08-17 19:55:22 +04:00
# include <asm/div64.h>
2014-07-14 20:52:02 +04:00
# define OSMR0 0x00 /* OS Timer 0 Match Register */
# define OSMR1 0x04 /* OS Timer 1 Match Register */
# define OSMR2 0x08 /* OS Timer 2 Match Register */
# define OSMR3 0x0C /* OS Timer 3 Match Register */
# define OSCR 0x10 /* OS Timer Counter Register */
# define OSSR 0x14 /* OS Timer Status Register */
# define OWER 0x18 /* OS Timer Watchdog Enable Register */
# define OIER 0x1C /* OS Timer Interrupt Enable Register */
# define OSSR_M3 (1 << 3) /* Match status channel 3 */
# define OSSR_M2 (1 << 2) /* Match status channel 2 */
# define OSSR_M1 (1 << 1) /* Match status channel 1 */
# define OSSR_M0 (1 << 0) /* Match status channel 0 */
# define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */
2005-04-17 02:20:36 +04:00
2007-08-17 19:55:22 +04:00
/*
* This is PXA ' s sched_clock implementation . This has a resolution
* of at least 308 ns and a maximum value of 208 days .
*
* The return value is guaranteed to be monotonic in that range as
* long as there is always less than 582 seconds between successive
* calls to sched_clock ( ) which should always be the case in practice .
*/
2014-07-14 20:52:02 +04:00
# define timer_readl(reg) readl_relaxed(timer_base + (reg))
# define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg))
static void __iomem * timer_base ;
2013-11-16 03:26:19 +04:00
static u64 notrace pxa_read_sched_clock ( void )
2007-08-17 19:55:22 +04:00
{
2014-07-14 20:52:02 +04:00
return timer_readl ( OSCR ) ;
2007-08-17 19:55:22 +04:00
}
2007-11-13 01:45:16 +03:00
# define MIN_OSCR_DELTA 16
2005-04-17 02:20:36 +04:00
static irqreturn_t
2007-07-21 06:39:36 +04:00
pxa_ost0_interrupt ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2007-07-21 06:39:36 +04:00
struct clock_event_device * c = dev_id ;
2007-11-13 01:45:16 +03:00
/* Disarm the compare/match, signal the event. */
2014-07-14 20:52:02 +04:00
timer_writel ( timer_readl ( OIER ) & ~ OIER_E0 , OIER ) ;
timer_writel ( OSSR_M0 , OSSR ) ;
2007-11-13 01:45:16 +03:00
c - > event_handler ( c ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
2007-07-21 06:39:36 +04:00
static int
pxa_osmr0_set_next_event ( unsigned long delta , struct clock_event_device * dev )
{
2009-12-17 14:43:29 +03:00
unsigned long next , oscr ;
2007-07-21 06:39:36 +04:00
2014-07-14 20:52:02 +04:00
timer_writel ( timer_readl ( OIER ) | OIER_E0 , OIER ) ;
next = timer_readl ( OSCR ) + delta ;
timer_writel ( next , OSMR0 ) ;
oscr = timer_readl ( OSCR ) ;
2007-11-09 02:35:46 +03:00
return ( signed ) ( next - oscr ) < = MIN_OSCR_DELTA ? - ETIME : 0 ;
2007-07-21 06:39:36 +04:00
}
2015-06-18 13:54:30 +03:00
static int pxa_osmr0_shutdown ( struct clock_event_device * evt )
2007-07-21 06:39:36 +04:00
{
2015-06-18 13:54:30 +03:00
/* initializing, released, or preparing for suspend */
timer_writel ( timer_readl ( OIER ) & ~ OIER_E0 , OIER ) ;
timer_writel ( OSSR_M0 , OSSR ) ;
return 0 ;
2007-07-21 06:39:36 +04:00
}
2012-11-08 03:34:13 +04:00
# ifdef CONFIG_PM
static unsigned long osmr [ 4 ] , oier , oscr ;
static void pxa_timer_suspend ( struct clock_event_device * cedev )
{
2014-07-14 20:52:02 +04:00
osmr [ 0 ] = timer_readl ( OSMR0 ) ;
osmr [ 1 ] = timer_readl ( OSMR1 ) ;
osmr [ 2 ] = timer_readl ( OSMR2 ) ;
osmr [ 3 ] = timer_readl ( OSMR3 ) ;
oier = timer_readl ( OIER ) ;
oscr = timer_readl ( OSCR ) ;
2012-11-08 03:34:13 +04:00
}
static void pxa_timer_resume ( struct clock_event_device * cedev )
{
/*
* Ensure that we have at least MIN_OSCR_DELTA between match
* register 0 and the OSCR , to guarantee that we will receive
* the one - shot timer interrupt . We adjust OSMR0 in preference
* to OSCR to guarantee that OSCR is monotonically incrementing .
*/
if ( osmr [ 0 ] - oscr < MIN_OSCR_DELTA )
osmr [ 0 ] + = MIN_OSCR_DELTA ;
2014-07-14 20:52:02 +04:00
timer_writel ( osmr [ 0 ] , OSMR0 ) ;
timer_writel ( osmr [ 1 ] , OSMR1 ) ;
timer_writel ( osmr [ 2 ] , OSMR2 ) ;
timer_writel ( osmr [ 3 ] , OSMR3 ) ;
timer_writel ( oier , OIER ) ;
timer_writel ( oscr , OSCR ) ;
2012-11-08 03:34:13 +04:00
}
# else
# define pxa_timer_suspend NULL
# define pxa_timer_resume NULL
# endif
2007-07-21 06:39:36 +04:00
static struct clock_event_device ckevt_pxa_osmr0 = {
2015-06-18 13:54:30 +03:00
. name = " osmr0 " ,
. features = CLOCK_EVT_FEAT_ONESHOT ,
. rating = 200 ,
. set_next_event = pxa_osmr0_set_next_event ,
. set_state_shutdown = pxa_osmr0_shutdown ,
. set_state_oneshot = pxa_osmr0_shutdown ,
. suspend = pxa_timer_suspend ,
. resume = pxa_timer_resume ,
2005-04-17 02:20:36 +04:00
} ;
2007-07-21 06:39:36 +04:00
static struct irqaction pxa_ost0_irq = {
. name = " ost0 " ,
2013-12-09 14:22:22 +04:00
. flags = IRQF_TIMER | IRQF_IRQPOLL ,
2007-07-21 06:39:36 +04:00
. handler = pxa_ost0_interrupt ,
. dev_id = & ckevt_pxa_osmr0 ,
} ;
2016-06-06 18:58:27 +03:00
static int __init pxa_timer_common_init ( int irq , unsigned long clock_tick_rate )
2005-04-17 02:20:36 +04:00
{
2016-06-06 18:58:27 +03:00
int ret ;
2014-07-14 20:52:02 +04:00
timer_writel ( 0 , OIER ) ;
timer_writel ( OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3 , OSSR ) ;
2005-04-17 02:20:36 +04:00
2013-11-16 03:26:19 +04:00
sched_clock_register ( pxa_read_sched_clock , 32 , clock_tick_rate ) ;
2007-08-17 19:55:22 +04:00
2008-12-13 13:50:26 +03:00
ckevt_pxa_osmr0 . cpumask = cpumask_of ( 0 ) ;
2005-04-17 02:20:36 +04:00
2016-06-06 18:58:27 +03:00
ret = setup_irq ( irq , & pxa_ost0_irq ) ;
if ( ret ) {
2017-03-09 12:47:10 +03:00
pr_err ( " Failed to setup irq \n " ) ;
2016-06-06 18:58:27 +03:00
return ret ;
}
ret = clocksource_mmio_init ( timer_base + OSCR , " oscr0 " , clock_tick_rate , 200 ,
32 , clocksource_mmio_readl_up ) ;
if ( ret ) {
2017-03-09 12:47:10 +03:00
pr_err ( " Failed to init clocksource \n " ) ;
2016-06-06 18:58:27 +03:00
return ret ;
}
2005-09-01 15:48:40 +04:00
2013-01-14 22:20:02 +04:00
clockevents_config_and_register ( & ckevt_pxa_osmr0 , clock_tick_rate ,
2014-07-14 20:52:02 +04:00
MIN_OSCR_DELTA * 2 , 0x7fffffff ) ;
2016-06-06 18:58:27 +03:00
return 0 ;
2014-07-14 20:52:02 +04:00
}
2016-06-06 18:58:27 +03:00
static int __init pxa_timer_dt_init ( struct device_node * np )
2014-07-14 20:52:02 +04:00
{
struct clk * clk ;
2016-06-06 18:58:27 +03:00
int irq , ret ;
2014-07-14 20:52:02 +04:00
/* timer registers are shared with watchdog timer */
timer_base = of_iomap ( np , 0 ) ;
2016-06-06 18:58:27 +03:00
if ( ! timer_base ) {
2018-08-28 04:52:14 +03:00
pr_err ( " %pOFn: unable to map resource \n " , np ) ;
2016-06-06 18:58:27 +03:00
return - ENXIO ;
}
2014-07-14 20:52:02 +04:00
clk = of_clk_get ( np , 0 ) ;
if ( IS_ERR ( clk ) ) {
2018-08-28 04:52:14 +03:00
pr_crit ( " %pOFn: unable to get clk \n " , np ) ;
2016-06-06 18:58:27 +03:00
return PTR_ERR ( clk ) ;
}
ret = clk_prepare_enable ( clk ) ;
if ( ret ) {
2017-03-09 12:47:10 +03:00
pr_crit ( " Failed to prepare clock \n " ) ;
2016-06-06 18:58:27 +03:00
return ret ;
2014-07-14 20:52:02 +04:00
}
/* we are only interested in OS-timer0 irq */
irq = irq_of_parse_and_map ( np , 0 ) ;
if ( irq < = 0 ) {
2018-08-28 04:52:14 +03:00
pr_crit ( " %pOFn: unable to parse OS-timer0 irq \n " , np ) ;
2016-06-06 18:58:27 +03:00
return - EINVAL ;
2014-07-14 20:52:02 +04:00
}
2016-06-06 18:58:27 +03:00
return pxa_timer_common_init ( irq , clk_get_rate ( clk ) ) ;
2014-07-14 20:52:02 +04:00
}
2017-05-26 17:56:11 +03:00
TIMER_OF_DECLARE ( pxa_timer , " marvell,pxa-timer " , pxa_timer_dt_init ) ;
2014-07-14 20:52:02 +04:00
/*
* Legacy timer init for non device - tree boards .
*/
2016-09-19 22:12:13 +03:00
void __init pxa_timer_nodt_init ( int irq , void __iomem * base )
2014-07-14 20:52:02 +04:00
{
struct clk * clk ;
timer_base = base ;
clk = clk_get ( NULL , " OSTIMER0 " ) ;
2016-09-19 22:12:13 +03:00
if ( clk & & ! IS_ERR ( clk ) ) {
2014-07-14 20:52:02 +04:00
clk_prepare_enable ( clk ) ;
2016-09-19 22:12:13 +03:00
pxa_timer_common_init ( irq , clk_get_rate ( clk ) ) ;
} else {
2014-07-14 20:52:02 +04:00
pr_crit ( " %s: unable to get clk \n " , __func__ ) ;
2016-09-19 22:12:13 +03:00
}
2005-09-01 15:48:40 +04:00
}