ARCv2: clocksource: Introduce 64bit local RTC counter
authorVineet Gupta <vgupta@synopsys.com>
Thu, 7 Nov 2013 09:27:16 +0000 (14:57 +0530)
committerVineet Gupta <vgupta@synopsys.com>
Mon, 22 Jun 2015 08:36:56 +0000 (14:06 +0530)
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
arch/arc/Kconfig
arch/arc/kernel/setup.c
arch/arc/kernel/time.c

index 974ed9058018395d69c9bbe76954102815857156..f09e03a0d60486fc307521c24aae79bccc0adce9 100644 (file)
@@ -372,6 +372,11 @@ config ARC_HAS_LL64
          dest operands with 2 possible source operands.
        default y
 
+config ARC_HAS_RTC
+       bool "Local 64-bit r/o cycle counter"
+       default n
+       depends on !SMP
+
 config ARC_NUMBER_OF_INTERRUPTS
        int "Number of interrupts"
        range 8 240
index ca71cef4bafdd81fd5ca983139a991cac2c1586e..a3d186211ed367bcf852718682a62f24b555f3de 100644 (file)
@@ -200,9 +200,11 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
                       (unsigned int)(arc_get_core_freq() / 1000000),
                       (unsigned int)(arc_get_core_freq() / 10000) % 100);
 
-       n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s\nISA Extn\t: ",
+       n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ",
                       IS_AVAIL1(cpu->timers.t0, "Timer0 "),
-                      IS_AVAIL1(cpu->timers.t1, "Timer1 "));
+                      IS_AVAIL1(cpu->timers.t1, "Timer1 "),
+                      IS_AVAIL2(cpu->timers.rtc, "64-bit RTC ",
+                                CONFIG_ARC_HAS_RTC));
 
        n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s",
                           IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
@@ -290,6 +292,9 @@ static void arc_chk_core_config(void)
        if (!cpu->timers.t1)
                panic("Timer1 is not present!\n");
 
+       if (IS_ENABLED(CONFIG_ARC_HAS_RTC) && !cpu->timers.rtc)
+               panic("RTC is not present\n");
+
 #ifdef CONFIG_ARC_HAS_DCCM
        /*
         * DCCM can be arbit placed in hardware.
index 71493f75ae6bd61e3418234e76caf9f8579e3d12..da495478a40b6d4f204c4043c058e75178d004f6 100644 (file)
 
 /********** Clock Source Device *********/
 
+#ifdef CONFIG_ARC_HAS_RTC
+
+#define AUX_RTC_CTRL   0x103
+#define AUX_RTC_LOW    0x104
+#define AUX_RTC_HIGH   0x105
+
+int arc_counter_setup(void)
+{
+       write_aux_reg(AUX_RTC_CTRL, 1);
+
+       /* Not usable in SMP */
+       return !IS_ENABLED(CONFIG_SMP);
+}
+
+static cycle_t arc_counter_read(struct clocksource *cs)
+{
+       unsigned long status;
+       union {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+               struct { u32 high, low; };
+#else
+               struct { u32 low, high; };
+#endif
+               cycle_t  full;
+       } stamp;
+
+
+       __asm__ __volatile(
+       "1:                                             \n"
+       "       lr              %0, [AUX_RTC_LOW]       \n"
+       "       lr              %1, [AUX_RTC_HIGH]      \n"
+       "       lr              %2, [AUX_RTC_CTRL]      \n"
+       "       bbit0.nt        %2, 31, 1b              \n"
+       : "=r" (stamp.low), "=r" (stamp.high), "=r" (status));
+
+       return stamp.full;
+}
+
+static struct clocksource arc_counter = {
+       .name   = "ARCv2 RTC",
+       .rating = 350,
+       .read   = arc_counter_read,
+       .mask   = CLOCKSOURCE_MASK(64),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+#else /* !CONFIG_ARC_HAS_RTC */
+
 /*
  * set 32bit TIMER1 to keep counting monotonically and wraparound
  */
@@ -86,6 +134,8 @@ static struct clocksource arc_counter = {
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+#endif
+
 /********** Clock Event Device *********/
 
 /*