aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r--arch/arm/mach-omap2/timer.c140
1 files changed, 105 insertions, 35 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index c512bac69ec5..840929bd9dae 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -90,7 +90,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
90} 90}
91 91
92static struct irqaction omap2_gp_timer_irq = { 92static struct irqaction omap2_gp_timer_irq = {
93 .name = "gp timer", 93 .name = "gp_timer",
94 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 94 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
95 .handler = omap2_gp_timer_interrupt, 95 .handler = omap2_gp_timer_interrupt,
96}; 96};
@@ -132,7 +132,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
132} 132}
133 133
134static struct clock_event_device clockevent_gpt = { 134static struct clock_event_device clockevent_gpt = {
135 .name = "gp timer", 135 .name = "gp_timer",
136 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 136 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
137 .shift = 32, 137 .shift = 32,
138 .set_next_event = omap2_gp_timer_set_next_event, 138 .set_next_event = omap2_gp_timer_set_next_event,
@@ -145,8 +145,10 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
145{ 145{
146 char name[10]; /* 10 = sizeof("gptXX_Xck0") */ 146 char name[10]; /* 10 = sizeof("gptXX_Xck0") */
147 struct omap_hwmod *oh; 147 struct omap_hwmod *oh;
148 struct resource irq_rsrc, mem_rsrc;
148 size_t size; 149 size_t size;
149 int res = 0; 150 int res = 0;
151 int r;
150 152
151 sprintf(name, "timer%d", gptimer_id); 153 sprintf(name, "timer%d", gptimer_id);
152 omap_hwmod_setup_one(name); 154 omap_hwmod_setup_one(name);
@@ -154,9 +156,16 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
154 if (!oh) 156 if (!oh)
155 return -ENODEV; 157 return -ENODEV;
156 158
157 timer->irq = oh->mpu_irqs[0].irq; 159 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq_rsrc);
158 timer->phys_base = oh->slaves[0]->addr->pa_start; 160 if (r)
159 size = oh->slaves[0]->addr->pa_end - timer->phys_base; 161 return -ENXIO;
162 timer->irq = irq_rsrc.start;
163
164 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, &mem_rsrc);
165 if (r)
166 return -ENXIO;
167 timer->phys_base = mem_rsrc.start;
168 size = mem_rsrc.end - mem_rsrc.start;
160 169
161 /* Static mapping, never released */ 170 /* Static mapping, never released */
162 timer->io_base = ioremap(timer->phys_base, size); 171 timer->io_base = ioremap(timer->phys_base, size);
@@ -169,13 +178,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
169 if (IS_ERR(timer->fclk)) 178 if (IS_ERR(timer->fclk))
170 return -ENODEV; 179 return -ENODEV;
171 180
172 sprintf(name, "gpt%d_ick", gptimer_id);
173 timer->iclk = clk_get(NULL, name);
174 if (IS_ERR(timer->iclk)) {
175 clk_put(timer->fclk);
176 return -ENODEV;
177 }
178
179 omap_hwmod_enable(oh); 181 omap_hwmod_enable(oh);
180 182
181 sys_timer_reserved |= (1 << (gptimer_id - 1)); 183 sys_timer_reserved |= (1 << (gptimer_id - 1));
@@ -234,22 +236,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
234} 236}
235 237
236/* Clocksource code */ 238/* Clocksource code */
237
238#ifdef CONFIG_OMAP_32K_TIMER
239/*
240 * When 32k-timer is enabled, don't use GPTimer for clocksource
241 * instead, just leave default clocksource which uses the 32k
242 * sync counter. See clocksource setup in plat-omap/counter_32k.c
243 */
244
245static void __init omap2_gp_clocksource_init(int unused, const char *dummy)
246{
247 omap_init_clocksource_32k();
248}
249
250#else
251
252static struct omap_dm_timer clksrc; 239static struct omap_dm_timer clksrc;
240static bool use_gptimer_clksrc;
253 241
254/* 242/*
255 * clocksource 243 * clocksource
@@ -260,7 +248,7 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs)
260} 248}
261 249
262static struct clocksource clocksource_gpt = { 250static struct clocksource clocksource_gpt = {
263 .name = "gp timer", 251 .name = "gp_timer",
264 .rating = 300, 252 .rating = 300,
265 .read = clocksource_read_cycles, 253 .read = clocksource_read_cycles,
266 .mask = CLOCKSOURCE_MASK(32), 254 .mask = CLOCKSOURCE_MASK(32),
@@ -276,7 +264,46 @@ static u32 notrace dmtimer_read_sched_clock(void)
276} 264}
277 265
278/* Setup free-running counter for clocksource */ 266/* Setup free-running counter for clocksource */
279static 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,
280 const char *fck_source) 307 const char *fck_source)
281{ 308{
282 int res; 309 int res;
@@ -284,9 +311,6 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
284 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); 311 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source);
285 BUG_ON(res); 312 BUG_ON(res);
286 313
287 pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
288 gptimer_id, clksrc.rate);
289
290 __omap_dm_timer_load_start(&clksrc, 314 __omap_dm_timer_load_start(&clksrc,
291 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); 315 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
292 setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); 316 setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
@@ -294,15 +318,36 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
294 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) 318 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
295 pr_err("Could not register clocksource %s\n", 319 pr_err("Could not register clocksource %s\n",
296 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);
297} 343}
298#endif
299 344
300#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ 345#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \
301 clksrc_nr, clksrc_src) \ 346 clksrc_nr, clksrc_src) \
302static void __init omap##name##_timer_init(void) \ 347static void __init omap##name##_timer_init(void) \
303{ \ 348{ \
304 omap2_gp_clockevent_init((clkev_nr), clkev_src); \ 349 omap2_gp_clockevent_init((clkev_nr), clkev_src); \
305 omap2_gp_clocksource_init((clksrc_nr), clksrc_src); \ 350 omap2_clocksource_init((clksrc_nr), clksrc_src); \
306} 351}
307 352
308#define OMAP_SYS_TIMER(name) \ 353#define OMAP_SYS_TIMER(name) \
@@ -333,7 +378,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
333static void __init omap4_timer_init(void) 378static void __init omap4_timer_init(void)
334{ 379{
335 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); 380 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
336 omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE); 381 omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
337#ifdef CONFIG_LOCAL_TIMERS 382#ifdef CONFIG_LOCAL_TIMERS
338 /* Local timers are not supprted on OMAP4430 ES1.0 */ 383 /* Local timers are not supprted on OMAP4430 ES1.0 */
339 if (omap_rev() != OMAP4430_REV_ES1_0) { 384 if (omap_rev() != OMAP4430_REV_ES1_0) {
@@ -501,3 +546,28 @@ static int __init omap2_dm_timer_init(void)
501 return 0; 546 return 0;
502} 547}
503arch_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);