diff options
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 209 |
1 files changed, 26 insertions, 183 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index ee9f6ebba29b..8dfb8186b2c2 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c | |||
@@ -41,127 +41,6 @@ | |||
41 | #include <plat/dmtimer.h> | 41 | #include <plat/dmtimer.h> |
42 | #include <mach/irqs.h> | 42 | #include <mach/irqs.h> |
43 | 43 | ||
44 | /* register offsets */ | ||
45 | #define _OMAP_TIMER_ID_OFFSET 0x00 | ||
46 | #define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 | ||
47 | #define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 | ||
48 | #define _OMAP_TIMER_STAT_OFFSET 0x18 | ||
49 | #define _OMAP_TIMER_INT_EN_OFFSET 0x1c | ||
50 | #define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 | ||
51 | #define _OMAP_TIMER_CTRL_OFFSET 0x24 | ||
52 | #define OMAP_TIMER_CTRL_GPOCFG (1 << 14) | ||
53 | #define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) | ||
54 | #define OMAP_TIMER_CTRL_PT (1 << 12) | ||
55 | #define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) | ||
56 | #define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) | ||
57 | #define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) | ||
58 | #define OMAP_TIMER_CTRL_SCPWM (1 << 7) | ||
59 | #define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ | ||
60 | #define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ | ||
61 | #define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */ | ||
62 | #define OMAP_TIMER_CTRL_POSTED (1 << 2) | ||
63 | #define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ | ||
64 | #define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ | ||
65 | #define _OMAP_TIMER_COUNTER_OFFSET 0x28 | ||
66 | #define _OMAP_TIMER_LOAD_OFFSET 0x2c | ||
67 | #define _OMAP_TIMER_TRIGGER_OFFSET 0x30 | ||
68 | #define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34 | ||
69 | #define WP_NONE 0 /* no write pending bit */ | ||
70 | #define WP_TCLR (1 << 0) | ||
71 | #define WP_TCRR (1 << 1) | ||
72 | #define WP_TLDR (1 << 2) | ||
73 | #define WP_TTGR (1 << 3) | ||
74 | #define WP_TMAR (1 << 4) | ||
75 | #define WP_TPIR (1 << 5) | ||
76 | #define WP_TNIR (1 << 6) | ||
77 | #define WP_TCVR (1 << 7) | ||
78 | #define WP_TOCR (1 << 8) | ||
79 | #define WP_TOWR (1 << 9) | ||
80 | #define _OMAP_TIMER_MATCH_OFFSET 0x38 | ||
81 | #define _OMAP_TIMER_CAPTURE_OFFSET 0x3c | ||
82 | #define _OMAP_TIMER_IF_CTRL_OFFSET 0x40 | ||
83 | #define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */ | ||
84 | #define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */ | ||
85 | #define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */ | ||
86 | #define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */ | ||
87 | #define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */ | ||
88 | #define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */ | ||
89 | |||
90 | /* register offsets with the write pending bit encoded */ | ||
91 | #define WPSHIFT 16 | ||
92 | |||
93 | #define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \ | ||
94 | | (WP_NONE << WPSHIFT)) | ||
95 | |||
96 | #define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \ | ||
97 | | (WP_NONE << WPSHIFT)) | ||
98 | |||
99 | #define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \ | ||
100 | | (WP_NONE << WPSHIFT)) | ||
101 | |||
102 | #define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \ | ||
103 | | (WP_NONE << WPSHIFT)) | ||
104 | |||
105 | #define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ | ||
106 | | (WP_NONE << WPSHIFT)) | ||
107 | |||
108 | #define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ | ||
109 | | (WP_NONE << WPSHIFT)) | ||
110 | |||
111 | #define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \ | ||
112 | | (WP_TCLR << WPSHIFT)) | ||
113 | |||
114 | #define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \ | ||
115 | | (WP_TCRR << WPSHIFT)) | ||
116 | |||
117 | #define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \ | ||
118 | | (WP_TLDR << WPSHIFT)) | ||
119 | |||
120 | #define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \ | ||
121 | | (WP_TTGR << WPSHIFT)) | ||
122 | |||
123 | #define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \ | ||
124 | | (WP_NONE << WPSHIFT)) | ||
125 | |||
126 | #define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \ | ||
127 | | (WP_TMAR << WPSHIFT)) | ||
128 | |||
129 | #define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \ | ||
130 | | (WP_NONE << WPSHIFT)) | ||
131 | |||
132 | #define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \ | ||
133 | | (WP_NONE << WPSHIFT)) | ||
134 | |||
135 | #define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \ | ||
136 | | (WP_NONE << WPSHIFT)) | ||
137 | |||
138 | #define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \ | ||
139 | | (WP_TPIR << WPSHIFT)) | ||
140 | |||
141 | #define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \ | ||
142 | | (WP_TNIR << WPSHIFT)) | ||
143 | |||
144 | #define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \ | ||
145 | | (WP_TCVR << WPSHIFT)) | ||
146 | |||
147 | #define OMAP_TIMER_TICK_INT_MASK_SET_REG \ | ||
148 | (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT)) | ||
149 | |||
150 | #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ | ||
151 | (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) | ||
152 | |||
153 | struct omap_dm_timer { | ||
154 | unsigned long phys_base; | ||
155 | int irq; | ||
156 | #ifdef CONFIG_ARCH_OMAP2PLUS | ||
157 | struct clk *iclk, *fclk; | ||
158 | #endif | ||
159 | void __iomem *io_base; | ||
160 | unsigned reserved:1; | ||
161 | unsigned enabled:1; | ||
162 | unsigned posted:1; | ||
163 | }; | ||
164 | |||
165 | static int dm_timer_count; | 44 | static int dm_timer_count; |
166 | 45 | ||
167 | #ifdef CONFIG_ARCH_OMAP1 | 46 | #ifdef CONFIG_ARCH_OMAP1 |
@@ -291,11 +170,7 @@ static spinlock_t dm_timer_lock; | |||
291 | */ | 170 | */ |
292 | 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) |
293 | { | 172 | { |
294 | if (timer->posted) | 173 | return __omap_dm_timer_read(timer->io_base, reg, timer->posted); |
295 | while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) | ||
296 | & (reg >> WPSHIFT)) | ||
297 | cpu_relax(); | ||
298 | return readl(timer->io_base + (reg & 0xff)); | ||
299 | } | 174 | } |
300 | 175 | ||
301 | /* | 176 | /* |
@@ -307,11 +182,7 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) | |||
307 | 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, |
308 | u32 value) | 183 | u32 value) |
309 | { | 184 | { |
310 | if (timer->posted) | 185 | __omap_dm_timer_write(timer->io_base, reg, value, timer->posted); |
311 | while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) | ||
312 | & (reg >> WPSHIFT)) | ||
313 | cpu_relax(); | ||
314 | writel(value, timer->io_base + (reg & 0xff)); | ||
315 | } | 186 | } |
316 | 187 | ||
317 | 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) |
@@ -330,7 +201,7 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) | |||
330 | 201 | ||
331 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) | 202 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) |
332 | { | 203 | { |
333 | u32 l; | 204 | int autoidle = 0, wakeup = 0; |
334 | 205 | ||
335 | if (!cpu_class_is_omap2() || timer != &dm_timers[0]) { | 206 | if (!cpu_class_is_omap2() || timer != &dm_timers[0]) { |
336 | 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); |
@@ -338,28 +209,21 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) | |||
338 | } | 209 | } |
339 | omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); | 210 | omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); |
340 | 211 | ||
341 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); | ||
342 | l |= 0x02 << 3; /* Set to smart-idle mode */ | ||
343 | l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ | ||
344 | |||
345 | /* Enable autoidle on OMAP2 / OMAP3 */ | 212 | /* Enable autoidle on OMAP2 / OMAP3 */ |
346 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | 213 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) |
347 | l |= 0x1 << 0; | 214 | autoidle = 1; |
348 | 215 | ||
349 | /* | 216 | /* |
350 | * Enable wake-up on OMAP2 CPUs. | 217 | * Enable wake-up on OMAP2 CPUs. |
351 | */ | 218 | */ |
352 | if (cpu_class_is_omap2()) | 219 | if (cpu_class_is_omap2()) |
353 | l |= 1 << 2; | 220 | wakeup = 1; |
354 | omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); | ||
355 | 221 | ||
356 | /* Match hardware reset default of posted mode */ | 222 | __omap_dm_timer_reset(timer->io_base, autoidle, wakeup); |
357 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, | ||
358 | OMAP_TIMER_CTRL_POSTED); | ||
359 | timer->posted = 1; | 223 | timer->posted = 1; |
360 | } | 224 | } |
361 | 225 | ||
362 | static void omap_dm_timer_prepare(struct omap_dm_timer *timer) | 226 | void omap_dm_timer_prepare(struct omap_dm_timer *timer) |
363 | { | 227 | { |
364 | omap_dm_timer_enable(timer); | 228 | omap_dm_timer_enable(timer); |
365 | omap_dm_timer_reset(timer); | 229 | omap_dm_timer_reset(timer); |
@@ -531,25 +395,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start); | |||
531 | 395 | ||
532 | void omap_dm_timer_stop(struct omap_dm_timer *timer) | 396 | void omap_dm_timer_stop(struct omap_dm_timer *timer) |
533 | { | 397 | { |
534 | u32 l; | 398 | unsigned long rate = 0; |
535 | 399 | ||
536 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | ||
537 | if (l & OMAP_TIMER_CTRL_ST) { | ||
538 | l &= ~0x1; | ||
539 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | ||
540 | #ifdef CONFIG_ARCH_OMAP2PLUS | 400 | #ifdef CONFIG_ARCH_OMAP2PLUS |
541 | /* Readback to make sure write has completed */ | 401 | rate = clk_get_rate(timer->fclk); |
542 | omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | ||
543 | /* | ||
544 | * Wait for functional clock period x 3.5 to make sure that | ||
545 | * timer is stopped | ||
546 | */ | ||
547 | udelay(3500000 / clk_get_rate(timer->fclk) + 1); | ||
548 | #endif | 402 | #endif |
549 | } | 403 | |
550 | /* Ack possibly pending interrupt */ | 404 | __omap_dm_timer_stop(timer->io_base, timer->posted, rate); |
551 | omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, | ||
552 | OMAP_TIMER_INT_OVERFLOW); | ||
553 | } | 405 | } |
554 | EXPORT_SYMBOL_GPL(omap_dm_timer_stop); | 406 | EXPORT_SYMBOL_GPL(omap_dm_timer_stop); |
555 | 407 | ||
@@ -572,22 +424,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); | |||
572 | 424 | ||
573 | 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) |
574 | { | 426 | { |
575 | int ret = -EINVAL; | ||
576 | |||
577 | if (source < 0 || source >= 3) | 427 | if (source < 0 || source >= 3) |
578 | return -EINVAL; | 428 | return -EINVAL; |
579 | 429 | ||
580 | clk_disable(timer->fclk); | 430 | return __omap_dm_timer_set_source(timer->fclk, |
581 | ret = clk_set_parent(timer->fclk, dm_source_clocks[source]); | 431 | dm_source_clocks[source]); |
582 | clk_enable(timer->fclk); | ||
583 | |||
584 | /* | ||
585 | * When the functional clock disappears, too quick writes seem | ||
586 | * to cause an abort. XXX Is this still necessary? | ||
587 | */ | ||
588 | __delay(300000); | ||
589 | |||
590 | return ret; | ||
591 | } | 432 | } |
592 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); | 433 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); |
593 | 434 | ||
@@ -625,8 +466,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, | |||
625 | } | 466 | } |
626 | l |= OMAP_TIMER_CTRL_ST; | 467 | l |= OMAP_TIMER_CTRL_ST; |
627 | 468 | ||
628 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load); | 469 | __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted); |
629 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | ||
630 | } | 470 | } |
631 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); | 471 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); |
632 | 472 | ||
@@ -679,8 +519,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); | |||
679 | 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, |
680 | unsigned int value) | 520 | unsigned int value) |
681 | { | 521 | { |
682 | omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); | 522 | __omap_dm_timer_int_enable(timer->io_base, value); |
683 | omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value); | ||
684 | } | 523 | } |
685 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); | 524 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); |
686 | 525 | ||
@@ -696,17 +535,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); | |||
696 | 535 | ||
697 | 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) |
698 | { | 537 | { |
699 | omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); | 538 | __omap_dm_timer_write_status(timer->io_base, value); |
700 | } | 539 | } |
701 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); | 540 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); |
702 | 541 | ||
703 | 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) |
704 | { | 543 | { |
705 | unsigned int l; | 544 | return __omap_dm_timer_read_counter(timer->io_base, timer->posted); |
706 | |||
707 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); | ||
708 | |||
709 | return l; | ||
710 | } | 545 | } |
711 | EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); | 546 | EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); |
712 | 547 | ||
@@ -737,7 +572,7 @@ int omap_dm_timers_active(void) | |||
737 | } | 572 | } |
738 | EXPORT_SYMBOL_GPL(omap_dm_timers_active); | 573 | EXPORT_SYMBOL_GPL(omap_dm_timers_active); |
739 | 574 | ||
740 | int __init omap_dm_timer_init(void) | 575 | static int __init omap_dm_timer_init(void) |
741 | { | 576 | { |
742 | struct omap_dm_timer *timer; | 577 | struct omap_dm_timer *timer; |
743 | int i, map_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */ | 578 | int i, map_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */ |
@@ -790,8 +625,16 @@ int __init omap_dm_timer_init(void) | |||
790 | sprintf(clk_name, "gpt%d_fck", i + 1); | 625 | sprintf(clk_name, "gpt%d_fck", i + 1); |
791 | timer->fclk = clk_get(NULL, clk_name); | 626 | timer->fclk = clk_get(NULL, clk_name); |
792 | } | 627 | } |
628 | |||
629 | /* One or two timers may be set up early for sys_timer */ | ||
630 | if (sys_timer_reserved & (1 << i)) { | ||
631 | timer->reserved = 1; | ||
632 | timer->posted = 1; | ||
633 | } | ||
793 | #endif | 634 | #endif |
794 | } | 635 | } |
795 | 636 | ||
796 | return 0; | 637 | return 0; |
797 | } | 638 | } |
639 | |||
640 | arch_initcall(omap_dm_timer_init); | ||