MIPS: Octeon: Scale Octeon2 clocks in octeon_init_cvmcount()
authorDavid Daney <ddaney@caviumnetworks.com>
Thu, 7 Oct 2010 23:03:47 +0000 (16:03 -0700)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 29 Oct 2010 18:08:38 +0000 (19:08 +0100)
The per-CPU clocks are synchronized from IPD_CLK_COUNT, on cn63XX it must
be scaled by the clock frequency ratio.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Patchwork: http://patchwork.linux-mips.org/patch/1667/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/cavium-octeon/csrc-octeon.c

index b6847c8e0ddd3784b4050b7dee6558cfd595e119..26bf71130bf8b1dd6fe1d24c8b5e336a2b30b78d 100644 (file)
@@ -4,14 +4,18 @@
  * for more details.
  *
  * Copyright (C) 2007 by Ralf Baechle
+ * Copyright (C) 2009, 2010 Cavium Networks, Inc.
  */
 #include <linux/clocksource.h>
 #include <linux/init.h>
+#include <linux/smp.h>
 
+#include <asm/cpu-info.h>
 #include <asm/time.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-ipd-defs.h>
+#include <asm/octeon/cvmx-mio-defs.h>
 
 /*
  * Set the current core's cvmcount counter to the value of the
  * on-line.  This allows for a read from a local cpu register to
  * access a synchronized counter.
  *
+ * On CPU_CAVIUM_OCTEON2 the IPD_CLK_COUNT is scaled by rdiv/sdiv.
  */
 void octeon_init_cvmcount(void)
 {
        unsigned long flags;
        unsigned loops = 2;
+       u64 f = 0;
+       u64 rdiv = 0;
+       u64 sdiv = 0;
+       if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {
+               union cvmx_mio_rst_boot rst_boot;
+               rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
+               rdiv = rst_boot.s.c_mul;        /* CPU clock */
+               sdiv = rst_boot.s.pnr_mul;      /* I/O clock */
+               f = (0x8000000000000000ull / sdiv) * 2;
+       }
+
 
        /* Clobber loops so GCC will not unroll the following while loop. */
        asm("" : "+r" (loops));
@@ -33,8 +49,20 @@ void octeon_init_cvmcount(void)
         * Loop several times so we are executing from the cache,
         * which should give more deterministic timing.
         */
-       while (loops--)
-               write_c0_cvmcount(cvmx_read_csr(CVMX_IPD_CLK_COUNT));
+       while (loops--) {
+               u64 ipd_clk_count = cvmx_read_csr(CVMX_IPD_CLK_COUNT);
+               if (rdiv != 0) {
+                       ipd_clk_count *= rdiv;
+                       if (f != 0) {
+                               asm("dmultu\t%[cnt],%[f]\n\t"
+                                   "mfhi\t%[cnt]"
+                                   : [cnt] "+r" (ipd_clk_count),
+                                     [f] "=r" (f)
+                                   : : "hi", "lo");
+                       }
+               }
+               write_c0_cvmcount(ipd_clk_count);
+       }
        local_irq_restore(flags);
 }
 
@@ -77,7 +105,7 @@ unsigned long long notrace sched_clock(void)
 void __init plat_time_init(void)
 {
        clocksource_mips.rating = 300;
-       clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
+       clocksource_set_clock(&clocksource_mips, octeon_get_clock_rate());
        clocksource_register(&clocksource_mips);
 }