2010-12-18 16:39:30 +03:00
/*
* Copyright ( C ) 2000 - 2001 Deep Blue Solutions
* Copyright ( C ) 2002 Shane Nay ( shane @ minirl . com )
* Copyright ( C ) 2006 - 2007 Pavel Pisa ( ppisa @ pikron . com )
* Copyright ( C ) 2008 Juergen Beisert ( kernel @ pengutronix . de )
* Copyright ( C ) 2010 Freescale Semiconductor , Inc . All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*/
2012-04-28 20:02:37 +04:00
# include <linux/err.h>
2010-12-18 16:39:30 +03:00
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/clockchips.h>
# include <linux/clk.h>
2012-08-20 04:51:45 +04:00
# include <linux/of.h>
2013-03-25 10:57:41 +04:00
# include <linux/of_address.h>
2012-08-20 04:51:45 +04:00
# include <linux/of_irq.h>
2013-03-25 16:04:34 +04:00
# include <linux/stmp_device.h>
2013-06-02 10:39:40 +04:00
# include <linux/sched_clock.h>
2010-12-18 16:39:30 +03:00
# include <asm/mach/time.h>
/*
* There are 2 versions of the timrot on Freescale MXS - based SoCs .
* The v1 on MX23 only gets 16 bits counter , while v2 on MX28
* extends the counter to 32 bits .
*
* The implementation uses two timers , one for clock_event and
* another for clocksource . MX28 uses timrot 0 and 1 , while MX23
* uses 0 and 2.
*/
# define MX23_TIMROT_VERSION_OFFSET 0x0a0
# define MX28_TIMROT_VERSION_OFFSET 0x120
# define BP_TIMROT_MAJOR_VERSION 24
# define BV_TIMROT_VERSION_1 0x01
# define BV_TIMROT_VERSION_2 0x02
# define timrot_is_v1() (timrot_major_version == BV_TIMROT_VERSION_1)
/*
* There are 4 registers for each timrotv2 instance , and 2 registers
* for each timrotv1 . So address step 0x40 in macros below strides
* one instance of timrotv2 while two instances of timrotv1 .
*
* As the result , HW_TIMROT_XXXn ( 1 ) defines the address of timrot1
* on MX28 while timrot2 on MX23 .
*/
/* common between v1 and v2 */
# define HW_TIMROT_ROTCTRL 0x00
# define HW_TIMROT_TIMCTRLn(n) (0x20 + (n) * 0x40)
/* v1 only */
# define HW_TIMROT_TIMCOUNTn(n) (0x30 + (n) * 0x40)
/* v2 only */
# define HW_TIMROT_RUNNING_COUNTn(n) (0x30 + (n) * 0x40)
# define HW_TIMROT_FIXED_COUNTn(n) (0x40 + (n) * 0x40)
# define BM_TIMROT_TIMCTRLn_RELOAD (1 << 6)
# define BM_TIMROT_TIMCTRLn_UPDATE (1 << 7)
# define BM_TIMROT_TIMCTRLn_IRQ_EN (1 << 14)
# define BM_TIMROT_TIMCTRLn_IRQ (1 << 15)
# define BP_TIMROT_TIMCTRLn_SELECT 0
2012-12-21 18:06:15 +04:00
# define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL 0x8
# define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL 0xb
# define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS 0xf
2010-12-18 16:39:30 +03:00
static struct clock_event_device mxs_clockevent_device ;
static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED ;
2013-03-25 10:57:41 +04:00
static void __iomem * mxs_timrot_base ;
2010-12-18 16:39:30 +03:00
static u32 timrot_major_version ;
static inline void timrot_irq_disable ( void )
{
2013-03-25 16:04:34 +04:00
__raw_writel ( BM_TIMROT_TIMCTRLn_IRQ_EN , mxs_timrot_base +
HW_TIMROT_TIMCTRLn ( 0 ) + STMP_OFFSET_REG_CLR ) ;
2010-12-18 16:39:30 +03:00
}
static inline void timrot_irq_enable ( void )
{
2013-03-25 16:04:34 +04:00
__raw_writel ( BM_TIMROT_TIMCTRLn_IRQ_EN , mxs_timrot_base +
HW_TIMROT_TIMCTRLn ( 0 ) + STMP_OFFSET_REG_SET ) ;
2010-12-18 16:39:30 +03:00
}
static void timrot_irq_acknowledge ( void )
{
2013-03-25 16:04:34 +04:00
__raw_writel ( BM_TIMROT_TIMCTRLn_IRQ , mxs_timrot_base +
HW_TIMROT_TIMCTRLn ( 0 ) + STMP_OFFSET_REG_CLR ) ;
2010-12-18 16:39:30 +03:00
}
static cycle_t timrotv1_get_cycles ( struct clocksource * cs )
{
return ~ ( ( __raw_readl ( mxs_timrot_base + HW_TIMROT_TIMCOUNTn ( 1 ) )
& 0xffff0000 ) > > 16 ) ;
}
static int timrotv1_set_next_event ( unsigned long evt ,
struct clock_event_device * dev )
{
/* timrot decrements the count */
__raw_writel ( evt , mxs_timrot_base + HW_TIMROT_TIMCOUNTn ( 0 ) ) ;
return 0 ;
}
static int timrotv2_set_next_event ( unsigned long evt ,
struct clock_event_device * dev )
{
/* timrot decrements the count */
__raw_writel ( evt , mxs_timrot_base + HW_TIMROT_FIXED_COUNTn ( 0 ) ) ;
return 0 ;
}
static irqreturn_t mxs_timer_interrupt ( int irq , void * dev_id )
{
struct clock_event_device * evt = dev_id ;
timrot_irq_acknowledge ( ) ;
evt - > event_handler ( evt ) ;
return IRQ_HANDLED ;
}
static struct irqaction mxs_timer_irq = {
. name = " MXS Timer Tick " ,
. dev_id = & mxs_clockevent_device ,
. flags = IRQF_TIMER | IRQF_IRQPOLL ,
. handler = mxs_timer_interrupt ,
} ;
# ifdef DEBUG
static const char * clock_event_mode_label [ ] const = {
[ CLOCK_EVT_MODE_PERIODIC ] = " CLOCK_EVT_MODE_PERIODIC " ,
[ CLOCK_EVT_MODE_ONESHOT ] = " CLOCK_EVT_MODE_ONESHOT " ,
[ CLOCK_EVT_MODE_SHUTDOWN ] = " CLOCK_EVT_MODE_SHUTDOWN " ,
[ CLOCK_EVT_MODE_UNUSED ] = " CLOCK_EVT_MODE_UNUSED "
} ;
# endif /* DEBUG */
static void mxs_set_mode ( enum clock_event_mode mode ,
struct clock_event_device * evt )
{
/* Disable interrupt in timer module */
timrot_irq_disable ( ) ;
if ( mode ! = mxs_clockevent_mode ) {
/* Set event time into the furthest future */
if ( timrot_is_v1 ( ) )
__raw_writel ( 0xffff ,
mxs_timrot_base + HW_TIMROT_TIMCOUNTn ( 1 ) ) ;
else
__raw_writel ( 0xffffffff ,
mxs_timrot_base + HW_TIMROT_FIXED_COUNTn ( 1 ) ) ;
/* Clear pending interrupt */
timrot_irq_acknowledge ( ) ;
}
# ifdef DEBUG
pr_info ( " %s: changing mode from %s to %s \n " , __func__ ,
clock_event_mode_label [ mxs_clockevent_mode ] ,
clock_event_mode_label [ mode ] ) ;
# endif /* DEBUG */
/* Remember timer mode */
mxs_clockevent_mode = mode ;
switch ( mode ) {
case CLOCK_EVT_MODE_PERIODIC :
pr_err ( " %s: Periodic mode is not implemented \n " , __func__ ) ;
break ;
case CLOCK_EVT_MODE_ONESHOT :
timrot_irq_enable ( ) ;
break ;
case CLOCK_EVT_MODE_SHUTDOWN :
case CLOCK_EVT_MODE_UNUSED :
case CLOCK_EVT_MODE_RESUME :
/* Left event sources disabled, no more interrupts appear */
break ;
}
}
static struct clock_event_device mxs_clockevent_device = {
. name = " mxs_timrot " ,
. features = CLOCK_EVT_FEAT_ONESHOT ,
. set_mode = mxs_set_mode ,
. set_next_event = timrotv2_set_next_event ,
. rating = 200 ,
} ;
static int __init mxs_clockevent_init ( struct clk * timer_clk )
{
2013-01-12 15:50:05 +04:00
if ( timrot_is_v1 ( ) )
2010-12-18 16:39:30 +03:00
mxs_clockevent_device . set_next_event = timrotv1_set_next_event ;
2013-01-12 15:50:05 +04:00
mxs_clockevent_device . cpumask = cpumask_of ( 0 ) ;
clockevents_config_and_register ( & mxs_clockevent_device ,
2012-12-21 18:06:16 +04:00
clk_get_rate ( timer_clk ) ,
timrot_is_v1 ( ) ? 0xf : 0x2 ,
2013-01-12 15:50:05 +04:00
timrot_is_v1 ( ) ? 0xfffe : 0xfffffffe ) ;
2010-12-18 16:39:30 +03:00
return 0 ;
}
static struct clocksource clocksource_mxs = {
. name = " mxs_timer " ,
. rating = 200 ,
2011-05-08 20:21:49 +04:00
. read = timrotv1_get_cycles ,
. mask = CLOCKSOURCE_MASK ( 16 ) ,
2010-12-18 16:39:30 +03:00
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2013-07-19 03:21:23 +04:00
static u64 notrace mxs_read_sched_clock_v2 ( void )
2012-11-09 02:39:14 +04:00
{
return ~ readl_relaxed ( mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn ( 1 ) ) ;
}
2010-12-18 16:39:30 +03:00
static int __init mxs_clocksource_init ( struct clk * timer_clk )
{
unsigned int c = clk_get_rate ( timer_clk ) ;
2011-05-08 20:21:49 +04:00
if ( timrot_is_v1 ( ) )
clocksource_register_hz ( & clocksource_mxs , c ) ;
2012-11-09 02:39:14 +04:00
else {
2011-05-08 20:21:49 +04:00
clocksource_mmio_init ( mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn ( 1 ) ,
" mxs_timer " , c , 200 , 32 , clocksource_mmio_readl_down ) ;
2013-07-19 03:21:23 +04:00
sched_clock_register ( mxs_read_sched_clock_v2 , 32 , c ) ;
2012-11-09 02:39:14 +04:00
}
2010-12-18 16:39:30 +03:00
return 0 ;
}
2013-03-25 10:53:08 +04:00
static void __init mxs_timer_init ( struct device_node * np )
2010-12-18 16:39:30 +03:00
{
2012-04-28 20:02:41 +04:00
struct clk * timer_clk ;
2012-08-20 04:51:45 +04:00
int irq ;
2013-03-25 10:57:41 +04:00
mxs_timrot_base = of_iomap ( np , 0 ) ;
WARN_ON ( ! mxs_timrot_base ) ;
2013-03-25 18:57:14 +04:00
timer_clk = of_clk_get ( np , 0 ) ;
2012-04-28 20:02:41 +04:00
if ( IS_ERR ( timer_clk ) ) {
pr_err ( " %s: failed to get clk \n " , __func__ ) ;
return ;
2012-04-28 20:02:37 +04:00
}
2011-12-20 09:50:11 +04:00
clk_prepare_enable ( timer_clk ) ;
2010-12-18 16:39:30 +03:00
/*
* Initialize timers to a known state
*/
2013-03-25 16:04:34 +04:00
stmp_reset_block ( mxs_timrot_base + HW_TIMROT_ROTCTRL ) ;
2010-12-18 16:39:30 +03:00
/* get timrot version */
timrot_major_version = __raw_readl ( mxs_timrot_base +
2013-03-25 15:41:39 +04:00
( of_device_is_compatible ( np , " fsl,imx23-timrot " ) ?
MX23_TIMROT_VERSION_OFFSET :
2010-12-18 16:39:30 +03:00
MX28_TIMROT_VERSION_OFFSET ) ) ;
timrot_major_version > > = BP_TIMROT_MAJOR_VERSION ;
/* one for clock_event */
__raw_writel ( ( timrot_is_v1 ( ) ?
BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
2012-12-21 18:06:15 +04:00
BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS ) |
2010-12-18 16:39:30 +03:00
BM_TIMROT_TIMCTRLn_UPDATE |
BM_TIMROT_TIMCTRLn_IRQ_EN ,
mxs_timrot_base + HW_TIMROT_TIMCTRLn ( 0 ) ) ;
/* another for clocksource */
__raw_writel ( ( timrot_is_v1 ( ) ?
BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
2012-12-21 18:06:15 +04:00
BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS ) |
2010-12-18 16:39:30 +03:00
BM_TIMROT_TIMCTRLn_RELOAD ,
mxs_timrot_base + HW_TIMROT_TIMCTRLn ( 1 ) ) ;
/* set clocksource timer fixed count to the maximum */
if ( timrot_is_v1 ( ) )
__raw_writel ( 0xffff ,
mxs_timrot_base + HW_TIMROT_TIMCOUNTn ( 1 ) ) ;
else
__raw_writel ( 0xffffffff ,
mxs_timrot_base + HW_TIMROT_FIXED_COUNTn ( 1 ) ) ;
/* init and register the timer to the framework */
mxs_clocksource_init ( timer_clk ) ;
mxs_clockevent_init ( timer_clk ) ;
/* Make irqs happen */
2012-08-20 04:51:45 +04:00
irq = irq_of_parse_and_map ( np , 0 ) ;
2010-12-18 16:39:30 +03:00
setup_irq ( irq , & mxs_timer_irq ) ;
}
2013-04-02 20:30:32 +04:00
CLOCKSOURCE_OF_DECLARE ( mxs , " fsl,timrot " , mxs_timer_init ) ;