diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 49 | ||||
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 3 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 52 |
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 | */ | ||
230 | u32 __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 | |||
225 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | 238 | static 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; | |||
360 | static cycle_t clocksource_read_cycles(struct clocksource *cs) | 389 | static 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 | ||
366 | static struct clocksource clocksource_gpt = { | 395 | static 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 | ||
135 | int omap_dm_timer_prepare(struct omap_dm_timer *timer) | 135 | int 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 | |||
69 | struct omap_timer_capability_dev_attr { | 79 | struct omap_timer_capability_dev_attr { |
70 | u32 timer_capability; | 80 | u32 timer_capability; |
71 | }; | 81 | }; |
@@ -97,6 +107,7 @@ struct timer_regs { | |||
97 | struct dmtimer_platform_data { | 107 | struct 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 | */ | ||
371 | static 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 | */ | ||
395 | static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer, | ||
396 | u32 errata) | ||
397 | { | ||
398 | timer->errata &= ~errata; | ||
351 | } | 399 | } |
352 | 400 | ||
353 | static inline int __omap_dm_timer_set_source(struct clk *timer_fck, | 401 | static inline int __omap_dm_timer_set_source(struct clk *timer_fck, |