aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/dmtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r--arch/arm/plat-omap/dmtimer.c212
1 files changed, 169 insertions, 43 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 302ad8dff2cb..f22506af0e67 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -38,34 +38,113 @@
38#include <asm/arch/irqs.h> 38#include <asm/arch/irqs.h>
39 39
40/* register offsets */ 40/* register offsets */
41#define OMAP_TIMER_ID_REG 0x00 41#define _OMAP_TIMER_ID_OFFSET 0x00
42#define OMAP_TIMER_OCP_CFG_REG 0x10 42#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10
43#define OMAP_TIMER_SYS_STAT_REG 0x14 43#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14
44#define OMAP_TIMER_STAT_REG 0x18 44#define _OMAP_TIMER_STAT_OFFSET 0x18
45#define OMAP_TIMER_INT_EN_REG 0x1c 45#define _OMAP_TIMER_INT_EN_OFFSET 0x1c
46#define OMAP_TIMER_WAKEUP_EN_REG 0x20 46#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20
47#define OMAP_TIMER_CTRL_REG 0x24 47#define _OMAP_TIMER_CTRL_OFFSET 0x24
48#define OMAP_TIMER_COUNTER_REG 0x28 48#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
49#define OMAP_TIMER_LOAD_REG 0x2c 49#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
50#define OMAP_TIMER_TRIGGER_REG 0x30 50#define OMAP_TIMER_CTRL_PT (1 << 12)
51#define OMAP_TIMER_WRITE_PEND_REG 0x34 51#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
52#define OMAP_TIMER_MATCH_REG 0x38 52#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
53#define OMAP_TIMER_CAPTURE_REG 0x3c 53#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
54#define OMAP_TIMER_IF_CTRL_REG 0x40 54#define OMAP_TIMER_CTRL_SCPWM (1 << 7)
55 55#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
56/* timer control reg bits */ 56#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
57#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) 57#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */
58#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) 58#define OMAP_TIMER_CTRL_POSTED (1 << 2)
59#define OMAP_TIMER_CTRL_PT (1 << 12) 59#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
60#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) 60#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
61#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) 61#define _OMAP_TIMER_COUNTER_OFFSET 0x28
62#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) 62#define _OMAP_TIMER_LOAD_OFFSET 0x2c
63#define OMAP_TIMER_CTRL_SCPWM (1 << 7) 63#define _OMAP_TIMER_TRIGGER_OFFSET 0x30
64#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ 64#define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34
65#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ 65#define WP_NONE 0 /* no write pending bit */
66#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ 66#define WP_TCLR (1 << 0)
67#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ 67#define WP_TCRR (1 << 1)
68#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ 68#define WP_TLDR (1 << 2)
69#define WP_TTGR (1 << 3)
70#define WP_TMAR (1 << 4)
71#define WP_TPIR (1 << 5)
72#define WP_TNIR (1 << 6)
73#define WP_TCVR (1 << 7)
74#define WP_TOCR (1 << 8)
75#define WP_TOWR (1 << 9)
76#define _OMAP_TIMER_MATCH_OFFSET 0x38
77#define _OMAP_TIMER_CAPTURE_OFFSET 0x3c
78#define _OMAP_TIMER_IF_CTRL_OFFSET 0x40
79#define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */
80#define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */
81#define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */
82#define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */
83#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */
84#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */
85
86/* register offsets with the write pending bit encoded */
87#define WPSHIFT 16
88
89#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \
90 | (WP_NONE << WPSHIFT))
91
92#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \
93 | (WP_NONE << WPSHIFT))
94
95#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \
96 | (WP_NONE << WPSHIFT))
97
98#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \
99 | (WP_NONE << WPSHIFT))
100
101#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \
102 | (WP_NONE << WPSHIFT))
103
104#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \
105 | (WP_NONE << WPSHIFT))
106
107#define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \
108 | (WP_TCLR << WPSHIFT))
109
110#define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \
111 | (WP_TCRR << WPSHIFT))
112
113#define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \
114 | (WP_TLDR << WPSHIFT))
115
116#define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \
117 | (WP_TTGR << WPSHIFT))
118
119#define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \
120 | (WP_NONE << WPSHIFT))
121
122#define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \
123 | (WP_TMAR << WPSHIFT))
124
125#define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \
126 | (WP_NONE << WPSHIFT))
127
128#define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \
129 | (WP_NONE << WPSHIFT))
130
131#define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \
132 | (WP_NONE << WPSHIFT))
133
134#define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \
135 | (WP_TPIR << WPSHIFT))
136
137#define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \
138 | (WP_TNIR << WPSHIFT))
139
140#define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \
141 | (WP_TCVR << WPSHIFT))
142
143#define OMAP_TIMER_TICK_INT_MASK_SET_REG \
144 (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
145
146#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \
147 (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
69 148
70struct omap_dm_timer { 149struct omap_dm_timer {
71 unsigned long phys_base; 150 unsigned long phys_base;
@@ -76,6 +155,7 @@ struct omap_dm_timer {
76 void __iomem *io_base; 155 void __iomem *io_base;
77 unsigned reserved:1; 156 unsigned reserved:1;
78 unsigned enabled:1; 157 unsigned enabled:1;
158 unsigned posted:1;
79}; 159};
80 160
81#ifdef CONFIG_ARCH_OMAP1 161#ifdef CONFIG_ARCH_OMAP1
@@ -181,16 +261,34 @@ static struct clk **dm_source_clocks;
181 261
182static spinlock_t dm_timer_lock; 262static spinlock_t dm_timer_lock;
183 263
184static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) 264/*
265 * Reads timer registers in posted and non-posted mode. The posted mode bit
266 * is encoded in reg. Note that in posted mode write pending bit must be
267 * checked. Otherwise a read of a non completed write will produce an error.
268 */
269static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
185{ 270{
186 return readl(timer->io_base + reg); 271 if (timer->posted)
272 while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
273 & (reg >> WPSHIFT))
274 cpu_relax();
275 return readl(timer->io_base + (reg & 0xff));
187} 276}
188 277
189static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) 278/*
279 * Writes timer registers in posted and non-posted mode. The posted mode bit
280 * is encoded in reg. Note that in posted mode the write pending bit must be
281 * checked. Otherwise a write on a register which has a pending write will be
282 * lost.
283 */
284static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
285 u32 value)
190{ 286{
191 writel(value, timer->io_base + reg); 287 if (timer->posted)
192 while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) 288 while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
193 ; 289 & (reg >> WPSHIFT))
290 cpu_relax();
291 writel(value, timer->io_base + (reg & 0xff));
194} 292}
195 293
196static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) 294static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
@@ -217,17 +315,23 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
217 } 315 }
218 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); 316 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
219 317
220 /* Set to smart-idle mode */
221 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); 318 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
222 l |= 0x02 << 3; 319 l |= 0x02 << 3; /* Set to smart-idle mode */
223 320 l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */
224 if (cpu_class_is_omap2() && timer == &dm_timers[0]) { 321
225 /* Enable wake-up only for GPT1 on OMAP2 CPUs*/ 322 /*
323 * Enable wake-up only for GPT1 on OMAP2 CPUs.
324 * FIXME: All timers should have wake-up enabled and clear
325 * PRCM status.
326 */
327 if (cpu_class_is_omap2() && (timer == &dm_timers[0]))
226 l |= 1 << 2; 328 l |= 1 << 2;
227 /* Non-posted mode */
228 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0);
229 }
230 omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); 329 omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
330
331 /* Match hardware reset default of posted mode */
332 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
333 OMAP_TIMER_CTRL_POSTED);
334 timer->posted = 1;
231} 335}
232 336
233static void omap_dm_timer_prepare(struct omap_dm_timer *timer) 337static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
@@ -434,9 +538,32 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
434 l &= ~OMAP_TIMER_CTRL_AR; 538 l &= ~OMAP_TIMER_CTRL_AR;
435 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 539 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
436 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); 540 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
541
542 /* REVISIT: hw feature, ttgr overtaking tldr? */
543 while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)))
544 cpu_relax();
545
437 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); 546 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
438} 547}
439 548
549/* Optimized set_load which removes costly spin wait in timer_start */
550void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
551 unsigned int load)
552{
553 u32 l;
554
555 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
556 if (autoreload)
557 l |= OMAP_TIMER_CTRL_AR;
558 else
559 l &= ~OMAP_TIMER_CTRL_AR;
560 l |= OMAP_TIMER_CTRL_ST;
561
562 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load);
563 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
564 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
565}
566
440void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, 567void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
441 unsigned int match) 568 unsigned int match)
442{ 569{
@@ -451,7 +578,6 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
451 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); 578 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
452} 579}
453 580
454
455void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, 581void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
456 int toggle, int trigger) 582 int toggle, int trigger)
457{ 583{