1 /* $NetBSD: gemini_timer.c,v 1.4 2010/01/05 13:14:56 mbalmer Exp $ */ 2 3 /* adapted from: 4 * NetBSD: omap2_geminitmr.c,v 1.1 2008/08/27 11:03:10 matt Exp 5 */ 6 7 /* 8 * GEMINI Timers 9 */ 10 11 /* 12 * Based on i80321_timer.c and arch/arm/sa11x0/sa11x0_ost.c 13 * 14 * Copyright (c) 1997 Mark Brinicombe. 15 * Copyright (c) 1997 Causality Limited. 16 * All rights reserved. 17 * 18 * This code is derived from software contributed to The NetBSD Foundation 19 * by IWAMOTO Toshihiro and Ichiro FUKUHARA. 20 * 21 * Redistribution and use in source and binary forms, with or without 22 * modification, are permitted provided that the following conditions 23 * are met: 24 * 1. Redistributions of source code must retain the above copyright 25 * notice, this list of conditions and the following disclaimer. 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in the 28 * documentation and/or other materials provided with the distribution. 29 * 3. All advertising materials mentioning features or use of this software 30 * must display the following acknowledgement: 31 * This product includes software developed by the NetBSD 32 * Foundation, Inc. and its contributors. 33 * 4. Neither the name of The NetBSD Foundation nor the names of its 34 * contributors may be used to endorse or promote products derived 35 * from this software without specific prior written permission. 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 38 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 39 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 40 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 41 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 42 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 43 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 44 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 45 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 47 * POSSIBILITY OF SUCH DAMAGE. 48 * 49 * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 50 * All rights reserved. 51 * 52 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 53 * 54 * Redistribution and use in source and binary forms, with or without 55 * modification, are permitted provided that the following conditions 56 * are met: 57 * 1. Redistributions of source code must retain the above copyright 58 * notice, this list of conditions and the following disclaimer. 59 * 2. Redistributions in binary form must reproduce the above copyright 60 * notice, this list of conditions and the following disclaimer in the 61 * documentation and/or other materials provided with the distribution. 62 * 3. All advertising materials mentioning features or use of this software 63 * must display the following acknowledgement: 64 * This product includes software developed for the NetBSD Project by 65 * Wasabi Systems, Inc. 66 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 67 * or promote products derived from this software without specific prior 68 * written permission. 69 * 70 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 71 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 72 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 73 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 74 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 75 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 76 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 77 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 78 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 79 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 80 * POSSIBILITY OF SUCH DAMAGE. 81 */ 82 83 #include <sys/cdefs.h> 84 __KERNEL_RCSID(0, "$NetBSD: gemini_timer.c,v 1.4 2010/01/05 13:14:56 mbalmer Exp $"); 85 86 #include "opt_gemini.h" 87 #include "opt_cpuoptions.h" 88 89 #include <sys/types.h> 90 #include <sys/param.h> 91 #include <sys/systm.h> 92 #include <sys/kernel.h> 93 #include <sys/time.h> 94 #include <sys/timetc.h> 95 #include <sys/device.h> 96 97 #include <dev/clock_subr.h> 98 99 #include <machine/bus.h> 100 #include <machine/intr.h> 101 102 #include <arm/cpufunc.h> 103 #include <arm/pic/picvar.h> 104 105 #include <arm/gemini/gemini_reg.h> 106 #include <arm/gemini/gemini_timervar.h> 107 #include <arm/gemini/gemini_timervar.h> 108 109 110 static const uint32_t counts_per_usec = (GEMINI_TIMER_CLOCK_FREQ / 1000000); 111 static uint32_t counts_per_hz = ~0; 112 113 struct geminitmr_softc *clock_sc; 114 struct geminitmr_softc *stat_sc; 115 struct geminitmr_softc *ref_sc; 116 static uint32_t gemini_get_timecount(struct timecounter *); 117 static void timer_init(geminitmr_softc_t *, int, boolean_t, boolean_t); 118 static void timer_factors(geminitmr_softc_t *, int, boolean_t); 119 120 #ifdef GEMINI_TIMER_DEBUG 121 static void tfprint(uint, timer_factors_t *); 122 #endif 123 124 static struct timecounter gemini_timecounter = { 125 .tc_get_timecount = gemini_get_timecount, 126 .tc_counter_mask = 0xffffffff, 127 .tc_frequency = GEMINI_TIMER_CLOCK_FREQ, 128 .tc_name = "gpt", 129 .tc_quality = 100, 130 .tc_priv = NULL 131 }; 132 133 static inline void 134 _timer_intr_dis(struct geminitmr_softc *sc) 135 { 136 uint32_t r; 137 138 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_INTRMASK); 139 r |= GEMINI_TIMERn_INTRMASK(sc->sc_timerno); 140 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_INTRMASK, r); 141 } 142 143 static inline void 144 _timer_intr_enb(struct geminitmr_softc *sc) 145 { 146 uint32_t r; 147 148 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_INTRMASK); 149 r &= ~TIMER_INTRMASK_TMnMATCH1(sc->sc_timerno); 150 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_INTRMASK, r); 151 } 152 153 static inline void 154 _timer_intr_clr(struct geminitmr_softc *sc) 155 { 156 uint32_t r; 157 int psw; 158 159 psw = disable_interrupts(I32_bit); 160 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_INTRSTATE); 161 r &= ~GEMINI_TIMERn_INTRMASK(sc->sc_timerno); 162 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_INTRSTATE, r); 163 restore_interrupts(psw); 164 } 165 166 static inline uint32_t 167 _timer_read(struct geminitmr_softc *sc) 168 { 169 uint32_t r; 170 171 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 172 GEMINI_TIMERn_COUNTER(sc->sc_timerno)); 173 174 return r; 175 } 176 177 static inline void 178 _timer_stop(struct geminitmr_softc *sc) 179 { 180 uint32_t r; 181 182 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_TMCR); 183 r &= ~GEMINI_TIMER_TMnCR_MASK(sc->sc_timerno); 184 } 185 186 /* 187 * note: 188 * This function assumes the timer is enabled. 189 * If the timer is disabled, GEMINI_TIMERn_COUNTER(n) will hold the value. 190 */ 191 static inline void 192 _timer_reload(struct geminitmr_softc *sc, uint32_t val) 193 { 194 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 195 GEMINI_TIMERn_COUNTER(sc->sc_timerno), val); 196 } 197 198 static inline void 199 _timer_start(struct geminitmr_softc *sc) 200 { 201 uint32_t r; 202 uint n = sc->sc_timerno; 203 timer_factors_t *tfp = &sc->sc_tf; 204 205 /* set Counter, TmLoad, Match1, Match2 */ 206 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 207 GEMINI_TIMERn_COUNTER(n), tfp->tf_counter); 208 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 209 GEMINI_TIMERn_LOAD(n), tfp->tf_reload); 210 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 211 GEMINI_TIMERn_MATCH1(n), tfp->tf_match1); 212 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 213 GEMINI_TIMERn_MATCH2(n), tfp->tf_match2); 214 215 /* set TmCR */ 216 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_TMCR); 217 r &= ~GEMINI_TIMER_TMnCR_MASK(n); 218 r |= tfp->tf_tmcr & GEMINI_TIMER_TMnCR_MASK(n); 219 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_TIMER_TMCR, r); 220 221 } 222 223 static uint32_t 224 gemini_get_timecount(struct timecounter *tc) 225 { 226 uint32_t r; 227 228 r = _timer_read(ref_sc); 229 230 return -r; 231 } 232 233 int 234 clockintr(void *frame) 235 { 236 struct geminitmr_softc *sc = clock_sc; 237 238 _timer_intr_clr(sc); 239 _timer_reload(sc, sc->sc_tf.tf_counter); 240 hardclock(frame); 241 if (clock_sc == stat_sc) 242 statclock(frame); 243 return 1; 244 } 245 246 int 247 statintr(void *frame) 248 { 249 struct geminitmr_softc *sc = stat_sc; 250 251 _timer_intr_clr(sc); 252 _timer_reload(sc, sc->sc_tf.tf_counter); 253 statclock(frame); 254 return 1; 255 } 256 257 static void 258 timer_init(geminitmr_softc_t *sc, int schz, boolean_t autoload, boolean_t intr) 259 { 260 int psw; 261 262 psw = disable_interrupts(I32_bit); 263 timer_factors(sc, schz, autoload); 264 _timer_stop(sc); 265 _timer_intr_dis(sc); 266 _timer_intr_clr(sc); 267 if (intr) 268 _timer_intr_enb(sc); 269 _timer_start(sc); 270 psw = disable_interrupts(I32_bit); 271 } 272 273 void 274 gemini_microtime_init(void) 275 { 276 if (ref_sc == NULL) 277 panic("microtime reference timer was not configured."); 278 timer_init(ref_sc, 0, TRUE, FALSE); 279 } 280 281 void 282 setstatclockrate(int schz) 283 { 284 if (stat_sc == NULL) 285 panic("Statistics timer was not configured."); 286 if (stat_sc != clock_sc) 287 timer_init(stat_sc, schz, FALSE, TRUE); 288 } 289 290 /* 291 * clock_sc and stat_sc starts here 292 * ref_sc is initialized already by obiotimer_attach 293 */ 294 void 295 cpu_initclocks(void) 296 { 297 if (clock_sc == NULL) 298 panic("Clock timer was not configured."); 299 if (stat_sc == NULL) 300 panic("Statistics timer was not configured."); 301 if (ref_sc == NULL) 302 panic("Microtime reference timer was not configured."); 303 304 /* 305 * We already have the timers running, but not generating interrupts. 306 * In addition, we've set stathz and profhz. 307 */ 308 printf("clock: hz=%d stathz=%d\n", hz, stathz); 309 310 /* 311 * The "cookie" parameter must be zero to pass the interrupt frame 312 * through to hardclock() and statclock(). 313 */ 314 intr_establish(clock_sc->sc_intr, IPL_CLOCK, IST_LEVEL_HIGH, 315 clockintr, 0); 316 317 if (clock_sc != stat_sc) 318 intr_establish(stat_sc->sc_intr, IPL_HIGH, IST_LEVEL_HIGH, 319 statintr, 0); 320 321 timer_init(clock_sc, hz, FALSE, TRUE); 322 if (clock_sc != stat_sc) 323 timer_init(stat_sc, stathz, FALSE, TRUE); 324 325 tc_init(&gemini_timecounter); 326 } 327 328 void 329 delay(u_int n) 330 { 331 struct geminitmr_softc *sc = ref_sc; 332 uint32_t cur, last, delta, usecs; 333 334 if (sc == NULL) 335 panic("The timer must be initialized sooner."); 336 337 /* 338 * This works by polling the timer and counting the 339 * number of microseconds that go by. 340 */ 341 last = _timer_read(sc); 342 343 delta = usecs = 0; 344 345 while (n > usecs) { 346 cur = _timer_read(sc); 347 348 /* Check to see if the timer has wrapped around. */ 349 if (last < cur) 350 delta += (last + (counts_per_hz - cur)); 351 else 352 delta += (last - cur); 353 354 last = cur; 355 356 if (delta >= counts_per_usec) { 357 usecs += delta / counts_per_usec; 358 delta %= counts_per_usec; 359 } 360 } 361 } 362 363 static void 364 timer_factors( 365 geminitmr_softc_t *sc, 366 int ints_per_sec, 367 boolean_t autoload) 368 { 369 timer_factors_t *tfp = &sc->sc_tf; 370 uint n = sc->sc_timerno; 371 const uint32_t us_per_sec = 1000000; 372 373 /* 374 * UPDOWN=0 (Down) 375 * OFENABLE=0 (no Irpt on overflow) 376 * CLOCK=0 (PCLK) 377 * ENABLE=1 378 */ 379 tfp->tf_tmcr = TIMER_TMCR_TMnENABLE(n); 380 381 if (ints_per_sec == 0) { 382 tfp->tf_counter = ~0U; 383 } else { 384 uint32_t count_freq; 385 386 count_freq = GEMINI_TIMER_CLOCK_FREQ; 387 count_freq /= ints_per_sec; 388 tfp->tf_counter = count_freq; 389 } 390 tfp->tf_counts_per_usec = GEMINI_TIMER_CLOCK_FREQ / us_per_sec; 391 392 if (autoload) 393 tfp->tf_reload = tfp->tf_counter; /* auto-reload */ 394 else 395 tfp->tf_reload = 0; /* no-auto_reload */ 396 397 tfp->tf_match1 = 0; 398 tfp->tf_match2 = 0; 399 400 #ifdef GEMINI_TIMER_DEBUG 401 tfprint(sc->sc_timerno, tfp); 402 Debugger(); 403 #endif 404 } 405 406 #ifdef GEMINI_TIMER_DEBUG 407 void 408 tfprint(uint n, timer_factors_t *tfp) 409 { 410 printf("%s: timer# %d\n", __FUNCTION__, n); 411 printf("\ttf_counts_per_usec: %#x\n", tfp->tf_counts_per_usec); 412 printf("\ttf_tmcr: %#x\n", tfp->tf_tmcr); 413 printf("\ttf_counter: %#x\n", tfp->tf_counter); 414 printf("\ttf_reload: %#x\n", tfp->tf_reload); 415 printf("\ttf_match1: %#x\n", tfp->tf_match1); 416 printf("\ttf_match2: %#x\n", tfp->tf_match2); 417 } 418 #endif 419