root/arch/mips/cavium-octeon/csrc-octeon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. octeon_setup_delays
  2. octeon_init_cvmcount
  3. octeon_cvmcount_read
  4. sched_clock
  5. plat_time_init
  6. __udelay
  7. __ndelay
  8. __delay
  9. octeon_io_clk_delay

   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 
  25 static u64 f;
  26 static u64 rdiv;
  27 static u64 sdiv;
  28 static u64 octeon_udelay_factor;
  29 static u64 octeon_ndelay_factor;
  30 
  31 void __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  */
  68 void 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 
 102 static u64 octeon_cvmcount_read(struct clocksource *cs)
 103 {
 104         return read_c0_cvmcount();
 105 }
 106 
 107 static 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 
 114 unsigned 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 
 138 void __init plat_time_init(void)
 139 {
 140         clocksource_mips.rating = 300;
 141         clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate());
 142 }
 143 
 144 void __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 }
 156 EXPORT_SYMBOL(__udelay);
 157 
 158 void __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 }
 170 EXPORT_SYMBOL(__ndelay);
 171 
 172 void __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 }
 182 EXPORT_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  */
 193 void 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 }
 214 EXPORT_SYMBOL(octeon_io_clk_delay);

/* [<][>][^][v][top][bottom][index][help] */