diff options
-rw-r--r-- | arch/arm/mach-pxa/generic.c | 62 | ||||
-rw-r--r-- | arch/arm/mach-pxa/time.c | 39 |
2 files changed, 39 insertions, 62 deletions
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 5510f6fdce5..9d6a2c00d76 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -25,10 +25,6 @@ #include <linux/pm.h> #include <linux/string.h> -#include <linux/sched.h> -#include <asm/cnt32_to_63.h> -#include <asm/div64.h> - #include <asm/hardware.h> #include <asm/irq.h> #include <asm/system.h> @@ -47,64 +43,6 @@ #include "generic.h" /* - * This is the PXA2xx sched_clock implementation. This has a resolution - * of at least 308ns and a maximum value that depends on the value of - * CLOCK_TICK_RATE. - * - * 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 this function. - */ -unsigned long long sched_clock(void) -{ - unsigned long long v = cnt32_to_63(OSCR); - /* Note: top bit ov v needs cleared unless multiplier is even. */ - -#if CLOCK_TICK_RATE == 3686400 - /* 1E9 / 3686400 => 78125 / 288, max value = 32025597s (370 days). */ - /* The <<1 is used to get rid of tick.hi top bit */ - v *= 78125<<1; - do_div(v, 288<<1); -#elif CLOCK_TICK_RATE == 3250000 - /* 1E9 / 3250000 => 4000 / 13, max value = 709490156s (8211 days) */ - v *= 4000; - do_div(v, 13); -#elif CLOCK_TICK_RATE == 3249600 - /* 1E9 / 3249600 => 625000 / 2031, max value = 4541295s (52 days) */ - v *= 625000; - do_div(v, 2031); -#else -#warning "consider fixing sched_clock for your value of CLOCK_TICK_RATE" - /* - * 96-bit math to perform tick * NSEC_PER_SEC / CLOCK_TICK_RATE for - * any value of CLOCK_TICK_RATE. Max value is in the 80 thousand - * years range and truncation to unsigned long long limits it to - * sched_clock's max range of ~584 years. This is nice but with - * higher computation cost. - */ - { - union { - unsigned long long val; - struct { unsigned long lo, hi; }; - } x; - unsigned long long y; - - x.val = v; - x.hi &= 0x7fffffff; - y = (unsigned long long)x.lo * NSEC_PER_SEC; - x.lo = y; - y = (y >> 32) + (unsigned long long)x.hi * NSEC_PER_SEC; - x.hi = do_div(y, CLOCK_TICK_RATE); - do_div(x.val, CLOCK_TICK_RATE); - x.hi += y; - v = x.val; - } -#endif - - return v; -} - -/* * Handy function to set GPIO alternate functions */ diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 98d27e646b0..7916311547c 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -16,11 +16,48 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/clockchips.h> +#include <linux/sched.h> +#include <asm/div64.h> +#include <asm/cnt32_to_63.h> #include <asm/mach/irq.h> #include <asm/mach/time.h> #include <asm/arch/pxa-regs.h> +/* + * 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. + */ + +#define OSCR2NS_SCALE_FACTOR 10 + +static unsigned long oscr2ns_scale; + +static void __init set_oscr2ns_scale(unsigned long oscr_rate) +{ + unsigned long long v = 1000000000ULL << OSCR2NS_SCALE_FACTOR; + do_div(v, oscr_rate); + oscr2ns_scale = v; + /* + * We want an even value to automatically clear the top bit + * returned by cnt32_to_63() without an additional run time + * instruction. So if the LSB is 1 then round it up. + */ + if (oscr2ns_scale & 1) + oscr2ns_scale++; +} + +unsigned long long sched_clock(void) +{ + unsigned long long v = cnt32_to_63(OSCR); + return (v * oscr2ns_scale) >> OSCR2NS_SCALE_FACTOR; +} + + static irqreturn_t pxa_ost0_interrupt(int irq, void *dev_id) { @@ -152,6 +189,8 @@ static void __init pxa_timer_init(void) OIER = 0; OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; + set_oscr2ns_scale(CLOCK_TICK_RATE); + ckevt_pxa_osmr0.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift); ckevt_pxa_osmr0.max_delta_ns = |