MIPS: Octeon: Scale Octeon2 clocks in octeon_init_cvmcount()

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>
This commit is contained in:
David Daney 2010-10-07 16:03:47 -07:00 committed by Ralf Baechle
parent f92a6b0875
commit 54954a6d6b

View file

@ -4,14 +4,18 @@
* for more details. * for more details.
* *
* Copyright (C) 2007 by Ralf Baechle * Copyright (C) 2007 by Ralf Baechle
* Copyright (C) 2009, 2010 Cavium Networks, Inc.
*/ */
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/smp.h>
#include <asm/cpu-info.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/octeon/octeon.h> #include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-ipd-defs.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 * Set the current core's cvmcount counter to the value of the
@ -19,11 +23,23 @@
* on-line. This allows for a read from a local cpu register to * on-line. This allows for a read from a local cpu register to
* access a synchronized counter. * access a synchronized counter.
* *
* On CPU_CAVIUM_OCTEON2 the IPD_CLK_COUNT is scaled by rdiv/sdiv.
*/ */
void octeon_init_cvmcount(void) void octeon_init_cvmcount(void)
{ {
unsigned long flags; unsigned long flags;
unsigned loops = 2; 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. */ /* Clobber loops so GCC will not unroll the following while loop. */
asm("" : "+r" (loops)); asm("" : "+r" (loops));
@ -33,8 +49,20 @@ void octeon_init_cvmcount(void)
* Loop several times so we are executing from the cache, * Loop several times so we are executing from the cache,
* which should give more deterministic timing. * which should give more deterministic timing.
*/ */
while (loops--) while (loops--) {
write_c0_cvmcount(cvmx_read_csr(CVMX_IPD_CLK_COUNT)); 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); local_irq_restore(flags);
} }
@ -77,7 +105,7 @@ unsigned long long notrace sched_clock(void)
void __init plat_time_init(void) void __init plat_time_init(void)
{ {
clocksource_mips.rating = 300; 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); clocksource_register(&clocksource_mips);
} }