aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/include
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2011-09-16 18:44:20 -0400
committerTony Lindgren <tony@atomide.com>2011-09-19 13:28:10 -0400
commitee17f1147f010898e97dea2524b2aa3bcd2447a4 (patch)
treeb8526aa2d3f8f6830ec6f9f6834fc206850d48bc /arch/arm/plat-omap/include
parentceb1c532ba6220900e61ec7073a9234661efa450 (diff)
ARM: OMAP: Add support for dmtimer v2 ip
The registers are slightly different between v1 and v2 ip that is available in omap4 and later for some timers. Add support for v2 ip by mapping the interrupt related registers separately and adding func_base for the functional registers. Also disable dmtimer driver features on omap4 for now as those need the hwmod conversion series to deal with enabling the timers properly in omap_dm_timer_init. Signed-off-by: Afzal Mohammed <afzal@ti.com> Tested-by: Hemant Pedanekar <hemantp@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/plat-omap/include')
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h144
1 files changed, 89 insertions, 55 deletions
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index eb5d16c60cd9..ad554d36866d 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -98,12 +98,30 @@ int omap_dm_timers_active(void);
98 * used by dmtimer.c and sys_timer related code. 98 * used by dmtimer.c and sys_timer related code.
99 */ 99 */
100 100
101/* register offsets */ 101/*
102#define _OMAP_TIMER_ID_OFFSET 0x00 102 * The interrupt registers are different between v1 and v2 ip.
103#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 103 * These registers are offsets from timer->iobase.
104#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 104 */
105#define _OMAP_TIMER_STAT_OFFSET 0x18 105#define OMAP_TIMER_ID_OFFSET 0x00
106#define _OMAP_TIMER_INT_EN_OFFSET 0x1c 106#define OMAP_TIMER_OCP_CFG_OFFSET 0x10
107
108#define OMAP_TIMER_V1_SYS_STAT_OFFSET 0x14
109#define OMAP_TIMER_V1_STAT_OFFSET 0x18
110#define OMAP_TIMER_V1_INT_EN_OFFSET 0x1c
111
112#define OMAP_TIMER_V2_IRQSTATUS_RAW 0x24
113#define OMAP_TIMER_V2_IRQSTATUS 0x28
114#define OMAP_TIMER_V2_IRQENABLE_SET 0x2c
115#define OMAP_TIMER_V2_IRQENABLE_CLR 0x30
116
117/*
118 * The functional registers have a different base on v1 and v2 ip.
119 * These registers are offsets from timer->func_base. The func_base
120 * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
121 *
122 */
123#define OMAP_TIMER_V2_FUNC_OFFSET 0x14
124
107#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 125#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20
108#define _OMAP_TIMER_CTRL_OFFSET 0x24 126#define _OMAP_TIMER_CTRL_OFFSET 0x24
109#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) 127#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
@@ -147,21 +165,6 @@ int omap_dm_timers_active(void);
147/* register offsets with the write pending bit encoded */ 165/* register offsets with the write pending bit encoded */
148#define WPSHIFT 16 166#define WPSHIFT 16
149 167
150#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \
151 | (WP_NONE << WPSHIFT))
152
153#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \
154 | (WP_NONE << WPSHIFT))
155
156#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \
157 | (WP_NONE << WPSHIFT))
158
159#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \
160 | (WP_NONE << WPSHIFT))
161
162#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \
163 | (WP_NONE << WPSHIFT))
164
165#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ 168#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \
166 | (WP_NONE << WPSHIFT)) 169 | (WP_NONE << WPSHIFT))
167 170
@@ -213,7 +216,14 @@ struct omap_dm_timer {
213#ifdef CONFIG_ARCH_OMAP2PLUS 216#ifdef CONFIG_ARCH_OMAP2PLUS
214 struct clk *iclk, *fclk; 217 struct clk *iclk, *fclk;
215#endif 218#endif
216 void __iomem *io_base; 219 void __iomem *io_base;
220 void __iomem *sys_stat; /* TISTAT timer status */
221 void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */
222 void __iomem *irq_ena; /* irq enable */
223 void __iomem *irq_dis; /* irq disable, only on v2 ip */
224 void __iomem *pend; /* write pending */
225 void __iomem *func_base; /* function register base */
226
217 unsigned long rate; 227 unsigned long rate;
218 unsigned reserved:1; 228 unsigned reserved:1;
219 unsigned enabled:1; 229 unsigned enabled:1;
@@ -223,35 +233,59 @@ struct omap_dm_timer {
223extern u32 sys_timer_reserved; 233extern u32 sys_timer_reserved;
224void omap_dm_timer_prepare(struct omap_dm_timer *timer); 234void omap_dm_timer_prepare(struct omap_dm_timer *timer);
225 235
226static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg, 236static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
227 int posted) 237 int posted)
228{ 238{
229 if (posted) 239 if (posted)
230 while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) 240 while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
231 & (reg >> WPSHIFT))
232 cpu_relax(); 241 cpu_relax();
233 242
234 return __raw_readl(base + (reg & 0xff)); 243 return __raw_readl(timer->func_base + (reg & 0xff));
235} 244}
236 245
237static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val, 246static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
238 int posted) 247 u32 reg, u32 val, int posted)
239{ 248{
240 if (posted) 249 if (posted)
241 while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) 250 while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
242 & (reg >> WPSHIFT))
243 cpu_relax(); 251 cpu_relax();
244 252
245 __raw_writel(val, base + (reg & 0xff)); 253 __raw_writel(val, timer->func_base + (reg & 0xff));
254}
255
256static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
257{
258 u32 tidr;
259
260 /* Assume v1 ip if bits [31:16] are zero */
261 tidr = __raw_readl(timer->io_base);
262 if (!(tidr >> 16)) {
263 timer->sys_stat = timer->io_base +
264 OMAP_TIMER_V1_SYS_STAT_OFFSET;
265 timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
266 timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
267 timer->irq_dis = 0;
268 timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
269 timer->func_base = timer->io_base;
270 } else {
271 timer->sys_stat = 0;
272 timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
273 timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
274 timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
275 timer->pend = timer->io_base +
276 _OMAP_TIMER_WRITE_PEND_OFFSET +
277 OMAP_TIMER_V2_FUNC_OFFSET;
278 timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
279 }
246} 280}
247 281
248/* Assumes the source clock has been set by caller */ 282/* Assumes the source clock has been set by caller */
249static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle, 283static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
250 int wakeup) 284 int autoidle, int wakeup)
251{ 285{
252 u32 l; 286 u32 l;
253 287
254 l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0); 288 l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
255 l |= 0x02 << 3; /* Set to smart-idle mode */ 289 l |= 0x02 << 3; /* Set to smart-idle mode */
256 l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ 290 l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */
257 291
@@ -261,10 +295,10 @@ static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
261 if (wakeup) 295 if (wakeup)
262 l |= 1 << 2; 296 l |= 1 << 2;
263 297
264 __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0); 298 __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
265 299
266 /* Match hardware reset default of posted mode */ 300 /* Match hardware reset default of posted mode */
267 __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG, 301 __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
268 OMAP_TIMER_CTRL_POSTED, 0); 302 OMAP_TIMER_CTRL_POSTED, 0);
269} 303}
270 304
@@ -286,18 +320,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
286 return ret; 320 return ret;
287} 321}
288 322
289static inline void __omap_dm_timer_stop(void __iomem *base, int posted, 323static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
290 unsigned long rate) 324 int posted, unsigned long rate)
291{ 325{
292 u32 l; 326 u32 l;
293 327
294 l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted); 328 l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
295 if (l & OMAP_TIMER_CTRL_ST) { 329 if (l & OMAP_TIMER_CTRL_ST) {
296 l &= ~0x1; 330 l &= ~0x1;
297 __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted); 331 __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
298#ifdef CONFIG_ARCH_OMAP2PLUS 332#ifdef CONFIG_ARCH_OMAP2PLUS
299 /* Readback to make sure write has completed */ 333 /* Readback to make sure write has completed */
300 __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted); 334 __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
301 /* 335 /*
302 * Wait for functional clock period x 3.5 to make sure that 336 * Wait for functional clock period x 3.5 to make sure that
303 * timer is stopped 337 * timer is stopped
@@ -307,34 +341,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
307 } 341 }
308 342
309 /* Ack possibly pending interrupt */ 343 /* Ack possibly pending interrupt */
310 __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, 344 __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
311 OMAP_TIMER_INT_OVERFLOW, 0);
312} 345}
313 346
314static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl, 347static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
315 unsigned int load, int posted) 348 u32 ctrl, unsigned int load,
349 int posted)
316{ 350{
317 __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted); 351 __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
318 __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted); 352 __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
319} 353}
320 354
321static inline void __omap_dm_timer_int_enable(void __iomem *base, 355static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
322 unsigned int value) 356 unsigned int value)
323{ 357{
324 __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0); 358 __raw_writel(value, timer->irq_ena);
325 __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0); 359 __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
326} 360}
327 361
328static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base, 362static inline unsigned int
329 int posted) 363__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
330{ 364{
331 return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted); 365 return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
332} 366}
333 367
334static inline void __omap_dm_timer_write_status(void __iomem *base, 368static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
335 unsigned int value) 369 unsigned int value)
336{ 370{
337 __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0); 371 __raw_writel(value, timer->irq_stat);
338} 372}
339 373
340#endif /* __ASM_ARCH_DMTIMER_H */ 374#endif /* __ASM_ARCH_DMTIMER_H */