diff options
Diffstat (limited to 'arch/arm/plat-orion/time.c')
-rw-r--r-- | arch/arm/plat-orion/time.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c index de8a001fc3a9..715a30177f28 100644 --- a/arch/arm/plat-orion/time.c +++ b/arch/arm/plat-orion/time.c | |||
@@ -12,11 +12,15 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/sched.h> | ||
16 | #include <linux/cnt32_to_63.h> | ||
17 | #include <linux/timer.h> | ||
15 | #include <linux/clockchips.h> | 18 | #include <linux/clockchips.h> |
16 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
17 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
18 | #include <asm/mach/time.h> | 21 | #include <asm/mach/time.h> |
19 | #include <mach/bridge-regs.h> | 22 | #include <mach/bridge-regs.h> |
23 | #include <mach/hardware.h> | ||
20 | 24 | ||
21 | /* | 25 | /* |
22 | * Number of timer ticks per jiffy. | 26 | * Number of timer ticks per jiffy. |
@@ -39,6 +43,56 @@ static u32 ticks_per_jiffy; | |||
39 | 43 | ||
40 | 44 | ||
41 | /* | 45 | /* |
46 | * Orion's sched_clock implementation. It has a resolution of | ||
47 | * at least 7.5ns (133MHz TCLK) and a maximum value of 834 days. | ||
48 | * | ||
49 | * Because the hardware timer period is quite short (21 secs if | ||
50 | * 200MHz TCLK) and because cnt32_to_63() needs to be called at | ||
51 | * least once per half period to work properly, a kernel timer is | ||
52 | * set up to ensure this requirement is always met. | ||
53 | */ | ||
54 | #define TCLK2NS_SCALE_FACTOR 8 | ||
55 | |||
56 | static unsigned long tclk2ns_scale; | ||
57 | |||
58 | unsigned long long sched_clock(void) | ||
59 | { | ||
60 | unsigned long long v = cnt32_to_63(0xffffffff - readl(TIMER0_VAL)); | ||
61 | return (v * tclk2ns_scale) >> TCLK2NS_SCALE_FACTOR; | ||
62 | } | ||
63 | |||
64 | static struct timer_list cnt32_to_63_keepwarm_timer; | ||
65 | |||
66 | static void cnt32_to_63_keepwarm(unsigned long data) | ||
67 | { | ||
68 | mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); | ||
69 | (void) sched_clock(); | ||
70 | } | ||
71 | |||
72 | static void __init setup_sched_clock(unsigned long tclk) | ||
73 | { | ||
74 | unsigned long long v; | ||
75 | unsigned long data; | ||
76 | |||
77 | v = NSEC_PER_SEC; | ||
78 | v <<= TCLK2NS_SCALE_FACTOR; | ||
79 | v += tclk/2; | ||
80 | do_div(v, tclk); | ||
81 | /* | ||
82 | * We want an even value to automatically clear the top bit | ||
83 | * returned by cnt32_to_63() without an additional run time | ||
84 | * instruction. So if the LSB is 1 then round it up. | ||
85 | */ | ||
86 | if (v & 1) | ||
87 | v++; | ||
88 | tclk2ns_scale = v; | ||
89 | |||
90 | data = (0xffffffffUL / tclk / 2 - 2) * HZ; | ||
91 | setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, data); | ||
92 | mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); | ||
93 | } | ||
94 | |||
95 | /* | ||
42 | * Clocksource handling. | 96 | * Clocksource handling. |
43 | */ | 97 | */ |
44 | static cycle_t orion_clksrc_read(struct clocksource *cs) | 98 | static cycle_t orion_clksrc_read(struct clocksource *cs) |
@@ -176,6 +230,10 @@ void __init orion_time_init(unsigned int irq, unsigned int tclk) | |||
176 | 230 | ||
177 | ticks_per_jiffy = (tclk + HZ/2) / HZ; | 231 | ticks_per_jiffy = (tclk + HZ/2) / HZ; |
178 | 232 | ||
233 | /* | ||
234 | * Set scale and timer for sched_clock | ||
235 | */ | ||
236 | setup_sched_clock(tclk); | ||
179 | 237 | ||
180 | /* | 238 | /* |
181 | * Setup free-running clocksource timer (interrupts | 239 | * Setup free-running clocksource timer (interrupts |
@@ -190,7 +248,6 @@ void __init orion_time_init(unsigned int irq, unsigned int tclk) | |||
190 | orion_clksrc.mult = clocksource_hz2mult(tclk, orion_clksrc.shift); | 248 | orion_clksrc.mult = clocksource_hz2mult(tclk, orion_clksrc.shift); |
191 | clocksource_register(&orion_clksrc); | 249 | clocksource_register(&orion_clksrc); |
192 | 250 | ||
193 | |||
194 | /* | 251 | /* |
195 | * Setup clockevent timer (interrupt-driven.) | 252 | * Setup clockevent timer (interrupt-driven.) |
196 | */ | 253 | */ |