Commit 54954a6d authored by David Daney's avatar David Daney Committed by Ralf Baechle
Browse files

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: default avatarDavid Daney <ddaney@caviumnetworks.com>
Patchwork: http://patchwork.linux-mips.org/patch/1667/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent f92a6b08
Loading
Loading
Loading
Loading
+31 −3
Original line number Diff line number Diff line
@@ -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
@@ -19,11 +23,23 @@
 * 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);
}