aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap1/timer32k.c19
-rw-r--r--arch/arm/mach-omap2/timer.c112
-rw-r--r--arch/arm/plat-omap/counter_32k.c91
-rw-r--r--arch/arm/plat-omap/include/plat/common.h2
4 files changed, 147 insertions, 77 deletions
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index e3613a8bcd90..eae49c3980c9 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -71,6 +71,7 @@
71 71
72/* 16xx specific defines */ 72/* 16xx specific defines */
73#define OMAP1_32K_TIMER_BASE 0xfffb9000 73#define OMAP1_32K_TIMER_BASE 0xfffb9000
74#define OMAP1_32KSYNC_TIMER_BASE 0xfffbc400
74#define OMAP1_32K_TIMER_CR 0x08 75#define OMAP1_32K_TIMER_CR 0x08
75#define OMAP1_32K_TIMER_TVR 0x00 76#define OMAP1_32K_TIMER_TVR 0x00
76#define OMAP1_32K_TIMER_TCR 0x04 77#define OMAP1_32K_TIMER_TCR 0x04
@@ -186,8 +187,22 @@ int __init omap_32k_timer_init(void)
186{ 187{
187 int ret = -ENODEV; 188 int ret = -ENODEV;
188 189
189 if (cpu_is_omap16xx()) 190 if (cpu_is_omap16xx()) {
190 ret = omap_init_clocksource_32k(); 191 void __iomem *base;
192 struct clk *sync32k_ick;
193
194 base = ioremap(OMAP1_32KSYNC_TIMER_BASE, SZ_1K);
195 if (!base) {
196 pr_err("32k_counter: failed to map base addr\n");
197 return -ENODEV;
198 }
199
200 sync32k_ick = clk_get(NULL, "omap_32ksync_ick");
201 if (!IS_ERR(sync32k_ick))
202 clk_enable(sync32k_ick);
203
204 ret = omap_init_clocksource_32k(base);
205 }
191 206
192 if (!ret) 207 if (!ret)
193 omap_init_32k_timer(); 208 omap_init_32k_timer();
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);
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}
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index b4d7ec3fbfbe..55c514be382e 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -30,7 +30,7 @@
30#include <plat/i2c.h> 30#include <plat/i2c.h>
31#include <plat/omap_hwmod.h> 31#include <plat/omap_hwmod.h>
32 32
33extern int __init omap_init_clocksource_32k(void); 33extern int __init omap_init_clocksource_32k(void __iomem *vbase);
34 34
35extern void omap_reserve(void); 35extern void omap_reserve(void);
36extern int omap_dss_reset(struct omap_hwmod *); 36extern int omap_dss_reset(struct omap_hwmod *);