diff options
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 78 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 119 |
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 | */ |
171 | static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) | 171 | static 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) | |||
186 | static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, | 182 | static 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 | ||
196 | static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) | 188 | static 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 | ||
210 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) | 202 | static 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 | ||
241 | static void omap_dm_timer_prepare(struct omap_dm_timer *timer) | 226 | void 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 | ||
411 | void omap_dm_timer_stop(struct omap_dm_timer *timer) | 396 | void 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 | } |
433 | EXPORT_SYMBOL_GPL(omap_dm_timer_stop); | 406 | EXPORT_SYMBOL_GPL(omap_dm_timer_stop); |
434 | 407 | ||
@@ -451,22 +424,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); | |||
451 | 424 | ||
452 | int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) | 425 | int 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 | } |
471 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); | 433 | EXPORT_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 | } |
510 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); | 471 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); |
511 | 472 | ||
@@ -558,8 +519,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); | |||
558 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, | 519 | void 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 | } |
564 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); | 524 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); |
565 | 525 | ||
@@ -575,17 +535,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); | |||
575 | 535 | ||
576 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) | 536 | void 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 | } |
580 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); | 540 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); |
581 | 541 | ||
582 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) | 542 | unsigned 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 | } |
590 | EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); | 546 | EXPORT_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 | ||
224 | void omap_dm_timer_prepare(struct omap_dm_timer *timer); | ||
225 | |||
226 | static 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 | |||
237 | static 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 */ | ||
249 | static 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 | |||
271 | static 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 | |||
289 | static 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 | |||
314 | static 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 | |||
321 | static 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 | |||
328 | static 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 | |||
334 | static 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 */ |