diff options
-rw-r--r-- | arch/arm/mach-omap1/timer32k.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 112 | ||||
-rw-r--r-- | arch/arm/plat-omap/counter_32k.c | 91 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/common.h | 2 |
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 | |||
247 | static void __init omap2_gp_clocksource_init(int unused, const char *dummy) | ||
248 | { | ||
249 | omap_init_clocksource_32k(); | ||
250 | } | ||
251 | |||
252 | #else | ||
253 | |||
254 | static struct omap_dm_timer clksrc; | 239 | static struct omap_dm_timer clksrc; |
240 | static 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 */ |
281 | static void __init omap2_gp_clocksource_init(int gptimer_id, | 267 | static 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 | |||
306 | static 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 | |||
326 | static 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) \ |
304 | static void __init omap##name##_timer_init(void) \ | 347 | static 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, | |||
335 | static void __init omap4_timer_init(void) | 378 | static 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 | } |
505 | arch_initcall(omap2_dm_timer_init); | 548 | arch_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 | */ | ||
559 | static 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 | } | ||
573 | early_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 | */ |
36 | static void __iomem *timer_32k_base; | 39 | static void __iomem *sync32k_cnt_reg; |
37 | |||
38 | #define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 | ||
39 | 40 | ||
40 | static u32 notrace omap_32k_read_sched_clock(void) | 41 | static 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 | ||
71 | int __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 | */ | ||
81 | int __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 | ||
33 | extern int __init omap_init_clocksource_32k(void); | 33 | extern int __init omap_init_clocksource_32k(void __iomem *vbase); |
34 | 34 | ||
35 | extern void omap_reserve(void); | 35 | extern void omap_reserve(void); |
36 | extern int omap_dss_reset(struct omap_hwmod *); | 36 | extern int omap_dss_reset(struct omap_hwmod *); |