ARM: OMAP3+: Implement timer workaround for errata i103 and i767
[pandora-kernel.git] / arch / arm / plat-omap / include / plat / dmtimer.h
index b27d92a..47d506f 100644 (file)
 #define OMAP_TIMER_ALWON                               0x40000000
 #define OMAP_TIMER_HAS_PWM                             0x20000000
 
+/*
+ * timer errata flags
+ *
+ * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This
+ * errata prevents us from using posted mode on these devices, unless the
+ * timer counter register is never read. For more details please refer to
+ * the OMAP3/4/5 errata documents.
+ */
+#define OMAP_TIMER_ERRATA_I103_I767                    0x80000000
+
 struct omap_timer_capability_dev_attr {
        u32 timer_capability;
 };
@@ -104,6 +114,7 @@ struct dmtimer_platform_data {
        bool reserved;
 
        bool loses_context;
+       u32 timer_errata;
 
        int (*get_context_loss_count)(struct device *dev);
 };
@@ -277,6 +288,7 @@ struct omap_dm_timer {
        bool loses_context;
        int ctx_loss_count;
        int revision;
+       u32 errata;
        struct platform_device *pdev;
        struct list_head node;
 
@@ -350,10 +362,46 @@ static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
                l |= 1 << 2;
 
        __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
+}
+
+/*
+ * __omap_dm_timer_enable_posted - enables write posted mode
+ * @timer:      pointer to timer instance handle
+ *
+ * Enables the write posted mode for the timer. When posted mode is enabled
+ * writes to certain timer registers are immediately acknowledged by the
+ * internal bus and hence prevents stalling the CPU waiting for the write to
+ * complete. Enabling this feature can improve performance for writing to the
+ * timer registers.
+ */
+static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
+{
+       if (timer->posted)
+               return;
+
+       if (timer->errata & OMAP_TIMER_ERRATA_I103_I767)
+               return;
 
-       /* Match hardware reset default of posted mode */
        __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
-                                       OMAP_TIMER_CTRL_POSTED, 0);
+                             OMAP_TIMER_CTRL_POSTED, 0);
+       timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
+       timer->posted = OMAP_TIMER_POSTED;
+}
+
+/**
+ * __omap_dm_timer_override_errata - override errata flags for a timer
+ * @timer:      pointer to timer handle
+ * @errata:    errata flags to be ignored
+ *
+ * For a given timer, override a timer errata by clearing the flags
+ * specified by the errata argument. A specific erratum should only be
+ * overridden for a timer if the timer is used in such a way the erratum
+ * has no impact.
+ */
+static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer,
+                                                  u32 errata)
+{
+       timer->errata &= ~errata;
 }
 
 static inline int __omap_dm_timer_set_source(struct clk *timer_fck,