1 /* $NetBSD: clock.c,v 1.2 2002/03/15 21:12:07 eeh Exp $ */ 2 /* $OpenBSD: clock.c,v 1.3 1997/10/13 13:42:53 pefo Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 6 * Copyright (C) 1995, 1996 TooLs GmbH. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/systm.h> 38 #include <sys/properties.h> 39 40 #include <machine/walnut.h> 41 #include <machine/dcr.h> 42 43 #include <powerpc/spr.h> 44 45 /* 46 * Initially we assume a processor with a bus frequency of 12.5 MHz. 47 */ 48 static u_long ticks_per_sec; 49 static u_long ns_per_tick; 50 static long ticks_per_intr; 51 static volatile u_long lasttb; 52 static u_long ticksmissed; 53 static volatile int tickspending; 54 55 void decr_intr(struct clockframe *); /* called from trap_subr.S */ 56 void stat_intr(struct clockframe *); /* called from trap_subr.S */ 57 static inline u_quad_t mftb(void); 58 59 #ifdef FAST_STAT_CLOCK 60 /* Stat clock runs at ~ 1.5KHz */ 61 #define PERIOD_POWER 17 62 #define TCR_PERIOD TCR_FP_2_17 63 #else 64 /* Stat clock runs at ~ 95Hz */ 65 #define PERIOD_POWER 21 66 #define TCR_PERIOD TCR_FP_2_21 67 #endif 68 69 70 void 71 stat_intr(struct clockframe *frame) 72 { 73 extern u_long intrcnt[]; 74 75 mtspr(SPR_TSR, TSR_FIS); /* Clear TSR[FIS] */ 76 intrcnt[CNT_STATCLOCK]++; 77 statclock(frame); 78 } 79 80 void 81 decr_intr(struct clockframe *frame) 82 { 83 int pri; 84 long tick, xticks; 85 int nticks; 86 extern u_long intrcnt[]; 87 /* 88 * Check whether we are initialized. 89 */ 90 if (!ticks_per_intr) 91 return; 92 93 asm volatile("mftb %0":"=r"(tick):); 94 mtspr(SPR_TSR, TSR_PIS); /* Clear TSR[PIS] */ 95 /* 96 * lasttb is used during microtime. Set it to the virtual 97 * start of this tick interval. 98 */ 99 xticks = tick - lasttb; /* Number of TLB cycles since last exception */ 100 for (nticks = 0; xticks > ticks_per_intr; nticks++) 101 xticks -= ticks_per_intr; 102 lasttb = tick - xticks; 103 104 intrcnt[CNT_CLOCK]++; 105 pri = splclock(); 106 if (pri & SPL_CLOCK) { 107 tickspending += nticks; 108 ticksmissed+= nticks; 109 } else { 110 nticks += tickspending; 111 tickspending = 0; 112 113 /* 114 * Reenable interrupts 115 */ 116 asm volatile ("wrteei 1"); 117 118 /* 119 * Do standard timer interrupt stuff. 120 * Do softclock stuff only on the last iteration. 121 */ 122 frame->pri = pri | SINT_CLOCK; 123 while (--nticks > 0) 124 hardclock(frame); 125 frame->pri = pri; 126 hardclock(frame); 127 } 128 splx(pri); 129 } 130 131 void 132 cpu_initclocks(void) 133 { 134 ticks_per_intr = ticks_per_sec / hz; 135 stathz = profhz = ticks_per_sec / (1<<PERIOD_POWER); 136 printf("Setting PIT to %ld/%d = %ld\n", ticks_per_sec, hz, ticks_per_intr); 137 asm volatile ("mftb %0" : "=r"(lasttb)); 138 mtspr(SPR_PIT, ticks_per_intr); 139 /* Enable PIT & FIT(2^17c = 0.655ms) interrupts and auto-reload */ 140 mtspr(SPR_TCR, TCR_PIE | TCR_ARE | TCR_FIE | TCR_PERIOD); 141 } 142 143 void 144 calc_delayconst(void) 145 { 146 unsigned int processor_freq; 147 148 if (board_info_get("processor-frequency", 149 &processor_freq, sizeof(processor_freq)) == -1) 150 panic("no processor-frequency"); 151 152 ticks_per_sec = processor_freq; 153 ns_per_tick = 1000000000 / ticks_per_sec; 154 155 /* Make sure that timers run at CPU frequency */ 156 mtdcr(DCR_CPC0_CR1, mfdcr(DCR_CPC0_CR1) & ~CPC0_CR1_CETE); 157 } 158 159 static inline u_quad_t 160 mftb(void) 161 { 162 u_long scratch; 163 u_quad_t tb; 164 165 asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b" 166 : "=r"(tb), "=r"(scratch)); 167 return tb; 168 } 169 170 /* 171 * Fill in *tvp with current time with microsecond resolution. 172 */ 173 void 174 microtime(struct timeval *tvp) 175 { 176 u_long tb; 177 u_long ticks; 178 int msr; 179 180 asm volatile ("mfmsr %0; wrteei 0" : "=r"(msr) :); 181 asm ("mftb %0" : "=r"(tb)); 182 ticks = (tb - lasttb) * ns_per_tick; 183 *tvp = time; 184 asm volatile ("mtmsr %0" :: "r"(msr)); 185 ticks /= 1000; 186 tvp->tv_usec += ticks; 187 while (tvp->tv_usec >= 1000000) { 188 tvp->tv_usec -= 1000000; 189 tvp->tv_sec++; 190 } 191 } 192 193 /* 194 * Wait for about n microseconds (at least!). 195 */ 196 void 197 delay(unsigned int n) 198 { 199 u_quad_t tb; 200 u_long tbh, tbl, scratch; 201 202 tb = mftb(); 203 /* use 1000ULL to force 64 bit math to avoid 32 bit overflows */ 204 tb += (n * 1000ULL + ns_per_tick - 1) / ns_per_tick; 205 tbh = tb >> 32; 206 tbl = tb; 207 asm volatile ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;" 208 "mftb %0; cmplw %0,%2; blt 1b; 2:" 209 : "=r"(scratch) : "r"(tbh), "r"(tbl)); 210 } 211 212 /* 213 * Nothing to do. 214 */ 215 void 216 setstatclockrate(int arg) 217 { 218 219 /* Do nothing */ 220 } 221