aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-11-30 01:30:11 -0500
committerOlof Johansson <olof@lixom.net>2012-11-30 01:30:11 -0500
commitc8a1ceccf394b2f99feed2b702732140e9f0f92d (patch)
tree6632d05aae22e99d7f128104b536bfdfc225a696 /arch/arm/plat-omap
parent4c929c8a8837f4e5acdec5883a1b64a240751e2f (diff)
parent26f01998b0657a61167a819f1c37cb9f9e9d674b (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')
-rw-r--r--arch/arm/plat-omap/Kconfig6
-rw-r--r--arch/arm/plat-omap/dmtimer.c218
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h143
3 files changed, 240 insertions, 127 deletions
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 82fcb206b5b2..665870dce3c8 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -154,6 +154,12 @@ config OMAP_32K_TIMER
154 intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is 154 intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
155 currently only available for OMAP16XX, 24XX, 34XX and OMAP4/5. 155 currently only available for OMAP16XX, 24XX, 34XX and OMAP4/5.
156 156
157 On OMAP2PLUS this value is only used for CONFIG_HZ and
158 CLOCK_TICK_RATE compile time calculation.
159 The actual timer selection is done in the board file
160 through the (DT_)MACHINE_START structure.
161
162
157config OMAP3_L2_AUX_SECURE_SAVE_RESTORE 163config OMAP3_L2_AUX_SECURE_SAVE_RESTORE
158 bool "OMAP3 HS/EMU save and restore for L2 AUX control register" 164 bool "OMAP3 HS/EMU save and restore for L2 AUX control register"
159 depends on ARCH_OMAP3 && PM 165 depends on ARCH_OMAP3 && PM
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 82231a75abd6..89585c293554 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -35,11 +35,16 @@
35 * 675 Mass Ave, Cambridge, MA 02139, USA. 35 * 675 Mass Ave, Cambridge, MA 02139, USA.
36 */ 36 */
37 37
38#include <linux/clk.h>
38#include <linux/module.h> 39#include <linux/module.h>
39#include <linux/io.h> 40#include <linux/io.h>
40#include <linux/device.h> 41#include <linux/device.h>
41#include <linux/err.h> 42#include <linux/err.h>
42#include <linux/pm_runtime.h> 43#include <linux/pm_runtime.h>
44#include <linux/of.h>
45#include <linux/of_device.h>
46#include <linux/platform_device.h>
47#include <linux/platform_data/dmtimer-omap.h>
43 48
44#include <plat/dmtimer.h> 49#include <plat/dmtimer.h>
45 50
@@ -81,10 +86,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
81 86
82static void omap_timer_restore_context(struct omap_dm_timer *timer) 87static void omap_timer_restore_context(struct omap_dm_timer *timer)
83{ 88{
84 if (timer->revision == 1)
85 __raw_writel(timer->context.tistat, timer->sys_stat);
86
87 __raw_writel(timer->context.tisr, timer->irq_stat);
88 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, 89 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
89 timer->context.twer); 90 timer->context.twer);
90 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 91 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -100,39 +101,38 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
100 timer->context.tclr); 101 timer->context.tclr);
101} 102}
102 103
103static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) 104static int omap_dm_timer_reset(struct omap_dm_timer *timer)
104{ 105{
105 int c; 106 u32 l, timeout = 100000;
106 107
107 if (!timer->sys_stat) 108 if (timer->revision != 1)
108 return; 109 return -EINVAL;
109 110
110 c = 0; 111 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
111 while (!(__raw_readl(timer->sys_stat) & 1)) {
112 c++;
113 if (c > 100000) {
114 printk(KERN_ERR "Timer failed to reset\n");
115 return;
116 }
117 }
118}
119 112
120static void omap_dm_timer_reset(struct omap_dm_timer *timer) 113 do {
121{ 114 l = __omap_dm_timer_read(timer,
122 omap_dm_timer_enable(timer); 115 OMAP_TIMER_V1_SYS_STAT_OFFSET, 0);
123 if (timer->pdev->id != 1) { 116 } while (!l && timeout--);
124 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); 117
125 omap_dm_timer_wait_for_reset(timer); 118 if (!timeout) {
119 dev_err(&timer->pdev->dev, "Timer failed to reset\n");
120 return -ETIMEDOUT;
126 } 121 }
127 122
128 __omap_dm_timer_reset(timer, 0, 0); 123 /* Configure timer for smart-idle mode */
129 omap_dm_timer_disable(timer); 124 l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
130 timer->posted = 1; 125 l |= 0x2 << 0x3;
126 __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l, 0);
127
128 timer->posted = 0;
129
130 return 0;
131} 131}
132 132
133int omap_dm_timer_prepare(struct omap_dm_timer *timer) 133static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
134{ 134{
135 int ret; 135 int rc;
136 136
137 /* 137 /*
138 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so 138 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
@@ -147,13 +147,20 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
147 } 147 }
148 } 148 }
149 149
150 if (timer->capability & OMAP_TIMER_NEEDS_RESET) 150 omap_dm_timer_enable(timer);
151 omap_dm_timer_reset(timer); 151
152 if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
153 rc = omap_dm_timer_reset(timer);
154 if (rc) {
155 omap_dm_timer_disable(timer);
156 return rc;
157 }
158 }
152 159
153 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); 160 __omap_dm_timer_enable_posted(timer);
161 omap_dm_timer_disable(timer);
154 162
155 timer->posted = 1; 163 return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
156 return ret;
157} 164}
158 165
159static inline u32 omap_dm_timer_reserved_systimer(int id) 166static inline u32 omap_dm_timer_reserved_systimer(int id)
@@ -209,6 +216,13 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
209 unsigned long flags; 216 unsigned long flags;
210 int ret = 0; 217 int ret = 0;
211 218
219 /* Requesting timer by ID is not supported when device tree is used */
220 if (of_have_populated_dt()) {
221 pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n",
222 __func__);
223 return NULL;
224 }
225
212 spin_lock_irqsave(&dm_timer_lock, flags); 226 spin_lock_irqsave(&dm_timer_lock, flags);
213 list_for_each_entry(t, &omap_timer_list, node) { 227 list_for_each_entry(t, &omap_timer_list, node) {
214 if (t->pdev->id == id && !t->reserved) { 228 if (t->pdev->id == id && !t->reserved) {
@@ -234,6 +248,58 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
234} 248}
235EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); 249EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
236 250
251/**
252 * omap_dm_timer_request_by_cap - Request a timer by capability
253 * @cap: Bit mask of capabilities to match
254 *
255 * Find a timer based upon capabilities bit mask. Callers of this function
256 * should use the definitions found in the plat/dmtimer.h file under the
257 * comment "timer capabilities used in hwmod database". Returns pointer to
258 * timer handle on success and a NULL pointer on failure.
259 */
260struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
261{
262 struct omap_dm_timer *timer = NULL, *t;
263 unsigned long flags;
264
265 if (!cap)
266 return NULL;
267
268 spin_lock_irqsave(&dm_timer_lock, flags);
269 list_for_each_entry(t, &omap_timer_list, node) {
270 if ((!t->reserved) && ((t->capability & cap) == cap)) {
271 /*
272 * If timer is not NULL, we have already found one timer
273 * but it was not an exact match because it had more
274 * capabilites that what was required. Therefore,
275 * unreserve the last timer found and see if this one
276 * is a better match.
277 */
278 if (timer)
279 timer->reserved = 0;
280
281 timer = t;
282 timer->reserved = 1;
283
284 /* Exit loop early if we find an exact match */
285 if (t->capability == cap)
286 break;
287 }
288 }
289 spin_unlock_irqrestore(&dm_timer_lock, flags);
290
291 if (timer && omap_dm_timer_prepare(timer)) {
292 timer->reserved = 0;
293 timer = NULL;
294 }
295
296 if (!timer)
297 pr_debug("%s: timer request failed!\n", __func__);
298
299 return timer;
300}
301EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
302
237int omap_dm_timer_free(struct omap_dm_timer *timer) 303int omap_dm_timer_free(struct omap_dm_timer *timer)
238{ 304{
239 if (unlikely(!timer)) 305 if (unlikely(!timer))
@@ -388,7 +454,6 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)
388 */ 454 */
389 timer->context.tclr = 455 timer->context.tclr =
390 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 456 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
391 timer->context.tisr = __raw_readl(timer->irq_stat);
392 omap_dm_timer_disable(timer); 457 omap_dm_timer_disable(timer);
393 return 0; 458 return 0;
394} 459}
@@ -398,7 +463,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
398{ 463{
399 int ret; 464 int ret;
400 char *parent_name = NULL; 465 char *parent_name = NULL;
401 struct clk *fclk, *parent; 466 struct clk *parent;
402 struct dmtimer_platform_data *pdata; 467 struct dmtimer_platform_data *pdata;
403 468
404 if (unlikely(!timer)) 469 if (unlikely(!timer))
@@ -414,14 +479,11 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
414 * use the clock framework to set the parent clock. To be removed 479 * use the clock framework to set the parent clock. To be removed
415 * once OMAP1 migrated to using clock framework for dmtimers 480 * once OMAP1 migrated to using clock framework for dmtimers
416 */ 481 */
417 if (pdata->set_timer_src) 482 if (pdata && pdata->set_timer_src)
418 return pdata->set_timer_src(timer->pdev, source); 483 return pdata->set_timer_src(timer->pdev, source);
419 484
420 fclk = clk_get(&timer->pdev->dev, "fck"); 485 if (!timer->fclk)
421 if (IS_ERR_OR_NULL(fclk)) {
422 pr_err("%s: fck not found\n", __func__);
423 return -EINVAL; 486 return -EINVAL;
424 }
425 487
426 switch (source) { 488 switch (source) {
427 case OMAP_TIMER_SRC_SYS_CLK: 489 case OMAP_TIMER_SRC_SYS_CLK:
@@ -440,18 +502,15 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
440 parent = clk_get(&timer->pdev->dev, parent_name); 502 parent = clk_get(&timer->pdev->dev, parent_name);
441 if (IS_ERR_OR_NULL(parent)) { 503 if (IS_ERR_OR_NULL(parent)) {
442 pr_err("%s: %s not found\n", __func__, parent_name); 504 pr_err("%s: %s not found\n", __func__, parent_name);
443 ret = -EINVAL; 505 return -EINVAL;
444 goto out;
445 } 506 }
446 507
447 ret = clk_set_parent(fclk, parent); 508 ret = clk_set_parent(timer->fclk, parent);
448 if (IS_ERR_VALUE(ret)) 509 if (IS_ERR_VALUE(ret))
449 pr_err("%s: failed to set %s as parent\n", __func__, 510 pr_err("%s: failed to set %s as parent\n", __func__,
450 parent_name); 511 parent_name);
451 512
452 clk_put(parent); 513 clk_put(parent);
453out:
454 clk_put(fclk);
455 514
456 return ret; 515 return ret;
457} 516}
@@ -534,8 +593,8 @@ int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
534 l |= OMAP_TIMER_CTRL_CE; 593 l |= OMAP_TIMER_CTRL_CE;
535 else 594 else
536 l &= ~OMAP_TIMER_CTRL_CE; 595 l &= ~OMAP_TIMER_CTRL_CE;
537 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
538 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); 596 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
597 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
539 598
540 /* Save the context */ 599 /* Save the context */
541 timer->context.tclr = l; 600 timer->context.tclr = l;
@@ -611,6 +670,37 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
611} 670}
612EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); 671EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
613 672
673/**
674 * omap_dm_timer_set_int_disable - disable timer interrupts
675 * @timer: pointer to timer handle
676 * @mask: bit mask of interrupts to be disabled
677 *
678 * Disables the specified timer interrupts for a timer.
679 */
680int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
681{
682 u32 l = mask;
683
684 if (unlikely(!timer))
685 return -EINVAL;
686
687 omap_dm_timer_enable(timer);
688
689 if (timer->revision == 1)
690 l = __raw_readl(timer->irq_ena) & ~mask;
691
692 __raw_writel(l, timer->irq_dis);
693 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
694 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
695
696 /* Save the context */
697 timer->context.tier &= ~mask;
698 timer->context.twer &= ~mask;
699 omap_dm_timer_disable(timer);
700 return 0;
701}
702EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);
703
614unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) 704unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
615{ 705{
616 unsigned int l; 706 unsigned int l;
@@ -632,8 +722,7 @@ int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
632 return -EINVAL; 722 return -EINVAL;
633 723
634 __omap_dm_timer_write_status(timer, value); 724 __omap_dm_timer_write_status(timer, value);
635 /* Save the context */ 725
636 timer->context.tisr = value;
637 return 0; 726 return 0;
638} 727}
639EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); 728EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
@@ -696,7 +785,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
696 struct device *dev = &pdev->dev; 785 struct device *dev = &pdev->dev;
697 struct dmtimer_platform_data *pdata = pdev->dev.platform_data; 786 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
698 787
699 if (!pdata) { 788 if (!pdata && !dev->of_node) {
700 dev_err(dev, "%s: no platform data.\n", __func__); 789 dev_err(dev, "%s: no platform data.\n", __func__);
701 return -ENODEV; 790 return -ENODEV;
702 } 791 }
@@ -725,12 +814,25 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
725 return -ENOMEM; 814 return -ENOMEM;
726 } 815 }
727 816
728 timer->id = pdev->id; 817 if (dev->of_node) {
818 if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
819 timer->capability |= OMAP_TIMER_ALWON;
820 if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
821 timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
822 if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
823 timer->capability |= OMAP_TIMER_HAS_PWM;
824 if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
825 timer->capability |= OMAP_TIMER_SECURE;
826 } else {
827 timer->id = pdev->id;
828 timer->errata = pdata->timer_errata;
829 timer->capability = pdata->timer_capability;
830 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
831 timer->get_context_loss_count = pdata->get_context_loss_count;
832 }
833
729 timer->irq = irq->start; 834 timer->irq = irq->start;
730 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
731 timer->pdev = pdev; 835 timer->pdev = pdev;
732 timer->capability = pdata->timer_capability;
733 timer->get_context_loss_count = pdata->get_context_loss_count;
734 836
735 /* Skip pm_runtime_enable for OMAP1 */ 837 /* Skip pm_runtime_enable for OMAP1 */
736 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { 838 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
@@ -770,7 +872,8 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
770 872
771 spin_lock_irqsave(&dm_timer_lock, flags); 873 spin_lock_irqsave(&dm_timer_lock, flags);
772 list_for_each_entry(timer, &omap_timer_list, node) 874 list_for_each_entry(timer, &omap_timer_list, node)
773 if (timer->pdev->id == pdev->id) { 875 if (!strcmp(dev_name(&timer->pdev->dev),
876 dev_name(&pdev->dev))) {
774 list_del(&timer->node); 877 list_del(&timer->node);
775 ret = 0; 878 ret = 0;
776 break; 879 break;
@@ -780,11 +883,18 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
780 return ret; 883 return ret;
781} 884}
782 885
886static const struct of_device_id omap_timer_match[] = {
887 { .compatible = "ti,omap2-timer", },
888 {},
889};
890MODULE_DEVICE_TABLE(of, omap_timer_match);
891
783static struct platform_driver omap_dm_timer_driver = { 892static struct platform_driver omap_dm_timer_driver = {
784 .probe = omap_dm_timer_probe, 893 .probe = omap_dm_timer_probe,
785 .remove = __devexit_p(omap_dm_timer_remove), 894 .remove = __devexit_p(omap_dm_timer_remove),
786 .driver = { 895 .driver = {
787 .name = "omap_timer", 896 .name = "omap_timer",
897 .of_match_table = of_match_ptr(omap_timer_match),
788 }, 898 },
789}; 899};
790 900
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
65struct omap_timer_capability_dev_attr { 78struct omap_timer_capability_dev_attr {
66 u32 timer_capability; 79 u32 timer_capability;
67}; 80};
68 81
69struct omap_dm_timer;
70
71struct timer_regs { 82struct 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
93struct dmtimer_platform_data { 102struct 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
100int omap_dm_timer_reserve_systimer(int id); 127int omap_dm_timer_reserve_systimer(int id);
101struct omap_dm_timer *omap_dm_timer_request(void); 128struct omap_dm_timer *omap_dm_timer_request(void);
102struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); 129struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
130struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap);
103int omap_dm_timer_free(struct omap_dm_timer *timer); 131int omap_dm_timer_free(struct omap_dm_timer *timer);
104void omap_dm_timer_enable(struct omap_dm_timer *timer); 132void omap_dm_timer_enable(struct omap_dm_timer *timer);
105void omap_dm_timer_disable(struct omap_dm_timer *timer); 133void 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
121int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); 149int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
122 150
123int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); 151int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
152int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask);
124 153
125unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); 154unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
126int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); 155int 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
249struct 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
275int omap_dm_timer_prepare(struct omap_dm_timer *timer);
276
277static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, 278static 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/*
326static 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 */
333static 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
348static 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 */
357static 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
366static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, 363static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,