aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pxa/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-pxa/time.c')
-rw-r--r--arch/arm/mach-pxa/time.c84
1 files changed, 21 insertions, 63 deletions
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index fbfa1920353d..7b7c0179795b 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -59,55 +59,17 @@ unsigned long long sched_clock(void)
59} 59}
60 60
61 61
62#define MIN_OSCR_DELTA 16
63
62static irqreturn_t 64static irqreturn_t
63pxa_ost0_interrupt(int irq, void *dev_id) 65pxa_ost0_interrupt(int irq, void *dev_id)
64{ 66{
65 int next_match;
66 struct clock_event_device *c = dev_id; 67 struct clock_event_device *c = dev_id;
67 68
68 if (c->mode == CLOCK_EVT_MODE_ONESHOT) { 69 /* Disarm the compare/match, signal the event. */
69 /* Disarm the compare/match, signal the event. */ 70 OIER &= ~OIER_E0;
70 OIER &= ~OIER_E0; 71 OSSR = OSSR_M0;
71 OSSR = OSSR_M0; 72 c->event_handler(c);
72 c->event_handler(c);
73 } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) {
74 /* Call the event handler as many times as necessary
75 * to recover missed events, if any (if we update
76 * OSMR0 and OSCR0 is still ahead of us, we've missed
77 * the event). As we're dealing with that, re-arm the
78 * compare/match for the next event.
79 *
80 * HACK ALERT:
81 *
82 * There's a latency between the instruction that
83 * writes to OSMR0 and the actual commit to the
84 * physical hardware, because the CPU doesn't (have
85 * to) run at bus speed, there's a write buffer
86 * between the CPU and the bus, etc. etc. So if the
87 * target OSCR0 is "very close", to the OSMR0 load
88 * value, the update to OSMR0 might not get to the
89 * hardware in time and we'll miss that interrupt.
90 *
91 * To be safe, if the new OSMR0 is "very close" to the
92 * target OSCR0 value, we call the event_handler as
93 * though the event actually happened. According to
94 * Nico's comment in the previous version of this
95 * code, experience has shown that 6 OSCR ticks is
96 * "very close" but he went with 8. We will use 16,
97 * based on the results of testing on PXA270.
98 *
99 * To be doubly sure, we also tell clkevt via
100 * clockevents_register_device() not to ask for
101 * anything that might put us "very close".
102 */
103#define MIN_OSCR_DELTA 16
104 do {
105 OSSR = OSSR_M0;
106 next_match = (OSMR0 += LATCH);
107 c->event_handler(c);
108 } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA)
109 && (c->mode == CLOCK_EVT_MODE_PERIODIC));
110 }
111 73
112 return IRQ_HANDLED; 74 return IRQ_HANDLED;
113} 75}
@@ -133,14 +95,6 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
133 unsigned long irqflags; 95 unsigned long irqflags;
134 96
135 switch (mode) { 97 switch (mode) {
136 case CLOCK_EVT_MODE_PERIODIC:
137 raw_local_irq_save(irqflags);
138 OSSR = OSSR_M0;
139 OIER |= OIER_E0;
140 OSMR0 = OSCR + LATCH;
141 raw_local_irq_restore(irqflags);
142 break;
143
144 case CLOCK_EVT_MODE_ONESHOT: 98 case CLOCK_EVT_MODE_ONESHOT:
145 raw_local_irq_save(irqflags); 99 raw_local_irq_save(irqflags);
146 OIER &= ~OIER_E0; 100 OIER &= ~OIER_E0;
@@ -158,13 +112,14 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
158 break; 112 break;
159 113
160 case CLOCK_EVT_MODE_RESUME: 114 case CLOCK_EVT_MODE_RESUME:
115 case CLOCK_EVT_MODE_PERIODIC:
161 break; 116 break;
162 } 117 }
163} 118}
164 119
165static struct clock_event_device ckevt_pxa_osmr0 = { 120static struct clock_event_device ckevt_pxa_osmr0 = {
166 .name = "osmr0", 121 .name = "osmr0",
167 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 122 .features = CLOCK_EVT_FEAT_ONESHOT,
168 .shift = 32, 123 .shift = 32,
169 .rating = 200, 124 .rating = 200,
170 .cpumask = CPU_MASK_CPU0, 125 .cpumask = CPU_MASK_CPU0,
@@ -214,7 +169,7 @@ static void __init pxa_timer_init(void)
214 ckevt_pxa_osmr0.max_delta_ns = 169 ckevt_pxa_osmr0.max_delta_ns =
215 clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0); 170 clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
216 ckevt_pxa_osmr0.min_delta_ns = 171 ckevt_pxa_osmr0.min_delta_ns =
217 clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1; 172 clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_pxa_osmr0) + 1;
218 173
219 cksrc_pxa_oscr0.mult = 174 cksrc_pxa_oscr0.mult =
220 clocksource_hz2mult(clock_tick_rate, cksrc_pxa_oscr0.shift); 175 clocksource_hz2mult(clock_tick_rate, cksrc_pxa_oscr0.shift);
@@ -226,7 +181,7 @@ static void __init pxa_timer_init(void)
226} 181}
227 182
228#ifdef CONFIG_PM 183#ifdef CONFIG_PM
229static unsigned long osmr[4], oier; 184static unsigned long osmr[4], oier, oscr;
230 185
231static void pxa_timer_suspend(void) 186static void pxa_timer_suspend(void)
232{ 187{
@@ -235,23 +190,26 @@ static void pxa_timer_suspend(void)
235 osmr[2] = OSMR2; 190 osmr[2] = OSMR2;
236 osmr[3] = OSMR3; 191 osmr[3] = OSMR3;
237 oier = OIER; 192 oier = OIER;
193 oscr = OSCR;
238} 194}
239 195
240static void pxa_timer_resume(void) 196static void pxa_timer_resume(void)
241{ 197{
198 /*
199 * Ensure that we have at least MIN_OSCR_DELTA between match
200 * register 0 and the OSCR, to guarantee that we will receive
201 * the one-shot timer interrupt. We adjust OSMR0 in preference
202 * to OSCR to guarantee that OSCR is monotonically incrementing.
203 */
204 if (osmr[0] - oscr < MIN_OSCR_DELTA)
205 osmr[0] += MIN_OSCR_DELTA;
206
242 OSMR0 = osmr[0]; 207 OSMR0 = osmr[0];
243 OSMR1 = osmr[1]; 208 OSMR1 = osmr[1];
244 OSMR2 = osmr[2]; 209 OSMR2 = osmr[2];
245 OSMR3 = osmr[3]; 210 OSMR3 = osmr[3];
246 OIER = oier; 211 OIER = oier;
247 212 OSCR = oscr;
248 /*
249 * OSCR0 is the system timer, which has to increase
250 * monotonically until it rolls over in hardware. The value
251 * (OSMR0 - LATCH) is OSCR0 at the most recent system tick,
252 * which is a handy value to restore to OSCR0.
253 */
254 OSCR = OSMR0 - LATCH;
255} 213}
256#else 214#else
257#define pxa_timer_suspend NULL 215#define pxa_timer_suspend NULL