aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/counter_32k.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/plat-omap/counter_32k.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/plat-omap/counter_32k.c')
-rw-r--r--arch/arm/plat-omap/counter_32k.c91
1 files changed, 39 insertions, 52 deletions
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index 5068fe5a6910..b2f634ba7bc7 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -27,19 +27,20 @@
27 27
28#include <plat/clock.h> 28#include <plat/clock.h>
29 29
30/* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */
31#define OMAP2_32KSYNCNT_CR_OFF 0x10
32
30/* 33/*
31 * 32KHz clocksource ... always available, on pretty most chips except 34 * 32KHz clocksource ... always available, on pretty most chips except
32 * OMAP 730 and 1510. Other timers could be used as clocksources, with 35 * OMAP 730 and 1510. Other timers could be used as clocksources, with
33 * higher resolution in free-running counter modes (e.g. 12 MHz xtal), 36 * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
34 * but systems won't necessarily want to spend resources that way. 37 * but systems won't necessarily want to spend resources that way.
35 */ 38 */
36static void __iomem *timer_32k_base; 39static void __iomem *sync32k_cnt_reg;
37
38#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
39 40
40static u32 notrace omap_32k_read_sched_clock(void) 41static u32 notrace omap_32k_read_sched_clock(void)
41{ 42{
42 return timer_32k_base ? __raw_readl(timer_32k_base) : 0; 43 return sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0;
43} 44}
44 45
45/** 46/**
@@ -59,7 +60,7 @@ void read_persistent_clock(struct timespec *ts)
59 struct timespec *tsp = &persistent_ts; 60 struct timespec *tsp = &persistent_ts;
60 61
61 last_cycles = cycles; 62 last_cycles = cycles;
62 cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; 63 cycles = sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0;
63 delta = cycles - last_cycles; 64 delta = cycles - last_cycles;
64 65
65 nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); 66 nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift);
@@ -68,54 +69,40 @@ void read_persistent_clock(struct timespec *ts)
68 *ts = *tsp; 69 *ts = *tsp;
69} 70}
70 71
71int __init omap_init_clocksource_32k(void) 72/**
73 * omap_init_clocksource_32k - setup and register counter 32k as a
74 * kernel clocksource
75 * @pbase: base addr of counter_32k module
76 * @size: size of counter_32k to map
77 *
78 * Returns 0 upon success or negative error code upon failure.
79 *
80 */
81int __init omap_init_clocksource_32k(void __iomem *vbase)
72{ 82{
73 static char err[] __initdata = KERN_ERR 83 int ret;
74 "%s: can't register clocksource!\n"; 84
75 85 /*
76 if (cpu_is_omap16xx() || cpu_class_is_omap2()) { 86 * 32k sync Counter register offset is at 0x10
77 u32 pbase; 87 */
78 unsigned long size = SZ_4K; 88 sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF;
79 void __iomem *base; 89
80 struct clk *sync_32k_ick; 90 /*
81 91 * 120000 rough estimate from the calculations in
82 if (cpu_is_omap16xx()) { 92 * __clocksource_updatefreq_scale.
83 pbase = OMAP16XX_TIMER_32K_SYNCHRONIZED; 93 */
84 size = SZ_1K; 94 clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
85 } else if (cpu_is_omap2420()) 95 32768, NSEC_PER_SEC, 120000);
86 pbase = OMAP2420_32KSYNCT_BASE + 0x10; 96
87 else if (cpu_is_omap2430()) 97 ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768,
88 pbase = OMAP2430_32KSYNCT_BASE + 0x10; 98 250, 32, clocksource_mmio_readl_up);
89 else if (cpu_is_omap34xx()) 99 if (ret) {
90 pbase = OMAP3430_32KSYNCT_BASE + 0x10; 100 pr_err("32k_counter: can't register clocksource\n");
91 else if (cpu_is_omap44xx()) 101 return ret;
92 pbase = OMAP4430_32KSYNCT_BASE + 0x10;
93 else
94 return -ENODEV;
95
96 /* For this to work we must have a static mapping in io.c for this area */
97 base = ioremap(pbase, size);
98 if (!base)
99 return -ENODEV;
100
101 sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
102 if (!IS_ERR(sync_32k_ick))
103 clk_enable(sync_32k_ick);
104
105 timer_32k_base = base;
106
107 /*
108 * 120000 rough estimate from the calculations in
109 * __clocksource_updatefreq_scale.
110 */
111 clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
112 32768, NSEC_PER_SEC, 120000);
113
114 if (clocksource_mmio_init(base, "32k_counter", 32768, 250, 32,
115 clocksource_mmio_readl_up))
116 printk(err, "32k_counter");
117
118 setup_sched_clock(omap_32k_read_sched_clock, 32, 32768);
119 } 102 }
103
104 setup_sched_clock(omap_32k_read_sched_clock, 32, 32768);
105 pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
106
120 return 0; 107 return 0;
121} 108}