Path: blob/master/arch/mips/cavium-octeon/csrc-octeon.c
26451 views
/*1* This file is subject to the terms and conditions of the GNU General Public2* License. See the file "COPYING" in the main directory of this archive3* for more details.4*5* Copyright (C) 2007 by Ralf Baechle6* Copyright (C) 2009, 2012 Cavium, Inc.7*/8#include <linux/clocksource.h>9#include <linux/sched/clock.h>10#include <linux/export.h>11#include <linux/init.h>12#include <linux/smp.h>1314#include <asm/cpu-info.h>15#include <asm/cpu-type.h>16#include <asm/time.h>1718#include <asm/octeon/octeon.h>19#include <asm/octeon/cvmx-ipd-defs.h>20#include <asm/octeon/cvmx-mio-defs.h>21#include <asm/octeon/cvmx-rst-defs.h>22#include <asm/octeon/cvmx-fpa-defs.h>2324static u64 f;25static u64 rdiv;26static u64 sdiv;27static u64 octeon_udelay_factor;28static u64 octeon_ndelay_factor;2930void __init octeon_setup_delays(void)31{32octeon_udelay_factor = octeon_get_clock_rate() / 1000000;33/*34* For __ndelay we divide by 2^16, so the factor is multiplied35* by the same amount.36*/37octeon_ndelay_factor = (octeon_udelay_factor * 0x10000ull) / 1000ull;3839preset_lpj = octeon_get_clock_rate() / HZ;4041if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {42union cvmx_mio_rst_boot rst_boot;4344rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);45rdiv = rst_boot.s.c_mul; /* CPU clock */46sdiv = rst_boot.s.pnr_mul; /* I/O clock */47f = (0x8000000000000000ull / sdiv) * 2;48} else if (current_cpu_type() == CPU_CAVIUM_OCTEON3) {49union cvmx_rst_boot rst_boot;5051rst_boot.u64 = cvmx_read_csr(CVMX_RST_BOOT);52rdiv = rst_boot.s.c_mul; /* CPU clock */53sdiv = rst_boot.s.pnr_mul; /* I/O clock */54f = (0x8000000000000000ull / sdiv) * 2;55}5657}5859/*60* Set the current core's cvmcount counter to the value of the61* IPD_CLK_COUNT. We do this on all cores as they are brought62* on-line. This allows for a read from a local cpu register to63* access a synchronized counter.64*65* On CPU_CAVIUM_OCTEON2 the IPD_CLK_COUNT is scaled by rdiv/sdiv.66*/67void octeon_init_cvmcount(void)68{69u64 clk_reg;70unsigned long flags;71unsigned loops = 2;7273clk_reg = octeon_has_feature(OCTEON_FEATURE_FPA3) ?74CVMX_FPA_CLK_COUNT : CVMX_IPD_CLK_COUNT;7576/* Clobber loops so GCC will not unroll the following while loop. */77asm("" : "+r" (loops));7879local_irq_save(flags);80/*81* Loop several times so we are executing from the cache,82* which should give more deterministic timing.83*/84while (loops--) {85u64 clk_count = cvmx_read_csr(clk_reg);86if (rdiv != 0) {87clk_count *= rdiv;88if (f != 0) {89asm("dmultu\t%[cnt],%[f]\n\t"90"mfhi\t%[cnt]"91: [cnt] "+r" (clk_count)92: [f] "r" (f)93: "hi", "lo");94}95}96write_c0_cvmcount(clk_count);97}98local_irq_restore(flags);99}100101static u64 octeon_cvmcount_read(struct clocksource *cs)102{103return read_c0_cvmcount();104}105106static struct clocksource clocksource_mips = {107.name = "OCTEON_CVMCOUNT",108.read = octeon_cvmcount_read,109.mask = CLOCKSOURCE_MASK(64),110.flags = CLOCK_SOURCE_IS_CONTINUOUS,111};112113unsigned long long notrace sched_clock(void)114{115/* 64-bit arithmetic can overflow, so use 128-bit. */116u64 t1, t2, t3;117unsigned long long rv;118u64 mult = clocksource_mips.mult;119u64 shift = clocksource_mips.shift;120u64 cnt = read_c0_cvmcount();121122asm (123"dmultu\t%[cnt],%[mult]\n\t"124"nor\t%[t1],$0,%[shift]\n\t"125"mfhi\t%[t2]\n\t"126"mflo\t%[t3]\n\t"127"dsll\t%[t2],%[t2],1\n\t"128"dsrlv\t%[rv],%[t3],%[shift]\n\t"129"dsllv\t%[t1],%[t2],%[t1]\n\t"130"or\t%[rv],%[t1],%[rv]\n\t"131: [rv] "=&r" (rv), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3)132: [cnt] "r" (cnt), [mult] "r" (mult), [shift] "r" (shift)133: "hi", "lo");134return rv;135}136137void __init plat_time_init(void)138{139clocksource_mips.rating = 300;140clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate());141}142143void __udelay(unsigned long us)144{145u64 cur, end, inc;146147cur = read_c0_cvmcount();148149inc = us * octeon_udelay_factor;150end = cur + inc;151152while (end > cur)153cur = read_c0_cvmcount();154}155EXPORT_SYMBOL(__udelay);156157void __ndelay(unsigned long ns)158{159u64 cur, end, inc;160161cur = read_c0_cvmcount();162163inc = ((ns * octeon_ndelay_factor) >> 16);164end = cur + inc;165166while (end > cur)167cur = read_c0_cvmcount();168}169EXPORT_SYMBOL(__ndelay);170171void __delay(unsigned long loops)172{173u64 cur, end;174175cur = read_c0_cvmcount();176end = cur + loops;177178while (end > cur)179cur = read_c0_cvmcount();180}181EXPORT_SYMBOL(__delay);182183184/**185* octeon_io_clk_delay - wait for a given number of io clock cycles to pass.186*187* We scale the wait by the clock ratio, and then wait for the188* corresponding number of core clocks.189*190* @count: The number of clocks to wait.191*/192void octeon_io_clk_delay(unsigned long count)193{194u64 cur, end;195196cur = read_c0_cvmcount();197if (rdiv != 0) {198end = count * rdiv;199if (f != 0) {200asm("dmultu\t%[cnt],%[f]\n\t"201"mfhi\t%[cnt]"202: [cnt] "+r" (end)203: [f] "r" (f)204: "hi", "lo");205}206end = cur + end;207} else {208end = cur + count;209}210while (end > cur)211cur = read_c0_cvmcount();212}213EXPORT_SYMBOL(octeon_io_clk_delay);214215216