2006-09-18 23:18:16 +01: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 17:13:34 +01:00
# include <asm/arch/time.h>
2006-09-18 23:18:16 +01:00
static unsigned long ticks_per_jiffy ;
static unsigned long ticks_per_usec ;
static unsigned long next_jiffy_time ;
2007-02-13 17:13:34 +01:00
unsigned long iop_gettimeoffset ( void )
2006-09-18 23:18:16 +01:00
{
2007-02-13 17:13:34 +01:00
unsigned long offset , temp1 , temp2 ;
/* 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 "
" ands %1, %0, #(1 << 6) \n \t "
" orreq %0, %0, #(1 << 6) \n \t "
" mcreq p15, 0, %0, c15, c1, 0 \n \t "
# ifdef CONFIG_XSCALE
" mrceq p15, 0, %0, c15, c1, 0 \n \t "
" moveq %0, %0 \n \t "
" subeq pc, pc, #4 \n \t "
# endif
: " =r " ( temp1 ) , " =r " ( temp2 ) : : " cc " ) ;
2006-09-18 23:18:16 +01:00
2007-02-13 17:13:34 +01:00
offset = next_jiffy_time - read_tcr1 ( ) ;
2006-09-18 23:18:16 +01:00
return offset / ticks_per_usec ;
}
static irqreturn_t
2007-02-13 17:13:34 +01:00
iop_timer_interrupt ( int irq , void * dev_id )
2006-09-18 23:18:16 +01:00
{
write_seqlock ( & xtime_lock ) ;
2007-02-13 17:13:34 +01:00
write_tisr ( 1 ) ;
2006-09-18 23:18:16 +01:00
2007-02-13 17:13:34 +01:00
while ( ( signed long ) ( next_jiffy_time - read_tcr1 ( ) )
> = ticks_per_jiffy ) {
2006-10-06 10:53:39 -07:00
timer_tick ( ) ;
2006-09-18 23:18:16 +01:00
next_jiffy_time - = ticks_per_jiffy ;
}
write_sequnlock ( & xtime_lock ) ;
return IRQ_HANDLED ;
}
2007-02-13 17:13:34 +01:00
static struct irqaction iop_timer_irq = {
. name = " IOP Timer Tick " ,
. handler = iop_timer_interrupt ,
2006-09-18 23:18:16 +01:00
. flags = IRQF_DISABLED | IRQF_TIMER ,
} ;
2007-02-13 17:13:34 +01:00
void __init iop_init_time ( unsigned long tick_rate )
2006-09-18 23:18:16 +01:00
{
u32 timer_ctl ;
ticks_per_jiffy = ( tick_rate + HZ / 2 ) / HZ ;
ticks_per_usec = tick_rate / 1000000 ;
next_jiffy_time = 0xffffffff ;
2007-02-13 17:13:34 +01:00
timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1 ;
2006-09-18 23:18:16 +01:00
/*
* We use timer 0 for our timer interrupt , and timer 1 as
* monotonic counter for tracking missed jiffies .
*/
2007-02-13 17:13:34 +01:00
write_trr0 ( ticks_per_jiffy - 1 ) ;
write_tmr0 ( timer_ctl ) ;
write_trr1 ( 0xffffffff ) ;
write_tmr1 ( timer_ctl ) ;
2006-09-18 23:18:16 +01:00
2007-02-13 17:13:34 +01:00
setup_irq ( IRQ_IOP_TIMER0 , & iop_timer_irq ) ;
2006-09-18 23:18:16 +01:00
}