diff options
-rw-r--r-- | arch/arm/mach-omap2/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 90 |
2 files changed, 93 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 346fd26f3aa6..4b773fd56978 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig | |||
@@ -24,6 +24,9 @@ config ARCH_OMAP2PLUS_TYPICAL | |||
24 | config SOC_HAS_OMAP2_SDRC | 24 | config SOC_HAS_OMAP2_SDRC |
25 | bool "OMAP2 SDRAM Controller support" | 25 | bool "OMAP2 SDRAM Controller support" |
26 | 26 | ||
27 | config SOC_HAS_REALTIME_COUNTER | ||
28 | bool "Real time free running counter" | ||
29 | |||
27 | config ARCH_OMAP2 | 30 | config ARCH_OMAP2 |
28 | bool "TI OMAP2" | 31 | bool "TI OMAP2" |
29 | depends on ARCH_OMAP2PLUS | 32 | depends on ARCH_OMAP2PLUS |
@@ -70,6 +73,7 @@ config SOC_OMAP5 | |||
70 | select ARM_GIC | 73 | select ARM_GIC |
71 | select HAVE_SMP | 74 | select HAVE_SMP |
72 | select ARM_CPU_SUSPEND if PM | 75 | select ARM_CPU_SUSPEND if PM |
76 | select SOC_HAS_REALTIME_COUNTER | ||
73 | 77 | ||
74 | comment "OMAP Core Type" | 78 | comment "OMAP Core Type" |
75 | depends on ARCH_OMAP2 | 79 | depends on ARCH_OMAP2 |
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 2ba4f57dda86..026fcfff6698 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -69,6 +69,11 @@ | |||
69 | #define OMAP3_SECURE_TIMER 1 | 69 | #define OMAP3_SECURE_TIMER 1 |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #define REALTIME_COUNTER_BASE 0x48243200 | ||
73 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 | ||
74 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 | ||
75 | #define NUMERATOR_DENUMERATOR_MASK 0xfffff000 | ||
76 | |||
72 | /* Clockevent code */ | 77 | /* Clockevent code */ |
73 | 78 | ||
74 | static struct omap_dm_timer clkev; | 79 | static struct omap_dm_timer clkev; |
@@ -346,6 +351,84 @@ static void __init omap2_clocksource_init(int gptimer_id, | |||
346 | omap2_gptimer_clocksource_init(gptimer_id, fck_source); | 351 | omap2_gptimer_clocksource_init(gptimer_id, fck_source); |
347 | } | 352 | } |
348 | 353 | ||
354 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER | ||
355 | /* | ||
356 | * The realtime counter also called master counter, is a free-running | ||
357 | * counter, which is related to real time. It produces the count used | ||
358 | * by the CPU local timer peripherals in the MPU cluster. The timer counts | ||
359 | * at a rate of 6.144 MHz. Because the device operates on different clocks | ||
360 | * in different power modes, the master counter shifts operation between | ||
361 | * clocks, adjusting the increment per clock in hardware accordingly to | ||
362 | * maintain a constant count rate. | ||
363 | */ | ||
364 | static void __init realtime_counter_init(void) | ||
365 | { | ||
366 | void __iomem *base; | ||
367 | static struct clk *sys_clk; | ||
368 | unsigned long rate; | ||
369 | unsigned int reg, num, den; | ||
370 | |||
371 | base = ioremap(REALTIME_COUNTER_BASE, SZ_32); | ||
372 | if (!base) { | ||
373 | pr_err("%s: ioremap failed\n", __func__); | ||
374 | return; | ||
375 | } | ||
376 | sys_clk = clk_get(NULL, "sys_clkin_ck"); | ||
377 | if (!sys_clk) { | ||
378 | pr_err("%s: failed to get system clock handle\n", __func__); | ||
379 | iounmap(base); | ||
380 | return; | ||
381 | } | ||
382 | |||
383 | rate = clk_get_rate(sys_clk); | ||
384 | /* Numerator/denumerator values refer TRM Realtime Counter section */ | ||
385 | switch (rate) { | ||
386 | case 1200000: | ||
387 | num = 64; | ||
388 | den = 125; | ||
389 | break; | ||
390 | case 1300000: | ||
391 | num = 768; | ||
392 | den = 1625; | ||
393 | break; | ||
394 | case 19200000: | ||
395 | num = 8; | ||
396 | den = 25; | ||
397 | break; | ||
398 | case 2600000: | ||
399 | num = 384; | ||
400 | den = 1625; | ||
401 | break; | ||
402 | case 2700000: | ||
403 | num = 256; | ||
404 | den = 1125; | ||
405 | break; | ||
406 | case 38400000: | ||
407 | default: | ||
408 | /* Program it for 38.4 MHz */ | ||
409 | num = 4; | ||
410 | den = 25; | ||
411 | break; | ||
412 | } | ||
413 | |||
414 | /* Program numerator and denumerator registers */ | ||
415 | reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & | ||
416 | NUMERATOR_DENUMERATOR_MASK; | ||
417 | reg |= num; | ||
418 | __raw_writel(reg, base + INCREMENTER_NUMERATOR_OFFSET); | ||
419 | |||
420 | reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & | ||
421 | NUMERATOR_DENUMERATOR_MASK; | ||
422 | reg |= den; | ||
423 | __raw_writel(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET); | ||
424 | |||
425 | iounmap(base); | ||
426 | } | ||
427 | #else | ||
428 | static inline void __init realtime_counter_init(void) | ||
429 | {} | ||
430 | #endif | ||
431 | |||
349 | #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ | 432 | #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ |
350 | clksrc_nr, clksrc_src) \ | 433 | clksrc_nr, clksrc_src) \ |
351 | static void __init omap##name##_timer_init(void) \ | 434 | static void __init omap##name##_timer_init(void) \ |
@@ -403,7 +486,12 @@ OMAP_SYS_TIMER(4) | |||
403 | #endif | 486 | #endif |
404 | 487 | ||
405 | #ifdef CONFIG_SOC_OMAP5 | 488 | #ifdef CONFIG_SOC_OMAP5 |
406 | OMAP_SYS_TIMER_INIT(5, 1, OMAP4_CLKEV_SOURCE, 2, OMAP4_MPU_SOURCE) | 489 | static void __init omap5_timer_init(void) |
490 | { | ||
491 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); | ||
492 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); | ||
493 | realtime_counter_init(); | ||
494 | } | ||
407 | OMAP_SYS_TIMER(5) | 495 | OMAP_SYS_TIMER(5) |
408 | #endif | 496 | #endif |
409 | 497 | ||