ARM support for hrtimers, dyntick
Subsystems (7)
cover ARM support for hrtimers, dyntick
Here is support for hrtimers and dyntick on a few ARM platforms:
ixp4xx, versatile and OMAP. Patches are against today's Linus git tree.
For the time being, LED support is missing as the ARM-specific do_leds() is no longer used. Based on feedback from my previous RFC, I think the right thing to do is to migrate any LED drivers to the new drivers/led framework.
Kevin
RFC PATCH 1/7 ARM: build fixups for hrtimers
kernel/time/tick-sched.c +2 -0
@@ -21,6 +21,8 @@#include <linux/sched.h> #include <linux/tick.h> +#include <asm/irq_regs.h> +#include "tick-internal.h" /*
--
Re: [RFC, PATCH 1/7] ARM: build fixups for hrtimers
kernel/time/tick-sched.c line 26
Quoted 13 lines · Kevin Hilman
Signed-off-by Kevin Hilman <[email protected]>Index:
linux-2.6/kernel/time/tick-sched.c
===================================================================kernel/time/tick-sched.c +2
-0@@ -21,6 +21,8 @@#include <linux/sched.h> #include <linux/tick.h> +#include <asm/irq_regs.h> +#include "tick-internal.h"
Went in already via 9e203bcc1051cac2a8b15c3ee9db4c0d05794abe
tglx
-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
RFC PATCH 2/7 ARM: Kconfig support for GENERIC_CLOCKEVENTS
In reply to Kevin Hilmanarch/arm/Kconfig +7 -0
@@ -25,6 +25,10 @@ config GENERIC_TIME bool default n +config GENERIC_CLOCKEVENTS + bool + default n + config MMU bool default y
@@ -480,6 +484,8 @@ endmenu menu "Kernel Features" +source "kernel/time/Kconfig" + config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" depends on EXPERIMENTAL && REALVIEW_MPCORE
@@ -539,6 +545,7 @@ config PREEMPT config NO_IDLE_HZ bool "Dynamic tick timer" + depends on !GENERIC_CLOCKEVENTS help Select this option if you want to disable continuous timer ticks and have them programmed to occur as required. This option saves
--
Re: [RFC, PATCH 2/7] ARM: Kconfig support for GENERIC_CLOCKEVENTS
Quoted 2 lines · Kevin Hilman
plain text document attachment (arm-kconfig-clockevents.patch)
Signed-off-by Kevin Hilman <[email protected]>
-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
RFC PATCH 3/7 ARM: dynamic tick support in idle loop
In reply to Kevin Hilmanarch/arm/kernel/process.c +3 -0
@@ -28,6 +28,7 @@#include <linux/cpu.h> #include <linux/elfcore.h> #include <linux/pm.h> +#include <linux/tick.h> #include <asm/leds.h> #include <asm/processor.h>
@@ -154,9 +155,11 @@ void cpu_idle(void)if (!idle) idle = default_idle;leds_event (led_idle_start); +tick_nohz_stop_sched_tick ();while (!need_resched ())idle ();leds_event (led_idle_end); +tick_nohz_restart_sched_tick ();preempt_enable_no_resched ();schedule ();preempt_disable ();
--
RFC PATCH 4/7 ARM: clockevent support for ixp4xx platform
In reply to Kevin Hilmanarch/arm/mach-ixp4xx/common.c +74 -19
@@ -27,6 +27,7 @@#include <linux/time.h> #include <linux/timex.h> #include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/arch/udc.h> #include <asm/hardware.h>
@@ -41,6 +42,8 @@#include <asm/mach/time.h> static int __init ixp4xx_clocksource_init (void ); +static int __init ixp4xx_clockevent_init (void ); +static struct clock_event_device clockevent_ixp4xx;/************************************************************************* * IXP4xx chipset I/O mapping
@@ -239,52 +242,40 @@ void __init ixp4xx_init_irq(void)* counter as a source of real clock ticks to account for missed jiffies. *************************************************************************/ -static unsigned volatile last_jiffy_time; - -#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) -static irqreturn_t ixp4xx_timer_interrupt (int irq,void *dev_id) { -write_seqlock (&xtime_lock); +struct clock_event_device *evt = &clockevent_ixp4xx;/* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST =IXP4XX_OSST_TIMER_1_PEND ; -/* -* Catch up with the real idea of time -*/ -while ((signed long )(*IXP4XX_OSTS - last_jiffy_time) >=LATCH ) { -timer_tick (); - last_jiffy_time +=LATCH ; - } - -write_sequnlock (&xtime_lock); + evt->event_handler (evt);return IRQ_HANDLED ; }static struct irqaction ixp4xx_timer_irq = { - .name ="IXP4xx Timer Tick" , + .name ="timer1" , .flags =IRQF_DISABLED |IRQF_TIMER , .handler = ixp4xx_timer_interrupt, };static void __init ixp4xx_timer_init (void ) { +/* Reset/disable counter */ + *IXP4XX_OSRT1 =0 ; +/* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST =IXP4XX_OSST_TIMER_1_PEND ; -/* Setup the Timer counter value */ - *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK ) |IXP4XX_OST_ENABLE ; -/* Reset time-stamp counter */ *IXP4XX_OSTS =0 ; - last_jiffy_time =0 ;/* Connect the interrupt handler and enable the interrupt */ setup_irq (IRQ_IXP4XX_TIMER1 , &ixp4xx_timer_irq);ixp4xx_clocksource_init (); +ixp4xx_clockevent_init (); }struct sys_timer ixp4xx_timer = {
@@ -384,6 +375,9 @@ void __init ixp4xx_sys_init(void) ixp4xx_exp_bus_size >> 20); } +/* +* clocksource +*/ cycle_t ixp4xx_get_cycles (void ) {return *IXP4XX_OSTS ;
@@ -408,3 +402,64 @@ static int __init ixp4xx_clocksource_inireturn 0 ; } + +/* +* clockevents +*/ +static int ixp4xx_set_next_event (unsigned long evt, +struct clock_event_device *unused) +{ +unsigned long opts = *IXP4XX_OSRT1 &IXP4XX_OST_RELOAD_MASK ; + + *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK ) | opts; + +return 0 ; +} + +static void ixp4xx_set_mode (enum clock_event_mode mode, +struct clock_event_device *evt) +{ +unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK ; + +switch (mode) { +case CLOCK_EVT_MODE_PERIODIC : + osrt =LATCH & ~IXP4XX_OST_RELOAD_MASK ; + opts =IXP4XX_OST_ENABLE ; +break ; +case CLOCK_EVT_MODE_ONESHOT : +/* period set by 'set next_event' */ + osrt =0 ; + opts =IXP4XX_OST_ENABLE |IXP4XX_OST_ONE_SHOT ; +break ; +case CLOCK_EVT_MODE_SHUTDOWN : +case CLOCK_EVT_MODE_UNUSED : +default : + osrt = opts =0 ; +break ; + } + + *IXP4XX_OSRT1 = osrt | opts; +} + +static struct clock_event_device clockevent_ixp4xx = { + .name ="ixp4xx timer1" , + .features =CLOCK_EVT_FEAT_PERIODIC |CLOCK_EVT_FEAT_ONESHOT , + .rating =200 , + .shift =24 , + .set_mode = ixp4xx_set_mode, + .set_next_event = ixp4xx_set_next_event, +}; + +static int __init ixp4xx_clockevent_init (void ) +{ + clockevent_ixp4xx.mult =div_sc (FREQ ,NSEC_PER_SEC , + clockevent_ixp4xx.shift); + clockevent_ixp4xx.max_delta_ns = +clockevent_delta2ns (0xfffffffe , &clockevent_ixp4xx); + clockevent_ixp4xx.min_delta_ns = +clockevent_delta2ns (0xf , &clockevent_ixp4xx); + clockevent_ixp4xx.cpumask =cpumask_of_cpu (0 ); + +clockevents_register_device (&clockevent_ixp4xx); +return 0 ; +}
arch/arm/Kconfig +1 -0
@@ -255,6 +255,7 @@ config ARCH_IXP4XX bool "IXP4xx-based" depends on MMU select GENERIC_TIME + select GENERIC_CLOCKEVENTS help Support for Intel's IXP4XX (XScale) family of processors.
--
RFC PATCH 5/7 ARM: clocksource support for Versatile platform
In reply to Kevin Hilmanarch/arm/mach-versatile/core.c +34 -41
@@ -26,6 +26,7 @@#include <linux/interrupt.h> #include <linux/amba/bus.h> #include <linux/amba/clcd.h> +#include <linux/clocksource.h> #include <asm/cnt32_to_63.h> #include <asm/system.h>
@@ -829,46 +830,6 @@ void __init versatile_init(void)#endif /* -* Returns number of ms since last clock interrupt. Note that interrupts -* will have been disabled by do_gettimeoffset() -*/ -static unsigned long versatile_gettimeoffset (void ) -{ -unsigned long ticks1, ticks2, status; - -/* -* Get the current number of ticks. Note that there is a race -* condition between us reading the timer and checking for -* an interrupt. We get around this by ensuring that the -* counter has not reloaded between our two reads. -*/ - ticks2 =readl (TIMER0_VA_BASE +TIMER_VALUE ) &0xffff ; -do { - ticks1 = ticks2; - status =__raw_readl (VA_IC_BASE +VIC_RAW_STATUS ); - ticks2 =readl (TIMER0_VA_BASE +TIMER_VALUE ) &0xffff ; - }while (ticks2 > ticks1); - -/* -* Number of ticks since last interrupt. -*/ - ticks1 =TIMER_RELOAD - ticks2; - -/* -* Interrupt pending? If so, we've reloaded once already. -* -* FIXME: Need to check this is effectively timer 0 that expires -*/ -if (status &IRQMASK_TIMERINT0_1 ) - ticks1 +=TIMER_RELOAD ; - -/* -* Convert the ticks to usecs -*/ -return TICKS2USECS (ticks1); -} - -/* * IRQ handler for the timer */ static irqreturn_t versatile_timer_interrupt (int irq,void *dev_id)
@@ -891,6 +852,36 @@ static struct irqaction versatile_timer_ .handler = versatile_timer_interrupt, }; +static cycle_t versatile_get_cycles (void ) +{ +return ~readl (TIMER3_VA_BASE +TIMER_VALUE ); +} + +static struct clocksource clocksource_versatile = { + .name ="timer3" , + .rating =200 , + .read = versatile_get_cycles, + .mask =CLOCKSOURCE_MASK (32 ), + .shift =20 , + .flags =CLOCK_SOURCE_IS_CONTINUOUS , +}; + +static int __init versatile_clocksource_init (void ) +{ +/* setup timer3 as free-running clocksource */ +writel (0 ,TIMER3_VA_BASE +TIMER_CTRL ); +writel (0xffffffff ,TIMER3_VA_BASE +TIMER_LOAD ); +writel (0xffffffff ,TIMER3_VA_BASE +TIMER_VALUE ); +writel (TIMER_CTRL_32BIT |TIMER_CTRL_ENABLE |TIMER_CTRL_PERIODIC , +TIMER3_VA_BASE +TIMER_CTRL ); + + clocksource_versatile.mult = +clocksource_khz2mult (1000 , clocksource_versatile.shift); +clocksource_register (&clocksource_versatile); + +return 0 ; +} +/* * Set up timer interrupt, and return the current time in seconds. */
@@ -927,9 +918,11 @@ static void __init versatile_timer_init(* Make irqs happen for the system timer */ setup_irq (IRQ_TIMERINT0_1 , &versatile_timer_irq); + +versatile_clocksource_init (); }struct sys_timer versatile_timer = { .init = versatile_timer_init, - .offset = versatile_gettimeoffset, }; +
arch/arm/Kconfig +1 -0
@@ -162,6 +162,7 @@ config ARCH_VERSATILE select ARM_AMBA select ARM_VIC select ICST307 + select GENERIC_TIME help This enables support for ARM Ltd Versatile board.
--
RFC PATCH 6/7 ARM: clockevent support for Versatile platform
In reply to Kevin Hilmanarch/arm/mach-versatile/core.c +58 -10
@@ -27,6 +27,7 @@#include <linux/amba/bus.h> #include <linux/amba/clcd.h> #include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/cnt32_to_63.h> #include <asm/system.h>
@@ -829,19 +830,61 @@ void __init versatile_init(void)#define TICKS2USECS (x) ((x) / TICKS_PER_uSEC)#endif +static void timer_set_mode (enum clock_event_mode mode, +struct clock_event_device *clk) +{ +unsigned long ctrl; + +switch (mode) { +case CLOCK_EVT_MODE_PERIODIC : +writel (TIMER_RELOAD ,TIMER0_VA_BASE +TIMER_LOAD ); + + ctrl =TIMER_CTRL_PERIODIC ; + ctrl |=TIMER_CTRL_32BIT |TIMER_CTRL_IE |TIMER_CTRL_ENABLE ; +break ; +case CLOCK_EVT_MODE_ONESHOT : +/* period set, and timer enabled in 'next_event' hook */ + ctrl =TIMER_CTRL_ONESHOT ; + ctrl |=TIMER_CTRL_32BIT |TIMER_CTRL_IE ; +break ; +case CLOCK_EVT_MODE_UNUSED : +case CLOCK_EVT_MODE_SHUTDOWN : +default : + ctrl =0 ; + } + +writel (ctrl,TIMER0_VA_BASE +TIMER_CTRL ); +} + +static int timer_set_next_event (unsigned long evt, +struct clock_event_device *unused) +{ +unsigned long ctrl =readl (TIMER0_VA_BASE +TIMER_CTRL ); + +writel (evt,TIMER0_VA_BASE +TIMER_LOAD ); +writel (ctrl |TIMER_CTRL_ENABLE ,TIMER0_VA_BASE +TIMER_CTRL ); + +return 0 ; +} + +static struct clock_event_device timer0_clockevent = { + .name ="timer0" , + .shift =32 , + .features =CLOCK_EVT_FEAT_PERIODIC |CLOCK_EVT_FEAT_ONESHOT , + .set_mode = timer_set_mode, + .set_next_event = timer_set_next_event, +}; +/* * IRQ handler for the timer */ static irqreturn_t versatile_timer_interrupt (int irq,void *dev_id) { -write_seqlock (&xtime_lock); +struct clock_event_device *evt = &timer0_clockevent; -// ...clear the interrupt writel (1 ,TIMER0_VA_BASE +TIMER_INTCLR ); -timer_tick (); - -write_sequnlock (&xtime_lock); + evt->event_handler (evt);return IRQ_HANDLED ; }
@@ -909,17 +952,22 @@ static void __init versatile_timer_init(writel (0 ,TIMER2_VA_BASE +TIMER_CTRL );writel (0 ,TIMER3_VA_BASE +TIMER_CTRL ); -writel (TIMER_RELOAD ,TIMER0_VA_BASE +TIMER_LOAD ); -writel (TIMER_RELOAD ,TIMER0_VA_BASE +TIMER_VALUE ); -writel (TIMER_DIVISOR |TIMER_CTRL_ENABLE |TIMER_CTRL_PERIODIC | -TIMER_CTRL_IE ,TIMER0_VA_BASE +TIMER_CTRL ); -/* * Make irqs happen for the system timer */ setup_irq (IRQ_TIMERINT0_1 , &versatile_timer_irq);versatile_clocksource_init (); + + timer0_clockevent.mult = +div_sc (1000000 ,NSEC_PER_SEC , timer0_clockevent.shift); + timer0_clockevent.max_delta_ns = +clockevent_delta2ns (0xffffffff , &timer0_clockevent); + timer0_clockevent.min_delta_ns = +clockevent_delta2ns (0xf , &timer0_clockevent); + + timer0_clockevent.cpumask =cpumask_of_cpu (0 ); +clockevents_register_device (&timer0_clockevent); }struct sys_timer versatile_timer = {
arch/arm/Kconfig +1 -0
@@ -163,6 +163,7 @@ config ARCH_VERSATILE select ARM_VIC select ICST307 select GENERIC_TIME + select GENERIC_CLOCKEVENTS help This enables support for ARM Ltd Versatile board.
--
RFC PATCH 7/7 ARM: OMAP: clocksource and clockevent support
In reply to Kevin Hilmanarch/arm/mach-omap1/time.c +133 -73
@@ -39,6 +39,10 @@#include <linux/interrupt.h> #include <linux/sched.h> #include <linux/spinlock.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/system.h> #include <asm/hardware.h>
@@ -48,13 +52,7 @@#include <asm/mach/irq.h> #include <asm/mach/time.h> -struct sys_timer omap_timer; -/* -* --------------------------------------------------------------------------- -* MPU timer -* --------------------------------------------------------------------------- -*/ #define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE#define OMAP_MPU_TIMER_OFFSET 0x100
@@ -88,21 +86,6 @@ static inline unsigned long long cycles_return (cyc * cyc2ns_scale) >>CYC2NS_SCALE_FACTOR ; } -/* -* MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs -* will break. On P2, the timer count rate is 6.5 MHz after programming PTV -* with 0. This divides the 13MHz input by 2, and is undocumented. -*/ -#if defined(CONFIG_MACH_OMAP_PERSEUS2 ) || defined(CONFIG_MACH_OMAP_FSAMPLE ) -/* REVISIT: This ifdef construct should be replaced by a query to clock -* framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz. -*/ -#define MPU_TICKS_PER_SEC (13000000 / 2) -#else -#define MPU_TICKS_PER_SEC (12000000 / 2) -#endif - -#define MPU_TIMER_TICK_PERIOD ((MPU_TICKS_PER_SEC / HZ) - 1) typedef struct { u32 cntl; /* CNTL_TIMER, R/W */
@@ -120,98 +103,164 @@ static inline unsigned long omap_mpu_timreturn timer->read_tim; } -static inline void omap_mpu_timer_start (int nr,unsigned long load_val) +static inline void omap_mpu_set_autoreset (int nr) +{ +volatile omap_mpu_timer_regs_t * timer =omap_mpu_timer_base (nr); + + timer->cntl = timer->cntl |MPU_TIMER_AR ; +} + +static inline void omap_mpu_remove_autoreset (int nr) +{ +volatile omap_mpu_timer_regs_t * timer =omap_mpu_timer_base (nr); + + timer->cntl = timer->cntl & ~MPU_TIMER_AR ; +} + +static inline void omap_mpu_timer_start (int nr,unsigned long load_val, +int autoreset) {volatile omap_mpu_timer_regs_t * timer =omap_mpu_timer_base (nr); +unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE |MPU_TIMER_ST ); + +if (autoreset) timerflags |=MPU_TIMER_AR ; timer->cntl =MPU_TIMER_CLOCK_ENABLE ;udelay (1 ); timer->load_tim = load_val;udelay (1 ); - timer->cntl = (MPU_TIMER_CLOCK_ENABLE |MPU_TIMER_AR |MPU_TIMER_ST ); + timer->cntl = timerflags; +} + +/* +* --------------------------------------------------------------------------- +* MPU timer 1 ... count down to zero, interrupt, reload +* --------------------------------------------------------------------------- +*/ +static int omap_mpu_set_next_event (unsigned long cycles, +struct clock_event_device *evt) +{ +omap_mpu_timer_start (0 , cycles,0 ); +return 0 ; } -unsigned long omap_mpu_timer_ticks_to_usecs (unsigned long nr_ticks) +static void omap_mpu_set_mode (enum clock_event_mode mode, +struct clock_event_device *evt) +{ +switch (mode) { +case CLOCK_EVT_MODE_PERIODIC : +omap_mpu_set_autoreset (0 ); +break ; +case CLOCK_EVT_MODE_ONESHOT : +omap_mpu_remove_autoreset (0 ); +break ; +case CLOCK_EVT_MODE_UNUSED : +case CLOCK_EVT_MODE_SHUTDOWN : +break ; + } +} + +static struct clock_event_device clockevent_mpu_timer1 = { + .name ="mpu_timer1" , + .features =CLOCK_EVT_FEAT_PERIODIC ,CLOCK_EVT_FEAT_ONESHOT , + .shift =32 , + .set_next_event = omap_mpu_set_next_event, + .set_mode = omap_mpu_set_mode, +}; + +static irqreturn_t omap_mpu_timer1_interrupt (int irq,void *dev_id) { -unsigned long long nsec; +struct clock_event_device *evt = &clockevent_mpu_timer1; + + evt->event_handler (evt); - nsec =cycles_2_ns ((unsigned long long )nr_ticks); -return (unsigned long )nsec /1000 ; +return IRQ_HANDLED ; } -/* -* Last processed system timer interrupt -*/ -static unsigned long omap_mpu_timer_last =0 ; +static struct irqaction omap_mpu_timer1_irq = { + .name ="mpu_timer1" , + .flags =IRQF_DISABLED |IRQF_TIMER , + .handler = omap_mpu_timer1_interrupt, +}; -/* -* Returns elapsed usecs since last system timer interrupt -*/ -static unsigned long omap_mpu_timer_gettimeoffset (void ) +static __init void omap_init_mpu_timer (unsigned long rate) { -unsigned long now =0 -omap_mpu_timer_read (0 ); -unsigned long elapsed = now - omap_mpu_timer_last; +set_cyc2ns_scale (rate /1000 ); + +setup_irq (INT_TIMER1 , &omap_mpu_timer1_irq); +omap_mpu_timer_start (0 , (rate /HZ ) -1 ,1 ); + + clockevent_mpu_timer1.mult =div_sc (rate,NSEC_PER_SEC , + clockevent_mpu_timer1.shift); + clockevent_mpu_timer1.max_delta_ns = +clockevent_delta2ns (-1 , &clockevent_mpu_timer1); + clockevent_mpu_timer1.min_delta_ns = +clockevent_delta2ns (1 , &clockevent_mpu_timer1); -return omap_mpu_timer_ticks_to_usecs (elapsed); + clockevent_mpu_timer1.cpumask =cpumask_of_cpu (0 ); +clockevents_register_device (&clockevent_mpu_timer1); } +/* -* Elapsed time between interrupts is calculated using timer0. -* Latency during the interrupt is calculated using timer1. -* Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz). +* --------------------------------------------------------------------------- +* MPU timer 2 ... free running 32-bit clock source and scheduler clock +* --------------------------------------------------------------------------- */ -static irqreturn_t omap_mpu_timer_interrupt (int irq,void *dev_id) -{ -unsigned long now, latency; -write_seqlock (&xtime_lock); - now =0 -omap_mpu_timer_read (0 ); - latency =MPU_TICKS_PER_SEC /HZ -omap_mpu_timer_read (1 ); - omap_mpu_timer_last = now - latency; -timer_tick (); -write_sequnlock (&xtime_lock); +static unsigned long omap_mpu_timer2_overflows; +static irqreturn_t omap_mpu_timer2_interrupt (int irq,void *dev_id) +{ + omap_mpu_timer2_overflows++;return IRQ_HANDLED ; } -static struct irqaction omap_mpu_timer_irq = { - .name ="mpu timer" , - .flags =IRQF_DISABLED |IRQF_TIMER , - .handler = omap_mpu_timer_interrupt, +static struct irqaction omap_mpu_timer2_irq = { + .name ="mpu_timer2" , + .flags =IRQF_DISABLED , + .handler = omap_mpu_timer2_interrupt, }; -static unsigned long omap_mpu_timer1_overflows; -static irqreturn_t omap_mpu_timer1_interrupt (int irq,void *dev_id) +static cycle_t mpu_read (void ) { - omap_mpu_timer1_overflows++; -return IRQ_HANDLED ; +return ~omap_mpu_timer_read (1 ); } -static struct irqaction omap_mpu_timer1_irq = { - .name ="mpu timer1 overflow" , - .flags =IRQF_DISABLED , - .handler = omap_mpu_timer1_interrupt, +static struct clocksource clocksource_mpu = { + .name ="mpu_timer2" , + .rating =300 , + .read = mpu_read, + .mask =CLOCKSOURCE_MASK (32 ), + .shift =24 , + .flags =CLOCK_SOURCE_IS_CONTINUOUS , }; -static __init void omap_init_mpu_timer (void ) +static void __init omap_init_clocksource (unsigned long rate) { -set_cyc2ns_scale (MPU_TICKS_PER_SEC /1000 ); - omap_timer.offset = omap_mpu_timer_gettimeoffset; -setup_irq (INT_TIMER1 , &omap_mpu_timer1_irq); -setup_irq (INT_TIMER2 , &omap_mpu_timer_irq); -omap_mpu_timer_start (0 ,0xffffffff ); -omap_mpu_timer_start (1 ,MPU_TIMER_TICK_PERIOD ); +static char err[]__initdata =KERN_ERR +"%s: can't register clocksource!\n" ; + + clocksource_mpu.mult + =clocksource_khz2mult (rate/1000 , clocksource_mpu.shift); + +setup_irq (INT_TIMER2 , &omap_mpu_timer2_irq); +omap_mpu_timer_start (1 , ~0 ,1 ); + +if (clocksource_register (&clocksource_mpu)) +printk (err, clocksource_mpu.name); } +/* * Scheduler clock - returns current time in nanosec units. */ unsigned long long sched_clock (void ) { -unsigned long ticks =0 -omap_mpu_timer_read (0 ); +unsigned long ticks =0 -omap_mpu_timer_read (1 );unsigned long long ticks64; - ticks64 = omap_mpu_timer1_overflows; + ticks64 = omap_mpu_timer2_overflows; ticks64 <<=32 ; ticks64 |= ticks;
@@ -225,10 +274,21 @@ unsigned long long sched_clock(void)*/ static void __init omap_timer_init (void ) { -omap_init_mpu_timer (); +struct clk *ck_ref =clk_get (NULL ,"ck_ref" ); +unsigned long rate; + +BUG_ON (IS_ERR (ck_ref)); + + rate =clk_get_rate (ck_ref); +clk_put (ck_ref); + +/* PTV = 0 */ + rate /=2 ; + +omap_init_mpu_timer (rate); +omap_init_clocksource (rate); }struct sys_timer omap_timer = { .init = omap_timer_init, - .offset =NULL ,/* Initialized later */ };
arch/arm/plat-omap/Kconfig +1 -0
@@ -11,6 +11,7 @@ choice config ARCH_OMAP1 bool "TI OMAP1" + select GENERIC_CLOCKEVENTS config ARCH_OMAP2 bool "TI OMAP2"
arch/arm/plat-omap/common.c +50 -0
53 lines not on this page · raw message
arch/arm/plat-omap/timer32k.c +39 -100
199 lines not on this page · raw message
arch/arm/Kconfig +1 -0
@@ -346,6 +346,7 @@ config ARCH_LH7A40X config ARCH_OMAP bool "TI OMAP" + select GENERIC_TIME help Support for TI's OMAP platform (OMAP1 and OMAP2).
--