1 /* $NetBSD: clock_ebus.c,v 1.1 2011/01/26 01:18:50 pooka Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code was written by Alessandro Forin and Neil Pittman 8 * at Microsoft Research and contributed to The NetBSD Foundation 9 * by Microsoft Corporation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 __KERNEL_RCSID(0, "$NetBSD: clock_ebus.c,v 1.1 2011/01/26 01:18:50 pooka Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/kernel.h> 38 #include <sys/device.h> 39 #include <sys/systm.h> 40 #include <sys/timetc.h> 41 42 #include <dev/clock_subr.h> 43 44 #include <emips/ebus/ebusvar.h> 45 #include <emips/emips/machdep.h> 46 #include <machine/emipsreg.h> 47 48 /* 49 * Device softc 50 */ 51 struct eclock_softc { 52 struct device sc_dev; 53 struct _Tc *sc_dp; 54 uint32_t reload; 55 struct timecounter sc_tc; 56 #ifdef __HAVE_GENERIC_TODR 57 struct todr_chip_handle sc_todr; 58 #endif 59 }; 60 61 static int eclock_ebus_match (struct device *, struct cfdata *, void *); 62 static void eclock_ebus_attach (struct device *, struct device *, void *); 63 64 CFATTACH_DECL(eclock_ebus, sizeof (struct eclock_softc), 65 eclock_ebus_match, eclock_ebus_attach, NULL, NULL); 66 67 void eclock_init(struct device *); 68 static void __eclock_init(struct device *); 69 static int eclock_gettime(struct todr_chip_handle *, 70 struct timeval *); 71 static int eclock_settime(struct todr_chip_handle *, 72 struct timeval *); 73 static int eclock_ebus_intr(void *cookie, void *f); 74 static u_int eclock_counter(struct timecounter *tc); 75 76 struct device *clockdev = NULL; /* BUGBUG resolve the gap between cpu_initclocks() and eclock_init(x) */ 77 78 void 79 eclock_init(struct device *dev) 80 { 81 if (dev == NULL) 82 dev = clockdev; 83 if (dev == NULL) 84 panic("eclock_init"); 85 __eclock_init(dev); 86 } 87 88 static void 89 __eclock_init(struct device *dev) 90 { 91 struct eclock_softc *sc = (struct eclock_softc *)dev; 92 struct _Tc *tc = sc->sc_dp; 93 uint32_t reload = 10*1000000; /* 1sec in 100ns units (10MHz clock) */ 94 95 /* Compute reload according to whatever value passed in, Warn if fractional */ 96 if (hz > 1) { 97 uint32_t r = reload / hz; 98 if ((r * hz) != reload) 99 printf("%s: %d Hz clock will cause roundoffs with 10MHz xtal (%d)\n", 100 sc->sc_dev.dv_xname, hz, reload - (r * hz)); 101 reload = r; 102 } 103 104 sc->reload = reload; 105 106 /* Start the counter */ 107 tc->DownCounterHigh = 0; 108 tc->DownCounter = sc->reload; 109 tc->Control = TCCT_ENABLE | TCCT_INT_ENABLE; 110 } 111 112 /* 113 * Get the time of day, based on the clock's value and/or the base value. 114 * NB: At 10MHz, our 64bits FreeRunning is worth 58,426 years. 115 */ 116 117 extern u_quad_t __qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq); 118 119 120 static int 121 eclock_gettime(struct todr_chip_handle *todr, struct timeval *tv) 122 { 123 struct eclock_softc *sc = (struct eclock_softc *) todr->cookie; 124 struct _Tc *tc = sc->sc_dp; 125 uint64_t free; 126 int s; 127 128 /* 32bit processor, guard against interrupts in the middle of reading this 64bit entity 129 * BUGBUG Should read it "twice" to guard against rollover too. 130 */ 131 s = splhigh(); 132 free = tc->FreeRunning; 133 splx(s); 134 135 /* Big fight with the compiler here, it gets very confused by 64bits. 136 */ 137 #if 0 138 /* This is in C: 139 */ 140 { 141 uint64_t freeS, freeU; 142 freeS = free / (10*1000*1000); 143 freeU = free % (10*1000*1000); 144 tv->tv_sec = freeS; 145 tv->tv_usec = freeU / 10; 146 //printf("egt: s x%lx u x%lx (fs %lld fu %lld f %lld)\n",tv->tv_sec,tv->tv_usec,freeS,freeU,free); 147 } 148 #else 149 /* And this is in assembly :-) 150 */ 151 { 152 u_quad_t r; 153 u_quad_t d = __qdivrem(free,(u_quad_t)10000000,&r); 154 uint32_t su, uu; 155 su = (uint32_t) d; 156 uu = (uint32_t) r; 157 uu = uu / 10; /* in usecs */ 158 tv->tv_sec = su; 159 tv->tv_usec = uu; 160 //printf("egt: s x%lx u x%lx (d %lld r %lld f %lld)\n",tv->tv_sec,tv->tv_usec,d,r,free); 161 } 162 #endif 163 164 return 0; 165 } 166 167 /* 168 * Reset the TODR based on the time value. 169 */ 170 static int 171 eclock_settime(struct todr_chip_handle *todr, struct timeval *tv) 172 { 173 struct eclock_softc *sc = (struct eclock_softc *) todr->cookie; 174 struct _Tc *tc = sc->sc_dp; 175 uint64_t free; 176 uint32_t su, uu; 177 int s; 178 179 /* Careful with what we do here, else the compilerbugs hit hard */ 180 s = splhigh(); 181 182 su = (uint32_t) tv->tv_sec; //0(tv) 183 uu = (uint32_t) tv->tv_usec; //4(tv) 184 185 186 free = 10*1000*1000 * (uint64_t)su; 187 free += uu * 10; 188 189 tc->FreeRunning = free; 190 splx(s); 191 192 #if 0 193 Should compile to something like this: 194 80260c84 <eclock_settime>: 195 80260c84: 27bdffc0 addiu sp,sp,-64 196 80260c88: afbf0038 sw ra,56(sp) 197 80260c8c: afb40030 sw s4,48(sp) 198 80260c90: afb3002c sw s3,44(sp) 199 80260c94: afb20028 sw s2,40(sp) 200 80260c98: afb10024 sw s1,36(sp) 201 80260c9c: afb00020 sw s0,32(sp) 202 80260ca0: afb50034 sw s5,52(sp) 203 80260ca4: 8c820000 lw v0,0(a0) 204 80260ca8: 00a09021 move s2,a1 205 80260cac: 8c55003c lw s5,60(v0) //s5=tc 206 80260cb0: 0c004122 jal 80010488 <_splraise> 207 80260cb4: 3404ff00 li a0,0xff00 208 80260cb8: 8e540000 lw s4,0(s2) //s4=tv->tv_sec=us 209 80260cbc: 3c060098 lui a2,0x98 210 80260cc0: 34c69680 ori a2,a2,0x9680 //a2=10000000 211 80260cc4: 02860019 multu s4,a2 //free=us*10000000 212 80260cc8: 8e530004 lw s3,4(s2) //s3=uu 213 80260ccc: 00402021 move a0,v0 //s=splhigh() 214 80260cd0: 001328c0 sll a1,s3,0x3 215 80260cd4: 00131040 sll v0,s3,0x1 216 80260cd8: 00451021 addu v0,v0,a1 217 80260cdc: 00401821 move v1,v0 //v1 = uu*10 218 80260ce0: 00001021 move v0,zero 219 80260ce4: 00003812 mflo a3 //a3=low(free) 220 80260ce8: 00e38821 addu s1,a3,v1 //s1=low(free)+(uu*10) 221 80260cec: 0227282b sltu a1,s1,a3 //a1=overflow bit 222 80260cf0: 00003010 mfhi a2 //a2=high(free) 223 80260cf4: 00c28021 addu s0,a2,v0 //s0=a2=high(free) [useless, v0=0] 224 80260cf8: 00b08021 addu s0,a1,s0 //s0+=overflow bit 225 80260cfc: aeb1000c sw s1,12(s5) 226 80260d00: aeb00008 sw s0,8(s5) 227 80260d04: 0c00413f jal 800104fc <_splset> 228 80260d08: 00000000 nop 229 230 #endif 231 232 //printf("est: s x%lx u x%lx (%d %d), free %lld\n",tv->tv_sec,tv->tv_usec,su,uu,free); 233 234 return 0; 235 } 236 237 static int 238 eclock_ebus_intr(void *cookie, void *f) 239 { 240 struct eclock_softc *sc = cookie; 241 struct _Tc *tc = sc->sc_dp; 242 struct clockframe *cf = f; 243 volatile uint32_t x; 244 245 x = tc->Control; 246 tc->DownCounterHigh = 0; 247 tc->DownCounter = sc->reload; 248 249 hardclock(cf); 250 emips_clock_evcnt.ev_count++; 251 252 return (0); 253 } 254 255 static u_int 256 eclock_counter(struct timecounter *tc) 257 { 258 struct eclock_softc *sc = tc->tc_priv; 259 struct _Tc *Tc = sc->sc_dp; 260 return (u_int)Tc->FreeRunning; /* NB: chops to 32bits */ 261 } 262 263 264 static int 265 eclock_ebus_match(struct device *parent, struct cfdata *match, void *aux) 266 { 267 struct ebus_attach_args *ia = aux; 268 struct _Tc *mc = (struct _Tc *)ia->ia_vaddr; 269 270 if (strcmp("eclock", ia->ia_name) != 0) 271 return (0); 272 if ((mc == NULL) || 273 (mc->Tag != PMTTAG_TIMER)) 274 return (0); 275 276 return (1); 277 } 278 279 static void 280 eclock_ebus_attach(struct device *parent, struct device *self, void *aux) 281 { 282 struct ebus_attach_args *ia =aux; 283 struct eclock_softc *sc = (struct eclock_softc *)self; 284 285 sc->sc_dp = (struct _Tc*)ia->ia_vaddr; 286 287 /* NB: We are chopping our 64bit free-running down to 32bits */ 288 sc->sc_tc.tc_get_timecount = eclock_counter; 289 sc->sc_tc.tc_poll_pps = 0; 290 sc->sc_tc.tc_counter_mask = 0xffffffff; 291 sc->sc_tc.tc_frequency = 10*1000*1000; /* 10 MHz */ 292 sc->sc_tc.tc_name = "eclock"; /* BUGBUG is it unique per instance?? */ 293 sc->sc_tc.tc_quality = 2000; /* uhu? */ 294 sc->sc_tc.tc_priv = sc; 295 sc->sc_tc.tc_next = NULL; 296 297 #if DEBUG 298 printf(" virt=%p ", (void*)sc->sc_dp); 299 #endif 300 printf(": eMIPS clock\n"); 301 302 /* Turn interrupts off, just in case. */ 303 sc->sc_dp->Control &= ~(TCCT_INT_ENABLE|TCCT_INTERRUPT); 304 305 ebus_intr_establish(parent, (void *)ia->ia_cookie, IPL_CLOCK, 306 eclock_ebus_intr, sc); 307 308 #ifdef EVCNT_COUNTERS 309 evcnt_attach_dynamic(&clock_intr_evcnt, EVCNT_TYPE_INTR, NULL, 310 sc->sc_dev->dv_xname, "intr"); 311 #endif 312 313 #ifdef __HAVE_GENERIC_TODR 314 clockdev = self; 315 memset(&sc->sc_todr,0,sizeof sc->sc_todr); 316 sc->sc_todr.cookie = sc; 317 sc->sc_todr.todr_gettime = eclock_gettime; 318 sc->sc_todr.todr_settime = eclock_settime; 319 todr_attach(&sc->sc_todr); 320 #endif 321 322 tc_init(&sc->sc_tc); 323 } 324