2006-09-19 02:18:16 +04:00
/*
* arch / arm / plat - iop / time . c
*
* Timer code for IOP32x and IOP33x based systems
*
* Author : Deepak Saxena < dsaxena @ mvista . com >
*
* Copyright 2002 - 2003 MontaVista Software Inc .
*
* 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 .
*/
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/time.h>
# include <linux/init.h>
# include <linux/timex.h>
# include <asm/hardware.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/uaccess.h>
# include <asm/mach/irq.h>
# include <asm/mach/time.h>
2007-02-13 19:13:34 +03:00
# include <asm/arch/time.h>
2006-09-19 02:18:16 +04:00
static unsigned long ticks_per_jiffy ;
static unsigned long ticks_per_usec ;
static unsigned long next_jiffy_time ;
2007-02-13 19:13:34 +03:00
unsigned long iop_gettimeoffset ( void )
2006-09-19 02:18:16 +04:00
{
2007-04-29 12:31:21 +04:00
unsigned long offset , temp ;
2007-02-13 19:13:34 +03:00
/* enable cp6, if necessary, to avoid taking the overhead of an
* undefined instruction trap
*/
asm volatile (
" mrc p15, 0, %0, c15, c1, 0 \n \t "
2007-04-29 12:31:21 +04:00
" tst %0, #(1 << 6) \n \t "
2007-02-13 19:13:34 +03:00
" orreq %0, %0, #(1 << 6) \n \t "
" mcreq p15, 0, %0, c15, c1, 0 \n \t "
2007-04-29 12:31:21 +04:00
# ifdef CONFIG_CPU_XSCALE
2007-02-13 19:13:34 +03:00
" mrceq p15, 0, %0, c15, c1, 0 \n \t "
" moveq %0, %0 \n \t "
" subeq pc, pc, #4 \n \t "
# endif
2007-04-29 12:31:21 +04:00
: " =r " ( temp ) : : " cc " ) ;
2006-09-19 02:18:16 +04:00
2007-02-13 19:13:34 +03:00
offset = next_jiffy_time - read_tcr1 ( ) ;
2006-09-19 02:18:16 +04:00
return offset / ticks_per_usec ;
}
static irqreturn_t
2007-02-13 19:13:34 +03:00
iop_timer_interrupt ( int irq , void * dev_id )
2006-09-19 02:18:16 +04:00
{
write_seqlock ( & xtime_lock ) ;
2007-02-13 19:13:34 +03:00
write_tisr ( 1 ) ;
2006-09-19 02:18:16 +04:00
2007-02-13 19:13:34 +03:00
while ( ( signed long ) ( next_jiffy_time - read_tcr1 ( ) )
> = ticks_per_jiffy ) {
2006-10-06 21:53:39 +04:00
timer_tick ( ) ;
2006-09-19 02:18:16 +04:00
next_jiffy_time - = ticks_per_jiffy ;
}
write_sequnlock ( & xtime_lock ) ;
return IRQ_HANDLED ;
}
2007-02-13 19:13:34 +03:00
static struct irqaction iop_timer_irq = {
. name = " IOP Timer Tick " ,
. handler = iop_timer_interrupt ,
2007-05-08 11:35:39 +04:00
. flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
2006-09-19 02:18:16 +04:00
} ;
2007-07-20 05:07:26 +04:00
static unsigned long iop_tick_rate ;
unsigned long get_iop_tick_rate ( void )
{
return iop_tick_rate ;
}
EXPORT_SYMBOL ( get_iop_tick_rate ) ;
2007-02-13 19:13:34 +03:00
void __init iop_init_time ( unsigned long tick_rate )
2006-09-19 02:18:16 +04:00
{
u32 timer_ctl ;
ticks_per_jiffy = ( tick_rate + HZ / 2 ) / HZ ;
ticks_per_usec = tick_rate / 1000000 ;
next_jiffy_time = 0xffffffff ;
2007-07-20 05:07:26 +04:00
iop_tick_rate = tick_rate ;
2006-09-19 02:18:16 +04:00
2007-02-13 19:13:34 +03:00
timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1 ;
2006-09-19 02:18:16 +04:00
/*
* We use timer 0 for our timer interrupt , and timer 1 as
* monotonic counter for tracking missed jiffies .
*/
2007-02-13 19:13:34 +03:00
write_trr0 ( ticks_per_jiffy - 1 ) ;
write_tmr0 ( timer_ctl ) ;
write_trr1 ( 0xffffffff ) ;
write_tmr1 ( timer_ctl ) ;
2006-09-19 02:18:16 +04:00
2007-02-13 19:13:34 +03:00
setup_irq ( IRQ_IOP_TIMER0 , & iop_timer_irq ) ;
2006-09-19 02:18:16 +04:00
}