diff options
Diffstat (limited to 'arch/arm/plat-orion/time.c')
-rw-r--r-- | arch/arm/plat-orion/time.c | 50 |
1 files changed, 11 insertions, 39 deletions
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c index 715a30177f28..c3da2478b2aa 100644 --- a/arch/arm/plat-orion/time.c +++ b/arch/arm/plat-orion/time.c | |||
@@ -13,11 +13,11 @@ | |||
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/cnt32_to_63.h> | ||
17 | #include <linux/timer.h> | 16 | #include <linux/timer.h> |
18 | #include <linux/clockchips.h> | 17 | #include <linux/clockchips.h> |
19 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
20 | #include <linux/irq.h> | 19 | #include <linux/irq.h> |
20 | #include <asm/sched_clock.h> | ||
21 | #include <asm/mach/time.h> | 21 | #include <asm/mach/time.h> |
22 | #include <mach/bridge-regs.h> | 22 | #include <mach/bridge-regs.h> |
23 | #include <mach/hardware.h> | 23 | #include <mach/hardware.h> |
@@ -44,52 +44,26 @@ static u32 ticks_per_jiffy; | |||
44 | 44 | ||
45 | /* | 45 | /* |
46 | * Orion's sched_clock implementation. It has a resolution of | 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. | 47 | * at least 7.5ns (133MHz TCLK). |
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 | */ | 48 | */ |
54 | #define TCLK2NS_SCALE_FACTOR 8 | 49 | static DEFINE_CLOCK_DATA(cd); |
55 | |||
56 | static unsigned long tclk2ns_scale; | ||
57 | 50 | ||
58 | unsigned long long sched_clock(void) | 51 | unsigned long long notrace sched_clock(void) |
59 | { | 52 | { |
60 | unsigned long long v = cnt32_to_63(0xffffffff - readl(TIMER0_VAL)); | 53 | u32 cyc = 0xffffffff - readl(TIMER0_VAL); |
61 | return (v * tclk2ns_scale) >> TCLK2NS_SCALE_FACTOR; | 54 | return cyc_to_sched_clock(&cd, cyc, (u32)~0); |
62 | } | 55 | } |
63 | 56 | ||
64 | static struct timer_list cnt32_to_63_keepwarm_timer; | ||
65 | 57 | ||
66 | static void cnt32_to_63_keepwarm(unsigned long data) | 58 | static void notrace orion_update_sched_clock(void) |
67 | { | 59 | { |
68 | mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); | 60 | u32 cyc = 0xffffffff - readl(TIMER0_VAL); |
69 | (void) sched_clock(); | 61 | update_sched_clock(&cd, cyc, (u32)~0); |
70 | } | 62 | } |
71 | 63 | ||
72 | static void __init setup_sched_clock(unsigned long tclk) | 64 | static void __init setup_sched_clock(unsigned long tclk) |
73 | { | 65 | { |
74 | unsigned long long v; | 66 | init_sched_clock(&cd, orion_update_sched_clock, 32, tclk); |
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 | } | 67 | } |
94 | 68 | ||
95 | /* | 69 | /* |
@@ -102,7 +76,6 @@ static cycle_t orion_clksrc_read(struct clocksource *cs) | |||
102 | 76 | ||
103 | static struct clocksource orion_clksrc = { | 77 | static struct clocksource orion_clksrc = { |
104 | .name = "orion_clocksource", | 78 | .name = "orion_clocksource", |
105 | .shift = 20, | ||
106 | .rating = 300, | 79 | .rating = 300, |
107 | .read = orion_clksrc_read, | 80 | .read = orion_clksrc_read, |
108 | .mask = CLOCKSOURCE_MASK(32), | 81 | .mask = CLOCKSOURCE_MASK(32), |
@@ -245,8 +218,7 @@ void __init orion_time_init(unsigned int irq, unsigned int tclk) | |||
245 | writel(u & ~BRIDGE_INT_TIMER0, BRIDGE_MASK); | 218 | writel(u & ~BRIDGE_INT_TIMER0, BRIDGE_MASK); |
246 | u = readl(TIMER_CTRL); | 219 | u = readl(TIMER_CTRL); |
247 | writel(u | TIMER0_EN | TIMER0_RELOAD_EN, TIMER_CTRL); | 220 | writel(u | TIMER0_EN | TIMER0_RELOAD_EN, TIMER_CTRL); |
248 | orion_clksrc.mult = clocksource_hz2mult(tclk, orion_clksrc.shift); | 221 | clocksource_register_hz(&orion_clksrc, tclk); |
249 | clocksource_register(&orion_clksrc); | ||
250 | 222 | ||
251 | /* | 223 | /* |
252 | * Setup clockevent timer (interrupt-driven.) | 224 | * Setup clockevent timer (interrupt-driven.) |