Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-omap2 / timer.c
index 684d2fc3d4858a47c758efd83b3f2b253254d9ab..7016637b531c2daf7269fcdf1c4662ce741ade7a 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dmtimer-omap.h>
 
 #include <asm/mach/time.h>
 #include <asm/smp_twd.h>
 #define OMAP3_32K_SOURCE       "omap_32k_fck"
 #define OMAP4_32K_SOURCE       "sys_32k_ck"
 
-#ifdef CONFIG_OMAP_32K_TIMER
-#define OMAP2_CLKEV_SOURCE     OMAP2_32K_SOURCE
-#define OMAP3_CLKEV_SOURCE     OMAP3_32K_SOURCE
-#define OMAP4_CLKEV_SOURCE     OMAP4_32K_SOURCE
-#define OMAP3_SECURE_TIMER     12
-#define TIMER_PROP_SECURE      "ti,timer-secure"
-#else
-#define OMAP2_CLKEV_SOURCE     OMAP2_MPU_SOURCE
-#define OMAP3_CLKEV_SOURCE     OMAP3_MPU_SOURCE
-#define OMAP4_CLKEV_SOURCE     OMAP4_MPU_SOURCE
-#define OMAP3_SECURE_TIMER     1
-#define TIMER_PROP_SECURE      "ti,timer-alwon"
-#endif
-
 #define REALTIME_COUNTER_BASE                          0x48243200
 #define INCREMENTER_NUMERATOR_OFFSET                   0x10
 #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET          0x14
@@ -108,7 +96,7 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles,
                                         struct clock_event_device *evt)
 {
        __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
-                                               0xffffffff - cycles, 1);
+                                  0xffffffff - cycles, OMAP_TIMER_POSTED);
 
        return 0;
 }
@@ -118,7 +106,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 {
        u32 period;
 
-       __omap_dm_timer_stop(&clkev, 1, clkev.rate);
+       __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
 
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
@@ -126,10 +114,10 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
                period -= 1;
                /* Looks like we need to first set the load value separately */
                __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
-                                       0xffffffff - period, 1);
+                                     0xffffffff - period, OMAP_TIMER_POSTED);
                __omap_dm_timer_load_start(&clkev,
                                        OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
-                                               0xffffffff - period, 1);
+                                       0xffffffff - period, OMAP_TIMER_POSTED);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                break;
@@ -160,11 +148,6 @@ static struct of_device_id omap_timer_match[] __initdata = {
        { }
 };
 
-static struct of_device_id omap_counter_match[] __initdata = {
-       { .compatible = "ti,omap-counter32k", },
-       { }
-};
-
 /**
  * omap_get_timer_dt - get a timer using device-tree
  * @match      - device-tree match structure for matching a device type
@@ -222,19 +205,31 @@ void __init omap_dmtimer_init(void)
        }
 }
 
+/**
+ * omap_dm_timer_get_errata - get errata flags for a timer
+ *
+ * Get the timer errata flags that are specific to the OMAP device being used.
+ */
+u32 __init omap_dm_timer_get_errata(void)
+{
+       if (cpu_is_omap24xx())
+               return 0;
+
+       return OMAP_TIMER_ERRATA_I103_I767;
+}
+
 static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
                                                int gptimer_id,
                                                const char *fck_source,
-                                               const char *property)
+                                               const char *property,
+                                               int posted)
 {
        char name[10]; /* 10 = sizeof("gptXX_Xck0") */
        const char *oh_name;
        struct device_node *np;
        struct omap_hwmod *oh;
-       struct resource irq_rsrc, mem_rsrc;
-       size_t size;
-       int res = 0;
-       int r;
+       struct resource irq, mem;
+       int r = 0;
 
        if (of_have_populated_dt()) {
                np = omap_get_timer_dt(omap_timer_match, NULL);
@@ -260,28 +255,24 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
                oh_name = name;
        }
 
-       omap_hwmod_setup_one(oh_name);
        oh = omap_hwmod_lookup(oh_name);
-
        if (!oh)
                return -ENODEV;
 
        if (!of_have_populated_dt()) {
                r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL,
-                                                  &irq_rsrc);
+                                                  &irq);
                if (r)
                        return -ENXIO;
-               timer->irq = irq_rsrc.start;
+               timer->irq = irq.start;
 
                r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL,
-                                                  &mem_rsrc);
+                                                  &mem);
                if (r)
                        return -ENXIO;
-               timer->phys_base = mem_rsrc.start;
-               size = mem_rsrc.end - mem_rsrc.start;
 
                /* Static mapping, never released */
-               timer->io_base = ioremap(timer->phys_base, size);
+               timer->io_base = ioremap(mem.start, mem.end - mem.start);
        }
 
        if (!timer->io_base)
@@ -292,32 +283,37 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
        if (IS_ERR(timer->fclk))
                return -ENODEV;
 
