aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/timer.c49
-rw-r--r--arch/arm/plat-omap/dmtimer.c3
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h52
3 files changed, 93 insertions, 11 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index a135d28e202c..63229c5287e6 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -222,10 +222,24 @@ void __init omap_dmtimer_init(void)
222 } 222 }
223} 223}
224 224
225/**
226 * omap_dm_timer_get_errata - get errata flags for a timer
227 *
228 * Get the timer errata flags that are specific to the OMAP device being used.
229 */
230u32 __init omap_dm_timer_get_errata(void)
231{
232 if (cpu_is_omap24xx())
233 return 0;
234
235 return OMAP_TIMER_ERRATA_I103_I767;
236}
237
225static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, 238static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
226 int gptimer_id, 239 int gptimer_id,
227 const char *fck_source, 240 const char *fck_source,
228 const char *property) 241 const char *property,
242 int posted)
229{ 243{
230 char name[10]; /* 10 = sizeof("gptXX_Xck0") */ 244 char name[10]; /* 10 = sizeof("gptXX_Xck0") */
231 const char *oh_name; 245 const char *oh_name;
@@ -311,10 +325,15 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
311 } 325 }
312 __omap_dm_timer_init_regs(timer); 326 __omap_dm_timer_init_regs(timer);
313 __omap_dm_timer_reset(timer, 1, 1); 327 __omap_dm_timer_reset(timer, 1, 1);
314 timer->posted = 1;
315 328
316 timer->rate = clk_get_rate(timer->fclk); 329 if (posted)
330 __omap_dm_timer_enable_posted(timer);
331
332 /* Check that the intended posted configuration matches the actual */
333 if (posted != timer->posted)
334 return -EINVAL;
317 335
336 timer->rate = clk_get_rate(timer->fclk);
318 timer->reserved = 1; 337 timer->reserved = 1;
319 338
320 return res; 339 return res;
@@ -326,7 +345,17 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
326{ 345{
327 int res; 346 int res;
328 347
329 res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property); 348 clkev.errata = omap_dm_timer_get_errata();
349
350 /*
351 * For clock-event timers we never read the timer counter and
352 * so we are not impacted by errata i103 and i767. Therefore,
353 * we can safely ignore this errata for clock-event timers.
354 */
355 __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);
356
357 res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property,
358 OMAP_TIMER_POSTED);
330 BUG_ON(res); 359 BUG_ON(res);
331 360
332 omap2_gp_timer_irq.dev_id = &clkev; 361 omap2_gp_timer_irq.dev_id = &clkev;
@@ -360,7 +389,7 @@ static bool use_gptimer_clksrc;
360static cycle_t clocksource_read_cycles(struct clocksource *cs) 389static cycle_t clocksource_read_cycles(struct clocksource *cs)
361{ 390{
362 return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 391 return (cycle_t)__omap_dm_timer_read_counter(&clksrc,
363 OMAP_TIMER_POSTED); 392 OMAP_TIMER_NONPOSTED);
364} 393}
365 394
366static struct clocksource clocksource_gpt = { 395static struct clocksource clocksource_gpt = {
@@ -375,7 +404,7 @@ static u32 notrace dmtimer_read_sched_clock(void)
375{ 404{
376 if (clksrc.reserved) 405 if (clksrc.reserved)
377 return __omap_dm_timer_read_counter(&clksrc, 406 return __omap_dm_timer_read_counter(&clksrc,
378 OMAP_TIMER_POSTED); 407 OMAP_TIMER_NONPOSTED);
379 408
380 return 0; 409 return 0;
381} 410}
@@ -453,12 +482,15 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
453{ 482{
454 int res; 483 int res;
455 484
456 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL); 485 clksrc.errata = omap_dm_timer_get_errata();
486
487 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL,
488 OMAP_TIMER_NONPOSTED);
457 BUG_ON(res); 489 BUG_ON(res);
458 490
459 __omap_dm_timer_load_start(&clksrc, 491 __omap_dm_timer_load_start(&clksrc,
460 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 492 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0,
461 OMAP_TIMER_POSTED); 493 OMAP_TIMER_NONPOSTED);
462 setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); 494 setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
463 495
464 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) 496 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
@@ -696,6 +728,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
696 if (timer_dev_attr) 728 if (timer_dev_attr)
697 pdata->timer_capability = timer_dev_attr->timer_capability; 729 pdata->timer_capability = timer_dev_attr->timer_capability;
698 730
731 pdata->timer_errata = omap_dm_timer_get_errata();
699 pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; 732 pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
700 733
701 pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), 734 pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 9dca23e4d6b0..381a612e6a1d 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -128,8 +128,8 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
128 } 128 }
129 129
130 __omap_dm_timer_reset(timer, 0, 0); 130 __omap_dm_timer_reset(timer, 0, 0);
131 __omap_dm_timer_enable_posted(timer);
131 omap_dm_timer_disable(timer); 132 omap_dm_timer_disable(timer);
132 timer->posted = 1;
133} 133}
134 134
135int omap_dm_timer_prepare(struct omap_dm_timer *timer) 135int omap_dm_timer_prepare(struct omap_dm_timer *timer)
@@ -797,6 +797,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
797 timer->capability |= OMAP_TIMER_SECURE; 797 timer->capability |= OMAP_TIMER_SECURE;
798 } else { 798 } else {
799 timer->id = pdev->id; 799 timer->id = pdev->id;
800 timer->errata = pdata->timer_errata;
800 timer->capability = pdata->timer_capability; 801 timer->capability = pdata->timer_capability;
801 timer->reserved = omap_dm_timer_reserved_systimer(timer->id); 802 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
802 timer->get_context_loss_count = pdata->get_context_loss_count; 803 timer->get_context_loss_count = pdata->get_context_loss_count;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 1bee0ac88760..ac16f1e9d0e0 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -66,6 +66,16 @@
66#define OMAP_TIMER_NEEDS_RESET 0x10000000 66#define OMAP_TIMER_NEEDS_RESET 0x10000000
67#define OMAP_TIMER_HAS_DSP_IRQ 0x08000000 67#define OMAP_TIMER_HAS_DSP_IRQ 0x08000000
68 68
69/*
70 * timer errata flags
71 *
72 * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This
73 * errata prevents us from using posted mode on these devices, unless the
74 * timer counter register is never read. For more details please refer to
75 * the OMAP3/4/5 errata documents.
76 */
77#define OMAP_TIMER_ERRATA_I103_I767 0x80000000
78
69struct omap_timer_capability_dev_attr { 79struct omap_timer_capability_dev_attr {
70 u32 timer_capability; 80 u32 timer_capability;
71}; 81};
@@ -97,6 +107,7 @@ struct timer_regs {
97struct dmtimer_platform_data { 107struct dmtimer_platform_data {
98 /* set_timer_src - Only used for OMAP1 devices */ 108 /* set_timer_src - Only used for OMAP1 devices */
99 int (*set_timer_src)(struct platform_device *pdev, int source); 109 int (*set_timer_src)(struct platform_device *pdev, int source);
110 u32 timer_errata;
100 u32 timer_capability; 111 u32 timer_capability;
101 int (*get_context_loss_count)(struct device *); 112 int (*get_context_loss_count)(struct device *);
102}; 113};
@@ -273,6 +284,7 @@ struct omap_dm_timer {
273 int ctx_loss_count; 284 int ctx_loss_count;
274 int revision; 285 int revision;
275 u32 capability; 286 u32 capability;
287 u32 errata;
276 struct platform_device *pdev; 288 struct platform_device *pdev;
277 struct list_head node; 289 struct list_head node;
278}; 290};
@@ -344,10 +356,46 @@ static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
344 l |= 1 << 2; 356 l |= 1 << 2;
345 357
346 __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); 358 __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
359}
360
361/*
362 * __omap_dm_timer_enable_posted - enables write posted mode
363 * @timer: pointer to timer instance handle
364 *
365 * Enables the write posted mode for the timer. When posted mode is enabled
366 * writes to certain timer registers are immediately acknowledged by the
367 * internal bus and hence prevents stalling the CPU waiting for the write to
368 * complete. Enabling this feature can improve performance for writing to the
369 * timer registers.
370 */
371static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
372{
373 if (timer->posted)
374 return;
375
376 if (timer->errata & OMAP_TIMER_ERRATA_I103_I767)
377 return;
347 378
348 /* Match hardware reset default of posted mode */
349 __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 379 __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
350 OMAP_TIMER_CTRL_POSTED, 0); 380 OMAP_TIMER_CTRL_POSTED, 0);
381 timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
382 timer->posted = OMAP_TIMER_POSTED;
383}
384
385/**
386 * __omap_dm_timer_override_errata - override errata flags for a timer
387 * @timer: pointer to timer handle
388 * @errata: errata flags to be ignored
389 *
390 * For a given timer, override a timer errata by clearing the flags
391 * specified by the errata argument. A specific erratum should only be
392 * overridden for a timer if the timer is used in such a way the erratum
393 * has no impact.
394 */
395static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer,
396 u32 errata)
397{
398 timer->errata &= ~errata;
351} 399}
352 400
353static inline int __omap_dm_timer_set_source(struct clk *timer_fck, 401static inline int __omap_dm_timer_set_source(struct clk *timer_fck,