aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/timer.c
diff options
context:
space:
mode:
authorVaibhav Hiremath <hvaibhav@ti.com>2012-05-09 13:07:05 -0400
committerTony Lindgren <tony@atomide.com>2012-05-09 13:07:05 -0400
commit1fe97c8f6a1de67a5f56e029a818903d5bed8017 (patch)
tree850b55afd3750a58b553e04eb1c6e1f7a966c612 /arch/arm/mach-omap2/timer.c
parentf36921bebdf368ac4892f8ed62fb97dd6461d459 (diff)
ARM: OMAP: Make OMAP clocksource source selection using kernel param
Current OMAP code supports couple of clocksource options based on compilation flag (CONFIG_OMAP_32K_TIMER). The 32KHz sync-timer and a gptimer which can run on 32KHz or system clock (e.g 38.4 MHz). So there can be 3 options - 1. 32KHz sync-timer 2. Sys_clock based (e.g 13/19.2/26/38.4 MHz) gptimer 3. 32KHz based gptimer. The optional gptimer based clocksource was added so that it can give the high precision than sync-timer, so expected usage was 2 and not 3. Unfortunately option 2, clocksource doesn't meet the requirement of free-running clock as per clocksource need. It stops in low power states when sys_clock is cut. That makes gptimer based clocksource option useless for OMAP2/3/4 devices with sys_clock as a clock input. So, in order to use option 2, deeper idle state MUST be disabled. Option 3 will still work but it is no better than 32K sync-timer based clocksource. We must support both sync timer and gptimer based clocksource as some OMAP based derivative SoCs like AM33XX does not have the sync timer. Considering above, make sync-timer and gptimer clocksource runtime selectable so that both OMAP and AMXXXX continue to use the same code. And, in order to precisely configure/setup sched_clock for given clocksource, decision has to be made early enough in boot sequence. So, the solution is, Use standard kernel parameter ("clocksource=") to override default 32k_sync-timer, in addition to this, we also use hwmod database lookup mechanism, through which at run-time we can identify availability of 32k-sync timer on the device, else fall back to gptimer. Also, moved low-level SoC specific init code to respective files, (mach-omap1/timer32k.c and mach-omap2/timer.c) Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Acked-by: Kevin Hilman <khilman@ti.com> Tested-by: Kevin Hilman <khilman@ti.com> Cc: Benoit Cousson <b-cousson@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Tarun Kanti DebBarma <tarun.kanti@ti.com> Cc: Ming Lei <tom.leiming@gmail.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r--arch/arm/mach-omap2/timer.c112
1 files changed, 90 insertions, 22 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 105829e403b3..840929bd9dae 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -236,22 +236,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
236} 236}
237 237
238/* Clocksource code */ 238/* Clocksource code */
239
240#ifdef CONFIG_OMAP_32K_TIMER
241/*
242 * When 32k-timer is enabled, don't use GPTimer for clocksource
243 * instead, just leave default clocksource which uses the 32k
244 * sync counter. See clocksource setup in plat-omap/counter_32k.c
245 */
246
247static void __init omap2_gp_clocksource_init(int unused, const char *dummy)
248{
249 omap_init_clocksource_32k();
250}
251
252#else
253
254static struct omap_dm_timer clksrc; 239static struct omap_dm_timer clksrc;
240static bool use_gptimer_clksrc;
255 241
256/* 242/*
257 * clocksource 243 * clocksource
@@ -278,7 +264,46 @@ static u32 notrace dmtimer_read_sched_clock(void)
278} 264}
279 265
280/* Setup free-running counter for clocksource */ 266/* Setup free-running counter for clocksource */
281static void __init omap2_gp_clocksource_init(int gptimer_id, 267static int __init omap2_sync32k_clocksource_init(void)
268{
269 int ret;
270 struct omap_hwmod *oh;
271 void __iomem *vbase;
272 const char *oh_name = "counter_32k";
273
274 /*
275 * First check hwmod data is available for sync32k counter
276 */
277 oh = omap_hwmod_lookup(oh_name);
278 if (!oh || oh->slaves_cnt == 0)
279 return -ENODEV;
280
281 omap_hwmod_setup_one(oh_name);
282
283 vbase = omap_hwmod_get_mpu_rt_va(oh);
284 if (!vbase) {
285 pr_warn("%s: failed to get counter_32k resource\n", __func__);
286 return -ENXIO;
287 }
288
289 ret = omap_hwmod_enable(oh);
290 if (ret) {
291 pr_warn("%s: failed to enable counter_32k module (%d)\n",
292 __func__, ret);
293 return ret;
294 }
295
296 ret = omap_init_clocksource_32k(vbase);
297 if (ret) {
298 pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n",
299 __func__, ret);
300 omap_hwmod_idle(oh);
301 }
302
303 return ret;
304}
305
306static void __init omap2_gptimer_clocksource_init(int gptimer_id,
282 const char *fck_source) 307 const char *fck_source)
283{ 308{
284 int res; 309 int res;
@@ -286,9 +311,6 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
286 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); 311 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source);
287 BUG_ON(res); 312 BUG_ON(res);
288 313
289 pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
290 gptimer_id, clksrc.rate);
291
292 __omap_dm_timer_load_start(&clksrc, 314 __omap_dm_timer_load_start(&clksrc,
293 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); 315 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
294 setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); 316 setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
@@ -296,15 +318,36 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
296 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) 318 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
297 pr_err("Could not register clocksource %s\n", 319 pr_err("Could not register clocksource %s\n",
298 clocksource_gpt.name); 320 clocksource_gpt.name);
321 else
322 pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
323 gptimer_id, clksrc.rate);
324}
325
326static void __init omap2_clocksource_init(int gptimer_id,
327 const char *fck_source)
328{
329 /*
330 * First give preference to kernel parameter configuration
331 * by user (clocksource="gp_timer").
332 *
333 * In case of missing kernel parameter for clocksource,
334 * first check for availability for 32k-sync timer, in case
335 * of failure in finding 32k_counter module or registering
336 * it as clocksource, execution will fallback to gp-timer.
337 */
338 if (use_gptimer_clksrc == true)
339 omap2_gptimer_clocksource_init(gptimer_id, fck_source);
340 else if (omap2_sync32k_clocksource_init())
341 /* Fall back to gp-timer code */
342 omap2_gptimer_clocksource_init(gptimer_id, fck_source);
299} 343}
300#endif
301 344
302#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ 345#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \
303 clksrc_nr, clksrc_src) \ 346 clksrc_nr, clksrc_src) \
304static void __init omap##name##_timer_init(void) \ 347static void __init omap##name##_timer_init(void) \
305{ \ 348{ \
306 omap2_gp_clockevent_init((clkev_nr), clkev_src); \ 349 omap2_gp_clockevent_init((clkev_nr), clkev_src); \
307 omap2_gp_clocksource_init((clksrc_nr), clksrc_src); \ 350 omap2_clocksource_init((clksrc_nr), clksrc_src); \
308} 351}
309 352
310#define OMAP_SYS_TIMER(name) \ 353#define OMAP_SYS_TIMER(name) \
@@ -335,7 +378,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
335static void __init omap4_timer_init(void) 378static void __init omap4_timer_init(void)
336{ 379{
337 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); 380 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
338 omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE); 381 omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
339#ifdef CONFIG_LOCAL_TIMERS 382#ifdef CONFIG_LOCAL_TIMERS
340 /* Local timers are not supprted on OMAP4430 ES1.0 */ 383 /* Local timers are not supprted on OMAP4430 ES1.0 */
341 if (omap_rev() != OMAP4430_REV_ES1_0) { 384 if (omap_rev() != OMAP4430_REV_ES1_0) {
@@ -503,3 +546,28 @@ static int __init omap2_dm_timer_init(void)
503 return 0; 546 return 0;
504} 547}
505arch_initcall(omap2_dm_timer_init); 548arch_initcall(omap2_dm_timer_init);
549
550/**
551 * omap2_override_clocksource - clocksource override with user configuration
552 *
553 * Allows user to override default clocksource, using kernel parameter
554 * clocksource="gp_timer" (For all OMAP2PLUS architectures)
555 *
556 * Note that, here we are using same standard kernel parameter "clocksource=",
557 * and not introducing any OMAP specific interface.
558 */
559static int __init omap2_override_clocksource(char *str)
560{
561 if (!str)
562 return 0;
563 /*
564 * For OMAP architecture, we only have two options
565 * - sync_32k (default)
566 * - gp_timer (sys_clk based)
567 */
568 if (!strcmp(str, "gp_timer"))
569 use_gptimer_clksrc = true;
570
571 return 0;
572}
573early_param("clocksource", omap2_override_clocksource);