Pull button into test branch
[linux-drm-fsl-dcu.git] / arch / arm / mach-pxa / generic.c
index 45fb2c3bcf828f3812adf0b95675d77256487c05..6ae605857ca9bfb6764bfbe68761ff960ba35ddb 100644 (file)
 #include <linux/pm.h>
 #include <linux/string.h>
 
+#include <linux/sched.h>
+#include <asm/cnt32_to_63.h>
+#include <asm/div64.h>
+
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
 #include "generic.h"
 
+/*
+ * This is the PXA2xx sched_clock implementation. This has a resolution
+ * of at least 308ns and a maximum value that depends on the value of
+ * CLOCK_TICK_RATE.
+ *
+ * The return value is guaranteed to be monotonic in that range as
+ * long as there is always less than 582 seconds between successive
+ * calls to this function.
+ */
+unsigned long long sched_clock(void)
+{
+       unsigned long long v = cnt32_to_63(OSCR);
+       /* Note: top bit ov v needs cleared unless multiplier is even. */
+
+#if    CLOCK_TICK_RATE == 3686400
+       /* 1E9 / 3686400 => 78125 / 288, max value = 32025597s (370 days). */
+       /* The <<1 is used to get rid of tick.hi top bit */
+       v *= 78125<<1;
+       do_div(v, 288<<1);
+#elif  CLOCK_TICK_RATE == 3250000
+       /* 1E9 / 3250000 => 4000 / 13, max value = 709490156s (8211 days) */
+       v *= 4000;
+       do_div(v, 13);
+#elif  CLOCK_TICK_RATE == 3249600
+       /* 1E9 / 3249600 => 625000 / 2031, max value = 4541295s (52 days) */
+       v *= 625000;
+       do_div(v, 2031);
+#else
+#warning "consider fixing sched_clock for your value of CLOCK_TICK_RATE"
+       /*
+        * 96-bit math to perform tick * NSEC_PER_SEC / CLOCK_TICK_RATE for
+        * any value of CLOCK_TICK_RATE. Max value is in the 80 thousand
+        * years range which is nice, but with higher computation cost.
+        */
+       {
+               union {
+                       unsigned long long val;
+                       struct { unsigned long lo, hi; };
+               } x;
+               unsigned long long y;
+
+               x.val = v;
+               x.hi &= 0x7fffffff;
+               y = (unsigned long long)x.lo * NSEC_PER_SEC;
+               x.lo = y;
+               y = (y >> 32) + (unsigned long long)x.hi * NSEC_PER_SEC;
+               x.hi = do_div(y, CLOCK_TICK_RATE);
+               do_div(x.val, CLOCK_TICK_RATE);
+               x.hi += y;
+               v = x.val;
+       }
+#endif
+
+       return v;
+}
+
 /*
  * Handy function to set GPIO alternate functions
  */