aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2011-03-29 18:54:48 -0400
committerTony Lindgren <tony@atomide.com>2011-06-20 04:25:39 -0400
commitcaf64f2fdc48472995d40656eb1a75524c464447 (patch)
treeda7b97e9a711552463640d526a023dd40d3807da
parentec97489d199b3dcfc44042ccf89b37a264d14565 (diff)
omap: Make a subset of dmtimer functions into inline functions
This will allow us to share the code between system timer and dmtimer device driver code without having to initialize all the dmtimers early. This change will also make the timer_set_next_event more efficient as the inline functions will optimize the code better for the timer reprogramming. Signed-off-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Kevin Hilman <khilman@ti.com>
-rw-r--r--arch/arm/plat-omap/dmtimer.c78
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h119
2 files changed, 136 insertions, 61 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index dfdc3b2e3201..7c5cb4e128f2 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -170,11 +170,7 @@ static spinlock_t dm_timer_lock;
170 */ 170 */
171static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) 171static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
172{ 172{
173 if (timer->posted) 173 return __omap_dm_timer_read(timer->io_base, reg, timer->posted);
174 while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
175 & (reg >> WPSHIFT))
176 cpu_relax();
177 return readl(timer->io_base + (reg & 0xff));
178} 174}
179 175
180/* 176/*
@@ -186,11 +182,7 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
186static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, 182static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
187 u32 value) 183 u32 value)
188{ 184{
189 if (timer->posted) 185 __omap_dm_timer_write(timer->io_base, reg, value, timer->posted);
190 while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
191 & (reg >> WPSHIFT))
192 cpu_relax();
193 writel(value, timer->io_base + (reg & 0xff));
194} 186}
195 187
196static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) 188static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
@@ -209,7 +201,7 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
209 201
210static void omap_dm_timer_reset(struct omap_dm_timer *timer) 202static void omap_dm_timer_reset(struct omap_dm_timer *timer)
211{ 203{
212 u32 l; 204 int autoidle = 0, wakeup = 0;
213 205
214 if (!cpu_class_is_omap2() || timer != &dm_timers[0]) { 206 if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
215 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); 207 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
@@ -217,28 +209,21 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
217 } 209 }
218 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); 210 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
219 211
220 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
221 l |= 0x02 << 3; /* Set to smart-idle mode */
222 l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */
223
224 /* Enable autoidle on OMAP2 / OMAP3 */ 212 /* Enable autoidle on OMAP2 / OMAP3 */
225 if (cpu_is_omap24xx() || cpu_is_omap34xx()) 213 if (cpu_is_omap24xx() || cpu_is_omap34xx())
226 l |= 0x1 << 0; 214 autoidle = 1;
227 215
228 /* 216 /*
229 * Enable wake-up on OMAP2 CPUs. 217 * Enable wake-up on OMAP2 CPUs.
230 */ 218 */
231 if (cpu_class_is_omap2()) 219 if (cpu_class_is_omap2())
232 l |= 1 << 2; 220 wakeup = 1;
233 omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
234 221
235 /* Match hardware reset default of posted mode */ 222 __omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
236 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
237 OMAP_TIMER_CTRL_POSTED);
238 timer->posted = 1; 223 timer->posted = 1;
239} 224}
240 225
241static void omap_dm_timer_prepare(struct omap_dm_timer *timer) 226void omap_dm_timer_prepare(struct omap_dm_timer *timer)
242{ 227{
243 omap_dm_timer_enable(timer); 228 omap_dm_timer_enable(timer);
244 omap_dm_timer_reset(timer); 229 omap_dm_timer_reset(timer);
@@ -410,25 +395,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
410 395
411void omap_dm_timer_stop(struct omap_dm_timer *timer) 396void omap_dm_timer_stop(struct omap_dm_timer *timer)
412{ 397{
413 u32 l; 398 unsigned long rate = 0;
414 399
415 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
416 if (l & OMAP_TIMER_CTRL_ST) {
417 l &= ~0x1;
418 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
419#ifdef CONFIG_ARCH_OMAP2PLUS 400#ifdef CONFIG_ARCH_OMAP2PLUS
420 /* Readback to make sure write has completed */ 401 rate = clk_get_rate(timer->fclk);
421 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
422 /*
423 * Wait for functional clock period x 3.5 to make sure that
424 * timer is stopped
425 */
426 udelay(3500000 / clk_get_rate(timer->fclk) + 1);
427#endif 402#endif
428 } 403
429 /* Ack possibly pending interrupt */ 404 __omap_dm_timer_stop(timer->io_base, timer->posted, rate);
430 omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG,
431 OMAP_TIMER_INT_OVERFLOW);
432} 405}
433EXPORT_SYMBOL_GPL(omap_dm_timer_stop); 406EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
434 407
@@ -451,22 +424,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
451 424
452int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) 425int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
453{ 426{
454 int ret = -EINVAL;
455
456 if (source < 0 || source >= 3) 427 if (source < 0 || source >= 3)
457 return -EINVAL; 428 return -EINVAL;
458 429
459 clk_disable(timer->fclk); 430 return __omap_dm_timer_set_source(timer->fclk,
460 ret = clk_set_parent(timer->fclk, dm_source_clocks[source]); 431 dm_source_clocks[source]);
461 clk_enable(timer->fclk);
462
463 /*
464 * When the functional clock disappears, too quick writes seem
465 * to cause an abort. XXX Is this still necessary?
466 */
467 __delay(300000);
468
469 return ret;
470} 432}
471EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); 433EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
472 434
@@ -504,8 +466,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
504 } 466 }
505 l |= OMAP_TIMER_CTRL_ST; 467 l |= OMAP_TIMER_CTRL_ST;
506 468
507 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load); 469 __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted);
508 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
509} 470}
510EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); 471EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
511 472
@@ -558,8 +519,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
558void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, 519void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
559 unsigned int value) 520 unsigned int value)
560{ 521{
561 omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); 522 __omap_dm_timer_int_enable(timer->io_base, value);
562 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
563} 523}
564EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); 524EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
565 525
@@ -575,17 +535,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
575 535
576void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) 536void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
577{ 537{
578 omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); 538 __omap_dm_timer_write_status(timer->io_base, value);
579} 539}
580EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); 540EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
581 541
582unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) 542unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
583{ 543{
584 unsigned int l; 544 return __omap_dm_timer_read_counter(timer->io_base, timer->posted);
585
586 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
587
588 return l;
589} 545}
590EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); 546EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
591 547
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 32031056165d..54664a7498af 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -32,6 +32,9 @@
32 * 675 Mass Ave, Cambridge, MA 02139, USA. 32 * 675 Mass Ave, Cambridge, MA 02139, USA.
33 */ 33 */
34 34
35#include <linux/clk.h>
36#include <linux/delay.h>
37
35#ifndef __ASM_ARCH_DMTIMER_H 38#ifndef __ASM_ARCH_DMTIMER_H
36#define __ASM_ARCH_DMTIMER_H 39#define __ASM_ARCH_DMTIMER_H
37 40
@@ -218,4 +221,120 @@ struct omap_dm_timer {
218 unsigned posted:1; 221 unsigned posted:1;
219}; 222};
220 223
224void omap_dm_timer_prepare(struct omap_dm_timer *timer);
225
226static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
227 int posted)
228{
229 if (posted)
230 while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
231 & (reg >> WPSHIFT))
232 cpu_relax();
233
234 return __raw_readl(base + (reg & 0xff));
235}
236
237static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val,
238 int posted)
239{
240 if (posted)
241 while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
242 & (reg >> WPSHIFT))
243 cpu_relax();
244
245 __raw_writel(val, base + (reg & 0xff));
246}
247
248/* Assumes the source clock has been set by caller */
249static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
250 int wakeup)
251{
252 u32 l;
253
254 l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0);
255 l |= 0x02 << 3; /* Set to smart-idle mode */
256 l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */
257
258 if (autoidle)
259 l |= 0x1 << 0;
260
261 if (wakeup)
262 l |= 1 << 2;
263
264 __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0);
265
266 /* Match hardware reset default of posted mode */
267 __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG,
268 OMAP_TIMER_CTRL_POSTED, 0);
269}
270
271static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
272 struct clk *parent)
273{
274 int ret;
275
276 clk_disable(timer_fck);
277 ret = clk_set_parent(timer_fck, parent);
278 clk_enable(timer_fck);
279
280 /*
281 * When the functional clock disappears, too quick writes seem
282 * to cause an abort. XXX Is this still necessary?
283 */
284 __delay(300000);
285
286 return ret;
287}
288
289static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
290 unsigned long rate)
291{
292 u32 l;
293
294 l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
295 if (l & OMAP_TIMER_CTRL_ST) {
296 l &= ~0x1;
297 __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted);
298#ifdef CONFIG_ARCH_OMAP2PLUS
299 /* Readback to make sure write has completed */
300 __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
301 /*
302 * Wait for functional clock period x 3.5 to make sure that
303 * timer is stopped
304 */
305 udelay(3500000 / rate + 1);
306#endif
307 }
308
309 /* Ack possibly pending interrupt */
310 __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG,
311 OMAP_TIMER_INT_OVERFLOW, 0);
312}
313
314static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl,
315 unsigned int load, int posted)
316{
317 __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted);
318 __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted);
319}
320
321static inline void __omap_dm_timer_int_enable(void __iomem *base,
322 unsigned int value)
323{
324 __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0);
325 __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
326}
327
328static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base,
329 int posted)
330{
331 return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted);
332}
333
334static inline void __omap_dm_timer_write_status(void __iomem *base,
335 unsigned int value)
336{
337 __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0);
338}
339
221#endif /* __ASM_ARCH_DMTIMER_H */ 340#endif /* __ASM_ARCH_DMTIMER_H */