diff options
Diffstat (limited to 'arch/arm/mach-pxa/time.c')
-rw-r--r-- | arch/arm/mach-pxa/time.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 98d27e646b09..ec4286c7931c 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c | |||
@@ -16,10 +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> |
26 | #include <asm/mach-types.h> | ||
27 | |||
28 | /* | ||
29 | * This is PXA's sched_clock implementation. This has a resolution | ||
30 | * of at least 308 ns and a maximum value of 208 days. | ||
31 | * | ||
32 | * The return value is guaranteed to be monotonic in that range as | ||
33 | * long as there is always less than 582 seconds between successive | ||
34 | * calls to sched_clock() which should always be the case in practice. | ||
35 | */ | ||
36 | |||
37 | #define OSCR2NS_SCALE_FACTOR 10 | ||
38 | |||
39 | static unsigned long oscr2ns_scale; | ||
40 | |||
41 | static void __init set_oscr2ns_scale(unsigned long oscr_rate) | ||
42 | { | ||
43 | unsigned long long v = 1000000000ULL << OSCR2NS_SCALE_FACTOR; | ||
44 | do_div(v, oscr_rate); | ||
45 | oscr2ns_scale = v; | ||
46 | /* | ||
47 | * We want an even value to automatically clear the top bit | ||
48 | * returned by cnt32_to_63() without an additional run time | ||
49 | * instruction. So if the LSB is 1 then round it up. | ||
50 | */ | ||
51 | if (oscr2ns_scale & 1) | ||
52 | oscr2ns_scale++; | ||
53 | } | ||
54 | |||
55 | unsigned long long sched_clock(void) | ||
56 | { | ||
57 | unsigned long long v = cnt32_to_63(OSCR); | ||
58 | return (v * oscr2ns_scale) >> OSCR2NS_SCALE_FACTOR; | ||
59 | } | ||
60 | |||
23 | 61 | ||
24 | static irqreturn_t | 62 | static irqreturn_t |
25 | pxa_ost0_interrupt(int irq, void *dev_id) | 63 | pxa_ost0_interrupt(int irq, void *dev_id) |
@@ -149,18 +187,29 @@ static struct irqaction pxa_ost0_irq = { | |||
149 | 187 | ||
150 | static void __init pxa_timer_init(void) | 188 | static void __init pxa_timer_init(void) |
151 | { | 189 | { |
190 | unsigned long clock_tick_rate; | ||
191 | |||
152 | OIER = 0; | 192 | OIER = 0; |
153 | OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; | 193 | OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; |
154 | 194 | ||
195 | if (cpu_is_pxa21x() || cpu_is_pxa25x()) | ||
196 | clock_tick_rate = 3686400; | ||
197 | else if (machine_is_mainstone()) | ||
198 | clock_tick_rate = 3249600; | ||
199 | else | ||
200 | clock_tick_rate = 3250000; | ||
201 | |||
202 | set_oscr2ns_scale(clock_tick_rate); | ||
203 | |||
155 | ckevt_pxa_osmr0.mult = | 204 | ckevt_pxa_osmr0.mult = |
156 | div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift); | 205 | div_sc(clock_tick_rate, NSEC_PER_SEC, ckevt_pxa_osmr0.shift); |
157 | ckevt_pxa_osmr0.max_delta_ns = | 206 | ckevt_pxa_osmr0.max_delta_ns = |
158 | clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0); | 207 | clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0); |
159 | ckevt_pxa_osmr0.min_delta_ns = | 208 | ckevt_pxa_osmr0.min_delta_ns = |
160 | clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1; | 209 | clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1; |
161 | 210 | ||
162 | cksrc_pxa_oscr0.mult = | 211 | cksrc_pxa_oscr0.mult = |
163 | clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_pxa_oscr0.shift); | 212 | clocksource_hz2mult(clock_tick_rate, cksrc_pxa_oscr0.shift); |
164 | 213 | ||
165 | setup_irq(IRQ_OST0, &pxa_ost0_irq); | 214 | setup_irq(IRQ_OST0, &pxa_ost0_irq); |
166 | 215 | ||