csrc-octeon.c (4983B)
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2007 by Ralf Baechle 7 * Copyright (C) 2009, 2012 Cavium, Inc. 8 */ 9#include <linux/clocksource.h> 10#include <linux/sched/clock.h> 11#include <linux/export.h> 12#include <linux/init.h> 13#include <linux/smp.h> 14 15#include <asm/cpu-info.h> 16#include <asm/cpu-type.h> 17#include <asm/time.h> 18 19#include <asm/octeon/octeon.h> 20#include <asm/octeon/cvmx-ipd-defs.h> 21#include <asm/octeon/cvmx-mio-defs.h> 22#include <asm/octeon/cvmx-rst-defs.h> 23#include <asm/octeon/cvmx-fpa-defs.h> 24 25static u64 f; 26static u64 rdiv; 27static u64 sdiv; 28static u64 octeon_udelay_factor; 29static u64 octeon_ndelay_factor; 30 31void __init octeon_setup_delays(void) 32{ 33 octeon_udelay_factor = octeon_get_clock_rate() / 1000000; 34 /* 35 * For __ndelay we divide by 2^16, so the factor is multiplied 36 * by the same amount. 37 */ 38 octeon_ndelay_factor = (octeon_udelay_factor * 0x10000ull) / 1000ull; 39 40 preset_lpj = octeon_get_clock_rate() / HZ; 41 42 if (current_cpu_type() == CPU_CAVIUM_OCTEON2) { 43 union cvmx_mio_rst_boot rst_boot; 44 45 rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT); 46 rdiv = rst_boot.s.c_mul; /* CPU clock */ 47 sdiv = rst_boot.s.pnr_mul; /* I/O clock */ 48 f = (0x8000000000000000ull / sdiv) * 2; 49 } else if (current_cpu_type() == CPU_CAVIUM_OCTEON3) { 50 union cvmx_rst_boot rst_boot; 51 52 rst_boot.u64 = cvmx_read_csr(CVMX_RST_BOOT); 53 rdiv = rst_boot.s.c_mul; /* CPU clock */ 54 sdiv = rst_boot.s.pnr_mul; /* I/O clock */ 55 f = (0x8000000000000000ull / sdiv) * 2; 56 } 57 58} 59 60/* 61 * Set the current core's cvmcount counter to the value of the 62 * IPD_CLK_COUNT. We do this on all cores as they are brought 63 * on-line. This allows for a read from a local cpu register to 64 * access a synchronized counter. 65 * 66 * On CPU_CAVIUM_OCTEON2 the IPD_CLK_COUNT is scaled by rdiv/sdiv. 67 */ 68void octeon_init_cvmcount(void) 69{ 70 u64 clk_reg; 71 unsigned long flags; 72 unsigned loops = 2; 73 74 clk_reg = octeon_has_feature(OCTEON_FEATURE_FPA3) ? 75 CVMX_FPA_CLK_COUNT : CVMX_IPD_CLK_COUNT; 76 77 /* Clobber loops so GCC will not unroll the following while loop. */ 78 asm("" : "+r" (loops)); 79 80 local_irq_save(flags); 81 /* 82 * Loop several times so we are executing from the cache, 83 * which should give more deterministic timing. 84 */ 85 while (loops--) { 86 u64 clk_count = cvmx_read_csr(clk_reg); 87 if (rdiv != 0) { 88 clk_count *= rdiv; 89 if (f != 0) { 90 asm("dmultu\t%[cnt],%[f]\n\t" 91 "mfhi\t%[cnt]" 92 : [cnt] "+r" (clk_count) 93 : [f] "r" (f) 94 : "hi", "lo"); 95 } 96 } 97 write_c0_cvmcount(clk_count); 98 } 99 local_irq_restore(flags); 100} 101 102static u64 octeon_cvmcount_read(struct clocksource *cs) 103{ 104 return read_c0_cvmcount(); 105} 106 107static struct clocksource clocksource_mips = { 108 .name = "OCTEON_CVMCOUNT", 109 .read = octeon_cvmcount_read, 110 .mask = CLOCKSOURCE_MASK(64), 111 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 112}; 113 114unsigned long long notrace sched_clock(void) 115{ 116 /* 64-bit arithmatic can overflow, so use 128-bit. */ 117 u64 t1, t2, t3; 118 unsigned long long rv; 119 u64 mult = clocksource_mips.mult; 120 u64 shift = clocksource_mips.shift; 121 u64 cnt = read_c0_cvmcount(); 122 123 asm ( 124 "dmultu\t%[cnt],%[mult]\n\t" 125 "nor\t%[t1],$0,%[shift]\n\t" 126 "mfhi\t%[t2]\n\t" 127 "mflo\t%[t3]\n\t" 128 "dsll\t%[t2],%[t2],1\n\t" 129 "dsrlv\t%[rv],%[t3],%[shift]\n\t" 130 "dsllv\t%[t1],%[t2],%[t1]\n\t" 131 "or\t%[rv],%[t1],%[rv]\n\t" 132 : [rv] "=&r" (rv), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3) 133 : [cnt] "r" (cnt), [mult] "r" (mult), [shift] "r" (shift) 134 : "hi", "lo"); 135 return rv; 136} 137 138void __init plat_time_init(void) 139{ 140 clocksource_mips.rating = 300; 141 clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate()); 142} 143 144void __udelay(unsigned long us) 145{ 146 u64 cur, end, inc; 147 148 cur = read_c0_cvmcount(); 149 150 inc = us * octeon_udelay_factor; 151 end = cur + inc; 152 153 while (end > cur) 154 cur = read_c0_cvmcount(); 155} 156EXPORT_SYMBOL(__udelay); 157 158void __ndelay(unsigned long ns) 159{ 160 u64 cur, end, inc; 161 162 cur = read_c0_cvmcount(); 163 164 inc = ((ns * octeon_ndelay_factor) >> 16); 165 end = cur + inc; 166 167 while (end > cur) 168 cur = read_c0_cvmcount(); 169} 170EXPORT_SYMBOL(__ndelay); 171 172void __delay(unsigned long loops) 173{ 174 u64 cur, end; 175 176 cur = read_c0_cvmcount(); 177 end = cur + loops; 178 179 while (end > cur) 180 cur = read_c0_cvmcount(); 181} 182EXPORT_SYMBOL(__delay); 183 184 185/** 186 * octeon_io_clk_delay - wait for a given number of io clock cycles to pass. 187 * 188 * We scale the wait by the clock ratio, and then wait for the 189 * corresponding number of core clocks. 190 * 191 * @count: The number of clocks to wait. 192 */ 193void octeon_io_clk_delay(unsigned long count) 194{ 195 u64 cur, end; 196 197 cur = read_c0_cvmcount(); 198 if (rdiv != 0) { 199 end = count * rdiv; 200 if (f != 0) { 201 asm("dmultu\t%[cnt],%[f]\n\t" 202 "mfhi\t%[cnt]" 203 : [cnt] "+r" (end) 204 : [f] "r" (f) 205 : "hi", "lo"); 206 } 207 end = cur + end; 208 } else { 209 end = cur + count; 210 } 211 while (end > cur) 212 cur = read_c0_cvmcount(); 213} 214EXPORT_SYMBOL(octeon_io_clk_delay);