aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2007-08-17 11:55:22 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-10-12 16:14:35 -0400
commit6c3a158316598bfb165b8c83b168fa413d5ae2d8 (patch)
tree25850d9461a4a3ed5bf1833a54bcde00be8af280 /arch/arm
parente86908614f2c7fec401827e5cefd7a6ea9407f85 (diff)
[ARM] 4550/1: sched_clock on PXA should cope with run time clock rate selection
The previous implementation was relying on compile time optimizations based on a constant clock rate. However, support for different PXA flavors in the same kernel binary requires that the clock be selected at run time, so here it is. Let's move this code to a more appropriate location while at it. Signed-off-by: Nicolas Pitre <npitre@mvista.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-pxa/generic.c62
-rw-r--r--arch/arm/mach-pxa/time.c39
2 files changed, 39 insertions, 62 deletions
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 5510f6fdce55..9d6a2c00d762 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -25,10 +25,6 @@
25#include <linux/pm.h> 25#include <linux/pm.h>
26#include <linux/string.h> 26#include <linux/string.h>
27 27
28#include <linux/sched.h>
29#include <asm/cnt32_to_63.h>
30#include <asm/div64.h>
31
32#include <asm/hardware.h> 28#include <asm/hardware.h>
33#include <asm/irq.h> 29#include <asm/irq.h>
34#include <asm/system.h> 30#include <asm/system.h>
@@ -47,64 +43,6 @@
47#include "generic.h" 43#include "generic.h"
48 44
49/* 45/*
50 * This is the PXA2xx sched_clock implementation. This has a resolution
51 * of at least 308ns and a maximum value that depends on the value of
52 * CLOCK_TICK_RATE.
53 *
54 * The return value is guaranteed to be monotonic in that range as
55 * long as there is always less than 582 seconds between successive
56 * calls to this function.
57 */
58unsigned long long sched_clock(void)
59{
60 unsigned long long v = cnt32_to_63(OSCR);
61 /* Note: top bit ov v needs cleared unless multiplier is even. */
62
63#if CLOCK_TICK_RATE == 3686400
64 /* 1E9 / 3686400 => 78125 / 288, max value = 32025597s (370 days). */
65 /* The <<1 is used to get rid of tick.hi top bit */
66 v *= 78125<<1;
67 do_div(v, 288<<1);
68#elif CLOCK_TICK_RATE == 3250000
69 /* 1E9 / 3250000 => 4000 / 13, max value = 709490156s (8211 days) */
70 v *= 4000;
71 do_div(v, 13);
72#elif CLOCK_TICK_RATE == 3249600
73 /* 1E9 / 3249600 => 625000 / 2031, max value = 4541295s (52 days) */
74 v *= 625000;
75 do_div(v, 2031);
76#else
77#warning "consider fixing sched_clock for your value of CLOCK_TICK_RATE"
78 /*
79 * 96-bit math to perform tick * NSEC_PER_SEC / CLOCK_TICK_RATE for
80 * any value of CLOCK_TICK_RATE. Max value is in the 80 thousand
81 * years range and truncation to unsigned long long limits it to
82 * sched_clock's max range of ~584 years. This is nice but with
83 * higher computation cost.
84 */
85 {
86 union {
87 unsigned long long val;
88 struct { unsigned long lo, hi; };
89 } x;
90 unsigned long long y;
91
92 x.val = v;
93 x.hi &= 0x7fffffff;
94 y = (unsigned long long)x.lo * NSEC_PER_SEC;
95 x.lo = y;
96 y = (y >> 32) + (unsigned long long)x.hi * NSEC_PER_SEC;
97 x.hi = do_div(y, CLOCK_TICK_RATE);
98 do_div(x.val, CLOCK_TICK_RATE);
99 x.hi += y;
100 v = x.val;
101 }
102#endif
103
104 return v;
105}
106
107/*
108 * Handy function to set GPIO alternate functions 46 * Handy function to set GPIO alternate functions
109 */ 47 */
110 48
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 98d27e646b09..7916311547ca 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -16,11 +16,48 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/clockchips.h> 18#include <linux/clockchips.h>
19#include <linux/sched.h>
19 20
21#include <asm/div64.h>
22#include <asm/cnt32_to_63.h>
20#include <asm/mach/irq.h> 23#include <asm/mach/irq.h>
21#include <asm/mach/time.h> 24#include <asm/mach/time.h>
22#include <asm/arch/pxa-regs.h> 25#include <asm/arch/pxa-regs.h>
23 26
27/*
28 * This is PXA's sched_clock implementation. This has a resolution
29 * of at least 308 ns and a maximum value of 208 days.
30 *
31 * The return value is guaranteed to be monotonic in that range as
32 * long as there is always less than 582 seconds between successive
33 * calls to sched_clock() which should always be the case in practice.
34 */
35
36#define OSCR2NS_SCALE_FACTOR 10
37
38static unsigned long oscr2ns_scale;
39
40static void __init set_oscr2ns_scale(unsigned long oscr_rate)
41{
42 unsigned long long v = 1000000000ULL << OSCR2NS_SCALE_FACTOR;
43 do_div(v, oscr_rate);
44 oscr2ns_scale = v;
45 /*
46 * We want an even value to automatically clear the top bit
47 * returned by cnt32_to_63() without an additional run time
48 * instruction. So if the LSB is 1 then round it up.
49 */
50 if (oscr2ns_scale & 1)
51 oscr2ns_scale++;
52}
53
54unsigned long long sched_clock(void)
55{
56 unsigned long long v = cnt32_to_63(OSCR);
57 return (v * oscr2ns_scale) >> OSCR2NS_SCALE_FACTOR;
58}
59
60
24static irqreturn_t 61static irqreturn_t
25pxa_ost0_interrupt(int irq, void *dev_id) 62pxa_ost0_interrupt(int irq, void *dev_id)
26{ 63{
@@ -152,6 +189,8 @@ static void __init pxa_timer_init(void)
152 OIER = 0; 189 OIER = 0;
153 OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; 190 OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
154 191
192 set_oscr2ns_scale(CLOCK_TICK_RATE);
193
155 ckevt_pxa_osmr0.mult = 194 ckevt_pxa_osmr0.mult =
156 div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift); 195 div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift);
157 ckevt_pxa_osmr0.max_delta_ns = 196 ckevt_pxa_osmr0.max_delta_ns =