diff options
author | Olof Johansson <olof@lixom.net> | 2012-11-30 01:30:11 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-11-30 01:30:11 -0500 |
commit | c8a1ceccf394b2f99feed2b702732140e9f0f92d (patch) | |
tree | 6632d05aae22e99d7f128104b536bfdfc225a696 /arch/arm/plat-omap/include | |
parent | 4c929c8a8837f4e5acdec5883a1b64a240751e2f (diff) | |
parent | 26f01998b0657a61167a819f1c37cb9f9e9d674b (diff) |
Merge tag 'omap-for-v3.8/cleanup-timer-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/cleanup
Timer clean-up to get us closer to moving timer code to drivers,
and to get rid of CONFIG_OMAP_32K_TIMER and rely on the board
or devicetree provided timer configuration.
Note that these changes are on top of the recent timer fixes.
By Jon Hunter (32) and others
via Tony Lindgren
* tag 'omap-for-v3.8/cleanup-timer-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (71 commits)
ARM: OMAP3: cm-t3517: use GPTIMER for system clock
ARM: OMAP2+: timer: remove CONFIG_OMAP_32K_TIMER
ARM: OMAP2+: Fix compiler warning for 32k timer
ARM: OMAP: Remove unnecessary inclusion of dmtimer.h
ARM: OMAP: Add platform data header for DMTIMERs
ARM: OMAP: Remove unnecessary omap_dm_timer structure declaration
ARM: OMAP2+: Remove unnecessary local variable in timer code
ARM: OMAP: Don't store timers physical address
ARM: OMAP: Define omap_dm_timer_prepare function as static
ARM: OMAP: Clean-up dmtimer reset code
ARM: OMAP: Remove __omap_dm_timer_set_source function
ARM: OMAP: Remove unnecessary call to clk_get()
ARM: OMAP: Add dmtimer interrupt disable function
ARM: OMAP: Fix spurious interrupts when using timer match feature
ARM: OMAP: Don't restore DMTIMER interrupt status register
ARM: OMAP: Don't restore of DMTIMER TISTAT register
ARM: OMAP: Fix dmtimer reset for timer1
ARM: OMAP2+: Don't use __omap_dm_timer_reset()
ARM: OMAP2/3: Define HWMOD software reset status for DMTIMERs
ARM: OMAP3: Correct HWMOD DMTIMER SYSC register declarations
...
Change/change conflict in arch/arm/mach-omap2/board-cm-t3517.c.
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/plat-omap/include')
-rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 143 |
1 files changed, 70 insertions, 73 deletions
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 3f5b9cfd9c0b..a3fbc48c332e 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h | |||
@@ -32,7 +32,6 @@ | |||
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> | 35 | #include <linux/delay.h> |
37 | #include <linux/io.h> | 36 | #include <linux/io.h> |
38 | #include <linux/platform_device.h> | 37 | #include <linux/platform_device.h> |
@@ -55,6 +54,10 @@ | |||
55 | #define OMAP_TIMER_TRIGGER_OVERFLOW 0x01 | 54 | #define OMAP_TIMER_TRIGGER_OVERFLOW 0x01 |
56 | #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 | 55 | #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 |
57 | 56 | ||
57 | /* posted mode types */ | ||
58 | #define OMAP_TIMER_NONPOSTED 0x00 | ||
59 | #define OMAP_TIMER_POSTED 0x01 | ||
60 | |||
58 | /* timer capabilities used in hwmod database */ | 61 | /* timer capabilities used in hwmod database */ |
59 | #define OMAP_TIMER_SECURE 0x80000000 | 62 | #define OMAP_TIMER_SECURE 0x80000000 |
60 | #define OMAP_TIMER_ALWON 0x40000000 | 63 | #define OMAP_TIMER_ALWON 0x40000000 |
@@ -62,16 +65,22 @@ | |||
62 | #define OMAP_TIMER_NEEDS_RESET 0x10000000 | 65 | #define OMAP_TIMER_NEEDS_RESET 0x10000000 |
63 | #define OMAP_TIMER_HAS_DSP_IRQ 0x08000000 | 66 | #define OMAP_TIMER_HAS_DSP_IRQ 0x08000000 |
64 | 67 | ||
68 | /* | ||
69 | * timer errata flags | ||
70 | * | ||
71 | * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This | ||
72 | * errata prevents us from using posted mode on these devices, unless the | ||
73 | * timer counter register is never read. For more details please refer to | ||
74 | * the OMAP3/4/5 errata documents. | ||
75 | */ | ||
76 | #define OMAP_TIMER_ERRATA_I103_I767 0x80000000 | ||
77 | |||
65 | struct omap_timer_capability_dev_attr { | 78 | struct omap_timer_capability_dev_attr { |
66 | u32 timer_capability; | 79 | u32 timer_capability; |
67 | }; | 80 | }; |
68 | 81 | ||
69 | struct omap_dm_timer; | ||
70 | |||
71 | struct timer_regs { | 82 | struct timer_regs { |
72 | u32 tidr; | 83 | u32 tidr; |
73 | u32 tistat; | ||
74 | u32 tisr; | ||
75 | u32 tier; | 84 | u32 tier; |
76 | u32 twer; | 85 | u32 twer; |
77 | u32 tclr; | 86 | u32 tclr; |
@@ -90,16 +99,35 @@ struct timer_regs { | |||
90 | u32 towr; | 99 | u32 towr; |
91 | }; | 100 | }; |
92 | 101 | ||
93 | struct dmtimer_platform_data { | 102 | struct omap_dm_timer { |
94 | /* set_timer_src - Only used for OMAP1 devices */ | 103 | int id; |
95 | int (*set_timer_src)(struct platform_device *pdev, int source); | 104 | int irq; |
96 | u32 timer_capability; | 105 | struct clk *fclk; |
106 | |||
107 | void __iomem *io_base; | ||
108 | void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */ | ||
109 | void __iomem *irq_ena; /* irq enable */ | ||
110 | void __iomem *irq_dis; /* irq disable, only on v2 ip */ | ||
111 | void __iomem *pend; /* write pending */ | ||
112 | void __iomem *func_base; /* function register base */ | ||
113 | |||
114 | unsigned long rate; | ||
115 | unsigned reserved:1; | ||
116 | unsigned posted:1; | ||
117 | struct timer_regs context; | ||
97 | int (*get_context_loss_count)(struct device *); | 118 | int (*get_context_loss_count)(struct device *); |
119 | int ctx_loss_count; | ||
120 | int revision; | ||
121 | u32 capability; | ||
122 | u32 errata; | ||
123 | struct platform_device *pdev; | ||
124 | struct list_head node; | ||
98 | }; | 125 | }; |
99 | 126 | ||
100 | int omap_dm_timer_reserve_systimer(int id); | 127 | int omap_dm_timer_reserve_systimer(int id); |
101 | struct omap_dm_timer *omap_dm_timer_request(void); | 128 | struct omap_dm_timer *omap_dm_timer_request(void); |
102 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); | 129 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); |
130 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap); | ||
103 | int omap_dm_timer_free(struct omap_dm_timer *timer); | 131 | int omap_dm_timer_free(struct omap_dm_timer *timer); |
104 | void omap_dm_timer_enable(struct omap_dm_timer *timer); | 132 | void omap_dm_timer_enable(struct omap_dm_timer *timer); |
105 | void omap_dm_timer_disable(struct omap_dm_timer *timer); | 133 | void omap_dm_timer_disable(struct omap_dm_timer *timer); |
@@ -121,6 +149,7 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, i | |||
121 | int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); | 149 | int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); |
122 | 150 | ||
123 | int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); | 151 | int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); |
152 | int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask); | ||
124 | 153 | ||
125 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); | 154 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); |
126 | int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); | 155 | int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); |
@@ -246,34 +275,6 @@ int omap_dm_timers_active(void); | |||
246 | #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ | 275 | #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ |
247 | (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) | 276 | (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) |
248 | 277 | ||
249 | struct omap_dm_timer { | ||
250 | unsigned long phys_base; | ||
251 | int id; | ||
252 | int irq; | ||
253 | struct clk *fclk; | ||
254 | |||
255 | void __iomem *io_base; | ||
256 | void __iomem *sys_stat; /* TISTAT timer status */ | ||
257 | void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */ | ||
258 | void __iomem *irq_ena; /* irq enable */ | ||
259 | void __iomem *irq_dis; /* irq disable, only on v2 ip */ | ||
260 | void __iomem *pend; /* write pending */ | ||
261 | void __iomem *func_base; /* function register base */ | ||
262 | |||
263 | unsigned long rate; | ||
264 | unsigned reserved:1; | ||
265 | unsigned posted:1; | ||
266 | struct timer_regs context; | ||
267 | int (*get_context_loss_count)(struct device *); | ||
268 | int ctx_loss_count; | ||
269 | int revision; | ||
270 | u32 capability; | ||
271 | struct platform_device *pdev; | ||
272 | struct list_head node; | ||
273 | }; | ||
274 | |||
275 | int omap_dm_timer_prepare(struct omap_dm_timer *timer); | ||
276 | |||
277 | static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, | 278 | static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, |
278 | int posted) | 279 | int posted) |
279 | { | 280 | { |
@@ -302,16 +303,13 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) | |||
302 | tidr = __raw_readl(timer->io_base); | 303 | tidr = __raw_readl(timer->io_base); |
303 | if (!(tidr >> 16)) { | 304 | if (!(tidr >> 16)) { |
304 | timer->revision = 1; | 305 | timer->revision = 1; |
305 | timer->sys_stat = timer->io_base + | ||
306 | OMAP_TIMER_V1_SYS_STAT_OFFSET; | ||
307 | timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; | 306 | timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; |
308 | timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; | 307 | timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; |
309 | timer->irq_dis = NULL; | 308 | timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; |
310 | timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; | 309 | timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; |
311 | timer->func_base = timer->io_base; | 310 | timer->func_base = timer->io_base; |
312 | } else { | 311 | } else { |
313 | timer->revision = 2; | 312 | timer->revision = 2; |
314 | timer->sys_stat = NULL; | ||
315 | timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS; | 313 | timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS; |
316 | timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET; | 314 | timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET; |
317 | timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR; | 315 | timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR; |
@@ -322,45 +320,44 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) | |||
322 | } | 320 | } |
323 | } | 321 | } |
324 | 322 | ||
325 | /* Assumes the source clock has been set by caller */ | 323 | /* |
326 | static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer, | 324 | * __omap_dm_timer_enable_posted - enables write posted mode |
327 | int autoidle, int wakeup) | 325 | * @timer: pointer to timer instance handle |
326 | * | ||
327 | * Enables the write posted mode for the timer. When posted mode is enabled | ||
328 | * writes to certain timer registers are immediately acknowledged by the | ||
329 | * internal bus and hence prevents stalling the CPU waiting for the write to | ||
330 | * complete. Enabling this feature can improve performance for writing to the | ||
331 | * timer registers. | ||
332 | */ | ||
333 | static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer) | ||
328 | { | 334 | { |
329 | u32 l; | 335 | if (timer->posted) |
336 | return; | ||
330 | 337 | ||
331 | l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); | 338 | if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) |
332 | l |= 0x02 << 3; /* Set to smart-idle mode */ | 339 | return; |
333 | l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ | ||
334 | 340 | ||
335 | if (autoidle) | ||
336 | l |= 0x1 << 0; | ||
337 | |||
338 | if (wakeup) | ||
339 | l |= 1 << 2; | ||
340 | |||
341 | __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); | ||
342 | |||
343 | /* Match hardware reset default of posted mode */ | ||
344 | __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, | 341 | __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, |
345 | OMAP_TIMER_CTRL_POSTED, 0); | 342 | OMAP_TIMER_CTRL_POSTED, 0); |
343 | timer->context.tsicr = OMAP_TIMER_CTRL_POSTED; | ||
344 | timer->posted = OMAP_TIMER_POSTED; | ||
346 | } | 345 | } |
347 | 346 | ||
348 | static inline int __omap_dm_timer_set_source(struct clk *timer_fck, | 347 | /** |
349 | struct clk *parent) | 348 | * __omap_dm_timer_override_errata - override errata flags for a timer |
349 | * @timer: pointer to timer handle | ||
350 | * @errata: errata flags to be ignored | ||
351 | * | ||
352 | * For a given timer, override a timer errata by clearing the flags | ||
353 | * specified by the errata argument. A specific erratum should only be | ||
354 | * overridden for a timer if the timer is used in such a way the erratum | ||
355 | * has no impact. | ||
356 | */ | ||
357 | static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer, | ||
358 | u32 errata) | ||
350 | { | 359 | { |
351 | int ret; | 360 | timer->errata &= ~errata; |
352 | |||
353 | clk_disable(timer_fck); | ||
354 | ret = clk_set_parent(timer_fck, parent); | ||
355 | clk_enable(timer_fck); | ||
356 | |||
357 | /* | ||
358 | * When the functional clock disappears, too quick writes seem | ||
359 | * to cause an abort. XXX Is this still necessary? | ||
360 | */ | ||
361 | __delay(300000); | ||
362 | |||
363 | return ret; | ||
364 | } | 361 | } |
365 | 362 | ||
366 | static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, | 363 | static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, |