-       omap_hwmod_enable(oh);
-
        /* FIXME: Need to remove hard-coded test on timer ID */
        if (gptimer_id != 12) {
                struct clk *src;
 
                src = clk_get(NULL, fck_source);
                if (IS_ERR(src)) {
-                       res = -EINVAL;
+                       r = -EINVAL;
                } else {
-                       res = __omap_dm_timer_set_source(timer->fclk, src);
-                       if (IS_ERR_VALUE(res))
+                       r = clk_set_parent(timer->fclk, src);
+                       if (IS_ERR_VALUE(r))
                                pr_warn("%s: %s cannot set source\n",
                                        __func__, oh->name);
                        clk_put(src);
                }
        }
+
+       omap_hwmod_setup_one(oh_name);
+       omap_hwmod_enable(oh);
        __omap_dm_timer_init_regs(timer);
-       __omap_dm_timer_reset(timer, 1, 1);
-       timer->posted = 1;
 
-       timer->rate = clk_get_rate(timer->fclk);
+       if (posted)
+               __omap_dm_timer_enable_posted(timer);
+
+       /* Check that the intended posted configuration matches the actual */
+       if (posted != timer->posted)
+               return -EINVAL;
 
+       timer->rate = clk_get_rate(timer->fclk);
        timer->reserved = 1;
 
-       return res;
+       return r;
 }
 
 static void __init omap2_gp_clockevent_init(int gptimer_id,
@@ -326,7 +322,17 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
 {
        int res;
 
-       res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property);
+       clkev.errata = omap_dm_timer_get_errata();
+
+       /*
+        * For clock-event timers we never read the timer counter and
+        * so we are not impacted by errata i103 and i767. Therefore,
+        * we can safely ignore this errata for clock-event timers.
+        */
+       __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);
+
+       res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property,
+                                    OMAP_TIMER_POSTED);
        BUG_ON(res);
 
        omap2_gp_timer_irq.dev_id = &clkev;
@@ -359,7 +365,8 @@ static bool use_gptimer_clksrc;
  */
 static cycle_t clocksource_read_cycles(struct clocksource *cs)
 {
-       return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
+       return (cycle_t)__omap_dm_timer_read_counter(&clksrc,
+                                                    OMAP_TIMER_NONPOSTED);
 }
 
 static struct clocksource clocksource_gpt = {
@@ -373,12 +380,17 @@ static struct clocksource clocksource_gpt = {
 static u32 notrace dmtimer_read_sched_clock(void)
 {
        if (clksrc.reserved)
-               return __omap_dm_timer_read_counter(&clksrc, 1);
+               return __omap_dm_timer_read_counter(&clksrc,
+                                                   OMAP_TIMER_NONPOSTED);
 
        return 0;
 }
 
-#ifdef CONFIG_OMAP_32K_TIMER
+static struct of_device_id omap_counter_match[] __initdata = {
+       { .compatible = "ti,omap-counter32k", },
+       { }
+};
+
 /* Setup free-running counter for clocksource */
 static int __init omap2_sync32k_clocksource_init(void)
 {
@@ -439,23 +451,21 @@ static int __init omap2_sync32k_clocksource_init(void)
 
        return ret;
 }
-#else
-static inline int omap2_sync32k_clocksource_init(void)
-{
-       return -ENODEV;
-}
-#endif
 
 static void __init omap2_gptimer_clocksource_init(int gptimer_id,
                                                const char *fck_source)
 {
        int res;
 
-       res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL);
+       clksrc.errata = omap_dm_timer_get_errata();
+
+       res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL,
+                                    OMAP_TIMER_NONPOSTED);
        BUG_ON(res);
 
        __omap_dm_timer_load_start(&clksrc,
-                       OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+                                  OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0,
+                                  OMAP_TIMER_NONPOSTED);
        setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
 
        if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
@@ -466,25 +476,6 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
                        gptimer_id, clksrc.rate);
 }
 
-static void __init omap2_clocksource_init(int gptimer_id,
-                                               const char *fck_source)
-{
-       /*
-        * First give preference to kernel parameter configuration
-        * by user (clocksource="gp_timer").
-        *
-        * In case of missing kernel parameter for clocksource,
-        * first check for availability for 32k-sync timer, in case
-        * of failure in finding 32k_counter module or registering
-        * it as clocksource, execution will fallback to gp-timer.
-        */
-       if (use_gptimer_clksrc == true)
-               omap2_gptimer_clocksource_init(gptimer_id, fck_source);
-       else if (omap2_sync32k_clocksource_init())
-               /* Fall back to gp-timer code */
-               omap2_gptimer_clocksource_init(gptimer_id, fck_source);
-}
-
 #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
 /*
  * The realtime counter also called master counter, is a free-running
@@ -563,52 +554,65 @@ static inline void __init realtime_counter_init(void)
 {}
 #endif
 
-#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop,     \
+#define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop,  \
+                              clksrc_nr, clksrc_src)                   \
+static void __init omap##name##_gptimer_timer_init(void)               \
+{                                                                      \
+       omap_dmtimer_init();                                            \
+       omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);    \
+       omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src);        \
+}
+
+#define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \
                                clksrc_nr, clksrc_src)                  \
-static void __init omap##name##_timer_init(void)                       \
+static void __init omap##name##_sync32k_timer_init(void)               \
 {                                                                      \
        omap_dmtimer_init();                                            \
        omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);    \
-       omap2_clocksource_init((clksrc_nr), clksrc_src);                \
+       /* Enable the use of clocksource="gp_timer" kernel parameter */ \
+       if (use_gptimer_clksrc)                                         \
+               omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src);\
+       else                                                            \
+               omap2_sync32k_clocksource_init();                       \
 }
 
