1 /* $NetBSD: timer.c,v 1.25 2010/01/03 23:03:21 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1994 Gordon W. Ross 7 * Copyright (c) 1993 Adam Glass 8 * Copyright (c) 1996 Paul Kranenburg 9 * Copyright (c) 1996 10 * The President and Fellows of Harvard College. All rights reserved. 11 * 12 * This software was developed by the Computer Systems Engineering group 13 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 14 * contributed to Berkeley. 15 * 16 * All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Harvard University. 19 * This product includes software developed by the University of 20 * California, Lawrence Berkeley Laboratory. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * This product includes software developed by the University of 34 * California, Berkeley and its contributors. 35 * This product includes software developed by Paul Kranenburg. 36 * This product includes software developed by Harvard University. 37 * 4. Neither the name of the University nor the names of its contributors 38 * may be used to endorse or promote products derived from this software 39 * without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * @(#)clock.c 8.1 (Berkeley) 6/11/93 54 */ 55 56 /* 57 * Kernel clocks provided by "timer" device. The hardclock is provided by 58 * the timer register (aka system counter). The statclock is provided by 59 * per CPU counter register(s) (aka processor counter(s)). 60 */ 61 62 #include <sys/cdefs.h> 63 __KERNEL_RCSID(0, "$NetBSD: timer.c,v 1.25 2010/01/03 23:03:21 mrg Exp $"); 64 65 #include <sys/param.h> 66 #include <sys/kernel.h> 67 #include <sys/device.h> 68 #include <sys/systm.h> 69 #include <sys/timetc.h> 70 71 #include <machine/autoconf.h> 72 #include <machine/bus.h> 73 74 #include <sparc/sparc/timerreg.h> 75 #include <sparc/sparc/timervar.h> 76 77 static struct intrhand level10; 78 static struct intrhand level14; 79 80 static u_int timer_get_timecount(struct timecounter *); 81 82 /* 83 * timecounter local state 84 */ 85 static struct counter { 86 volatile u_int *cntreg; /* counter register */ 87 u_int limit; /* limit we count up to */ 88 u_int offset; /* accumulated offet due to wraps */ 89 u_int shift; /* scaling for valid bits */ 90 u_int mask; /* valid bit mask */ 91 } cntr; 92 93 /* 94 * define timecounter 95 */ 96 97 static struct timecounter counter_timecounter = { 98 timer_get_timecount, /* get_timecount */ 99 0, /* no poll_pps */ 100 ~0u, /* counter_mask */ 101 0, /* frequency - set at initialisation */ 102 "timer-counter", /* name */ 103 100, /* quality */ 104 &cntr /* private reference */ 105 }; 106 107 /* 108 * timer_get_timecount provide current counter value 109 */ 110 static u_int 111 timer_get_timecount(struct timecounter *tc) 112 { 113 struct counter *ctr = (struct counter *)tc->tc_priv; 114 115 u_int c, res, r; 116 int s; 117 118 119 s = splhigh(); 120 121 res = c = *ctr->cntreg; 122 123 res &= ~TMR_LIMIT; 124 125 if (c != res) { 126 r = ctr->limit; 127 } else { 128 r = 0; 129 } 130 131 res >>= ctr->shift; 132 res &= ctr->mask; 133 134 res += r + ctr->offset; 135 136 splx(s); 137 138 return res; 139 } 140 141 void 142 tickle_tc(void) 143 { 144 if (timecounter->tc_get_timecount == timer_get_timecount) { 145 cntr.offset += cntr.limit; 146 } 147 } 148 149 /* 150 * sun4/sun4c/sun4m common timer attach code 151 */ 152 void 153 timerattach(volatile int *cntreg, volatile int *limreg) 154 { 155 u_int prec = 0, t0; 156 157 /* 158 * Calibrate delay() by tweaking the magic constant 159 * until a delay(100) actually reads (at least) 100 us on the clock. 160 * Note: sun4m clocks tick with 500ns periods. 161 */ 162 for (timerblurb = 1; ; timerblurb++) { 163 volatile int discard; 164 u_int t1; 165 166 /* Reset counter register by writing some large limit value */ 167 discard = *limreg; 168 *limreg = tmr_ustolim(TMR_MASK-1); 169 170 t0 = *cntreg; 171 delay(100); 172 t1 = *cntreg; 173 174 prec |= (t0 ^ t1) | (*cntreg ^ *cntreg); 175 176 if (t1 & TMR_LIMIT) 177 panic("delay calibration"); 178 179 t0 = (t0 >> TMR_SHIFT) & TMR_MASK; 180 t1 = (t1 >> TMR_SHIFT) & TMR_MASK; 181 182 if (t1 >= t0 + 100) 183 break; 184 } 185 186 /* find lowest active bit */ 187 for (t0 = 0; t0 < TMR_SHIFT; t0++) 188 if ((1 << t0) & prec) 189 break; 190 191 cntr.shift = t0; 192 cntr.mask = (1 << (31-t0))-1; 193 counter_timecounter.tc_frequency = 1000000 * (TMR_SHIFT - t0 + 1); 194 195 printf(": delay constant %d, frequency = %" PRIu64 " Hz\n", timerblurb, counter_timecounter.tc_frequency); 196 197 #if defined(SUN4) || defined(SUN4C) 198 if (CPU_ISSUN4 || CPU_ISSUN4C) { 199 timer_init = timer_init_4; 200 level10.ih_fun = clockintr_4; 201 level14.ih_fun = statintr_4; 202 cntr.limit = tmr_ustolim(tick); 203 } 204 #endif 205 #if defined(SUN4M) 206 if (CPU_ISSUN4M) { 207 timer_init = timer_init_4m; 208 level10.ih_fun = clockintr_4m; 209 level14.ih_fun = statintr_4m; 210 cntr.limit = tmr_ustolim4m(tick); 211 } 212 #endif 213 /* link interrupt handlers */ 214 intr_establish(10, 0, &level10, NULL, true); 215 intr_establish(14, 0, &level14, NULL, true); 216 217 /* Establish a soft interrupt at a lower level for schedclock */ 218 sched_cookie = sparc_softintr_establish(IPL_SCHED, schedintr, NULL); 219 if (sched_cookie == NULL) 220 panic("timerattach: cannot establish schedintr"); 221 222 cntr.cntreg = cntreg; 223 cntr.limit >>= cntr.shift; 224 225 tc_init(&counter_timecounter); 226 } 227 228 /* 229 * Both sun4 and sun4m can attach a timer on obio. 230 * The sun4m OPENPROM calls the timer the "counter". 231 * The sun4 timer must be probed. 232 */ 233 static int 234 timermatch_obio(struct device *parent, struct cfdata *cf, void *aux) 235 { 236 #if defined(SUN4) || defined(SUN4M) 237 union obio_attach_args *uoba = aux; 238 #endif 239 #if defined(SUN4) 240 struct obio4_attach_args *oba; 241 #endif 242 243 #if defined(SUN4M) 244 if (uoba->uoba_isobio4 == 0) 245 return (strcmp("counter", uoba->uoba_sbus.sa_name) == 0); 246 #endif /* SUN4M */ 247 248 if (CPU_ISSUN4 == 0) { 249 printf("timermatch_obio: attach args mixed up\n"); 250 return (0); 251 } 252 253 #if defined(SUN4) 254 /* Only these sun4s have "timer" (others have "oclock") */ 255 if (cpuinfo.cpu_type != CPUTYP_4_300 && 256 cpuinfo.cpu_type != CPUTYP_4_400) 257 return (0); 258 259 /* Make sure there is something there */ 260 oba = &uoba->uoba_oba4; 261 return (bus_space_probe(oba->oba_bustag, oba->oba_paddr, 262 4, /* probe size */ 263 0, /* offset */ 264 0, /* flags */ 265 NULL, NULL)); 266 #endif /* SUN4 */ 267 panic("timermatch_obio: impossible"); 268 } 269 270 static void 271 timerattach_obio(struct device *parent, struct device *self, void *aux) 272 { 273 union obio_attach_args *uoba = aux; 274 275 if (uoba->uoba_isobio4 == 0) { 276 #if defined(SUN4M) 277 /* sun4m timer at obio */ 278 timerattach_obio_4m(parent, self, aux); 279 #endif /* SUN4M */ 280 return; 281 } 282 283 if (uoba->uoba_isobio4 != 0) { 284 #if defined(SUN4) 285 /* sun4 timer at obio */ 286 timerattach_obio_4(parent, self, aux); 287 #endif /* SUN4 */ 288 } 289 } 290 291 CFATTACH_DECL(timer_obio, sizeof(struct device), 292 timermatch_obio, timerattach_obio, NULL, NULL); 293 294 /* 295 * Only sun4c attaches a timer at mainbus 296 */ 297 static int 298 timermatch_mainbus(struct device *parent, struct cfdata *cf, void *aux) 299 { 300 #if defined(SUN4C) 301 struct mainbus_attach_args *ma = aux; 302 303 return (strcmp("counter-timer", ma->ma_name) == 0); 304 #else 305 return (0); 306 #endif 307 } 308 309 static void 310 timerattach_mainbus(struct device *parent, struct device *self, void *aux) 311 { 312 313 #if defined(SUN4C) 314 timerattach_mainbus_4c(parent, self, aux); 315 #endif /* SUN4C */ 316 } 317 318 CFATTACH_DECL(timer_mainbus, sizeof(struct device), 319 timermatch_mainbus, timerattach_mainbus, NULL, NULL); 320