]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/blobdiff - arch/arm/mach-omap2/timer.c
Merge branch 'platform-ti-linux-3.14.y' into pm-ti-linux-3.14.y
[android-sdk/kernel-video.git] / arch / arm / mach-omap2 / timer.c
index 64b16e5834b8e2cab9e76085200afab22e67160b..1ee3cb6482ddc0f4aa966a502c3ef8801b7cd1a0 100644 (file)
@@ -54,6 +54,7 @@
 
 #include "soc.h"
 #include "common.h"
+#include "control.h"
 #include "powerdomain.h"
 #include "pm.h"
 #include "omap-secure.h"
@@ -236,8 +237,8 @@ static struct device_node * __init omap_get_timer_dt(struct of_device_id *match,
 /**
  * omap_dmtimer_init - initialisation function when device tree is used
  *
- * For secure OMAP3 devices, timers with device type "timer-secure" cannot
- * be used by the kernel as they are reserved. Therefore, to prevent the
+ * For secure OMAP3/DRA7xx devices, timers with device type "timer-secure"
+ * cannot be used by the kernel as they are reserved. Therefore, to prevent the
  * kernel registering these devices remove them dynamically from the device
  * tree on boot.
  */
@@ -245,7 +246,7 @@ static void __init omap_dmtimer_init(void)
 {
        struct device_node *np;
 
-       if (!cpu_is_omap34xx())
+       if (!cpu_is_omap34xx() && !soc_is_dra7xx())
                return;
 
        /* If we are a secure device, remove any secure timer nodes */
@@ -587,7 +588,8 @@ static void __init realtime_counter_init(void)
        void __iomem *base;
        static struct clk *sys_clk;
        unsigned long rate;
-       unsigned int reg, num, den;
+       unsigned int reg;
+       unsigned long long num, den;
 
        base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
        if (!base) {
@@ -602,13 +604,42 @@ static void __init realtime_counter_init(void)
        }
 
        rate = clk_get_rate(sys_clk);
+
+       if (soc_is_dra7xx()) {
+               /*
+                * Errata i856 says the 32.768KHz crystal does not start at
+                * power on, so the CPU falls back to an emulated 32KHz clock
+                * based on sysclk / 610 instead. This causes the master counter
+                * frequency to not be 6.144MHz but at sysclk / 610 * 375 / 2
+                * (OR sysclk * 75 / 244)
+                *
+                * This affects at least the DRA7/AM572x 1.0, 1.1 revisions.
+                * Of course any board built without a populated 32.768KHz
+                * crystal would also need this fix even if the CPU is fixed
+                * later.
+                *
+                * Either case can be detected by using the two speedselect bits
+                * If they are not 0, then the 32.768KHz clock driving the
+                * coarse counter that corrects the fine counter every time it
+                * ticks is actually rate/610 rather than 32.768KHz and we
+                * should compensate to avoid the 570ppm (at 20MHz, much worse
+                * at other rates) too fast system time.
+                */
+               reg = omap_ctrl_readl(DRA7_CTRL_CORE_BOOTSTRAP);
+               if (reg & DRA7_SPEEDSELECT_MASK) {
+                       num = 75;
+                       den = 244;
+                       goto sysclk1_based;
+               }
+       }
+
        /* Numerator/denumerator values refer TRM Realtime Counter section */
        switch (rate) {
-       case 1200000:
+       case 12000000:
                num = 64;
                den = 125;
                break;
-       case 1300000:
+       case 13000000:
                num = 768;
                den = 1625;
                break;
@@ -620,11 +651,11 @@ static void __init realtime_counter_init(void)
                num = 192;
                den = 625;
                break;
-       case 2600000:
+       case 26000000:
                num = 384;
                den = 1625;
                break;
-       case 2700000:
+       case 27000000:
                num = 256;
                den = 1125;
                break;
@@ -636,6 +667,7 @@ static void __init realtime_counter_init(void)
                break;
        }
 
+sysclk1_based:
        /* Program numerator and denumerator registers */
        reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) &
                        NUMERATOR_DENUMERATOR_MASK;
@@ -647,7 +679,7 @@ static void __init realtime_counter_init(void)
        reg |= den;
        __raw_writel(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET);
 
-       arch_timer_freq = (rate / den) * num;
+       arch_timer_freq = DIV_ROUND_UP_ULL(rate * num, den);
        set_cntfreq();
 
        iounmap(base);