-#define OMAP_SYS_TIMER(name)                                           \
+#define OMAP_SYS_TIMER(name, clksrc)                                   \
 struct sys_timer omap##name##_timer = {                                        \
-       .init   = omap##name##_timer_init,                              \
+       .init   = omap##name##_##clksrc##_timer_init,                   \
 };
 
 #ifdef CONFIG_ARCH_OMAP2
-OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, "ti,timer-alwon",
-                   2, OMAP2_MPU_SOURCE)
-OMAP_SYS_TIMER(2)
-#endif
+OMAP_SYS_32K_TIMER_INIT(2, 1, OMAP2_32K_SOURCE, "ti,timer-alwon",
+                       2, OMAP2_MPU_SOURCE);
+OMAP_SYS_TIMER(2, sync32k);
+#endif /* CONFIG_ARCH_OMAP2 */
 
 #ifdef CONFIG_ARCH_OMAP3
-OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, "ti,timer-alwon",
-                   2, OMAP3_MPU_SOURCE)
-OMAP_SYS_TIMER(3)
-OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE,
-                       TIMER_PROP_SECURE, 2, OMAP3_MPU_SOURCE)
-OMAP_SYS_TIMER(3_secure)
-#endif
+OMAP_SYS_32K_TIMER_INIT(3, 1, OMAP3_32K_SOURCE, "ti,timer-alwon",
+                       2, OMAP3_MPU_SOURCE);
+OMAP_SYS_TIMER(3, sync32k);
+OMAP_SYS_32K_TIMER_INIT(3_secure, 12, OMAP3_32K_SOURCE, "ti,timer-secure",
+                       2, OMAP3_MPU_SOURCE);
+OMAP_SYS_TIMER(3_secure, sync32k);
+OMAP_SYS_GP_TIMER_INIT(3_gp, 1, OMAP3_MPU_SOURCE, "ti,timer-alwon",
+                      2, OMAP3_MPU_SOURCE);
+OMAP_SYS_TIMER(3_gp, gptimer);
+#endif /* CONFIG_ARCH_OMAP3 */
 
 #ifdef CONFIG_SOC_AM33XX
-OMAP_SYS_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
-                   2, OMAP4_MPU_SOURCE)
-OMAP_SYS_TIMER(3_am33xx)
-#endif
+OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
+                      2, OMAP4_MPU_SOURCE);
+OMAP_SYS_TIMER(3_am33xx, gptimer);
+#endif /* CONFIG_SOC_AM33XX */
 
 #ifdef CONFIG_ARCH_OMAP4
+OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
+                       2, OMAP4_MPU_SOURCE);
 #ifdef CONFIG_LOCAL_TIMERS
-static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
-                             OMAP44XX_LOCAL_TWD_BASE, 29);
-#endif
-
-static void __init omap4_timer_init(void)
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
+static void __init omap4_local_timer_init(void)
 {
-       omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE, "ti,timer-alwon");
-       omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
-#ifdef CONFIG_LOCAL_TIMERS
+       omap4_sync32k_timer_init();
        /* Local timers are not supprted on OMAP4430 ES1.0 */
        if (omap_rev() != OMAP4430_REV_ES1_0) {
                int err;
@@ -622,26 +626,32 @@ static void __init omap4_timer_init(void)
                if (err)
                        pr_err("twd_local_timer_register failed %d\n", err);
        }
-#endif
 }
-OMAP_SYS_TIMER(4)
-#endif
+#else /* CONFIG_LOCAL_TIMERS */
+static void __init omap4_local_timer_init(void)
+{
+       omap4_sync32k_timer_init();
+}
+#endif /* CONFIG_LOCAL_TIMERS */
+OMAP_SYS_TIMER(4, local);
+#endif /* CONFIG_ARCH_OMAP4 */
 
 #ifdef CONFIG_SOC_OMAP5
-static void __init omap5_timer_init(void)
+OMAP_SYS_32K_TIMER_INIT(5, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
+                       2, OMAP4_MPU_SOURCE);
+static void __init omap5_realtime_timer_init(void)
 {
        int err;
 
-       omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE, "ti,timer-alwon");
-       omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
+       omap5_sync32k_timer_init();
        realtime_counter_init();
 
        err = arch_timer_of_register();
        if (err)
                pr_err("%s: arch_timer_register failed %d\n", __func__, err);
 }
-OMAP_SYS_TIMER(5)
-#endif
+OMAP_SYS_TIMER(5, realtime);
+#endif /* CONFIG_SOC_OMAP5 */
 
 /**
  * omap_timer_init - build and register timer device with an
@@ -693,6 +703,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
        if (timer_dev_attr)
                pdata->timer_capability = timer_dev_attr->timer_capability;
 
+       pdata->timer_errata = omap_dm_timer_get_errata();
        pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
 
        pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata),