1 /* $NetBSD: gemini_timer.c,v 1.1 2008/10/24 04:23:18 matt 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.1 2008/10/24 04:23:18 matt 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 return 1; 242 } 243 244 int 245 statintr(void *frame) 246 { 247 struct geminitmr_softc *sc = stat_sc;; 248 249 _timer_intr_clr(sc); 250 _timer_reload(sc, sc->sc_tf.tf_counter); 251 statclock(frame); 252 return 1; 253 } 254 255 static void 256 timer_init(geminitmr_softc_t *sc, int schz, boolean_t autoload, boolean_t intr) 257 { 258 int psw; 259 260 psw = disable_interrupts(I32_bit); 261 timer_factors(sc, schz, autoload); 262 _timer_stop(sc); 263 _timer_intr_dis(sc); 264 _timer_intr_clr(sc); 265 if (intr) 266 _timer_intr_enb(sc); 267 _timer_start(sc); 268 psw = disable_interrupts(I32_bit); 269 } 270 271 void 272 gemini_microtime_init() 273 { 274 if (ref_sc == NULL) 275 panic("microtime reference timer was not configured."); 276 timer_init(ref_sc, 0, TRUE, FALSE); 277 } 278 279 void 280 setstatclockrate(int schz) 281 { 282 if (stat_sc == NULL) 283 panic("Statistics timer was not configured."); 284 timer_init(stat_sc, schz, FALSE, TRUE); 285 } 286 287 /* 288 * clock_sc and stat_sc starts here 289 * ref_sc is initialized already by obiotimer_attach 290 */ 291 void 292 cpu_initclocks(void) 293 { 294 if (clock_sc == NULL) 295 panic("Clock timer was not configured."); 296 if (stat_sc == NULL) 297 panic("Statistics timer was not configured."); 298 if (ref_sc == NULL) 299 panic("Microtime reference timer was not configured."); 300 301 /* 302 * We already have the timers running, but not generating interrupts. 303 * In addition, we've set stathz and profhz. 304 */ 305 printf("clock: hz=%d stathz=%d\n", hz, stathz); 306 307 /* 308 * The "cookie" parameter must be zero to pass the interrupt frame 309 * through to hardclock() and statclock(). 310 */ 311 intr_establish(clock_sc->sc_intr, IPL_CLOCK, IST_LEVEL_HIGH, 312 clockintr, 0); 313 314 intr_establish(stat_sc->sc_intr, IPL_HIGH, IST_LEVEL_HIGH, 315 statintr, 0); 316 317 timer_init(clock_sc, hz, FALSE, TRUE); 318 timer_init(stat_sc, stathz, FALSE, TRUE); 319 320 tc_init(&gemini_timecounter); 321 } 322 323 void 324 delay(u_int n) 325 { 326 struct geminitmr_softc *sc = ref_sc; 327 uint32_t cur, last, delta, usecs; 328 329 if (sc == NULL) 330 panic("The timer must be initialized sooner."); 331 332 /* 333 * This works by polling the timer and counting the 334 * number of microseconds that go by. 335 */ 336 last = _timer_read(sc); 337 338 delta = usecs = 0; 339 340 while (n > usecs) { 341 cur = _timer_read(sc); 342 343 /* Check to see if the timer has wrapped around. */ 344 if (last < cur) 345 delta += (last + (counts_per_hz - cur)); 346 else 347 delta += (last - cur); 348 349 last = cur; 350 351 if (delta >= counts_per_usec) { 352 usecs += delta / counts_per_usec; 353 delta %= counts_per_usec; 354 } 355 } 356 } 357 358 static void 359 timer_factors( 360 geminitmr_softc_t *sc, 361 int ints_per_sec, 362 boolean_t autoload) 363 { 364 timer_factors_t *tfp = &sc->sc_tf; 365 uint n = sc->sc_timerno; 366 const uint32_t us_per_sec = 1000000; 367 368 /* 369 * UPDOWN=0 (Down) 370 * OFENABLE=0 (no Irpt on overflow) 371 * CLOCK=0 (PCLK) 372 * ENABLE=1 373 */ 374 tfp->tf_tmcr = TIMER_TMCR_TMnENABLE(n); 375 376 if (ints_per_sec == 0) { 377 tfp->tf_counter = ~0U; 378 } else { 379 uint32_t count_freq; 380 381 count_freq = GEMINI_TIMER_CLOCK_FREQ; 382 count_freq /= ints_per_sec; 383 tfp->tf_counter = count_freq; 384 } 385 tfp->tf_counts_per_usec = GEMINI_TIMER_CLOCK_FREQ / us_per_sec; 386 387 if (autoload) 388 tfp->tf_reload = tfp->tf_counter; /* auto-reload */ 389 else 390 tfp->tf_reload = 0; /* no-auto_reload */ 391 392 tfp->tf_match1 = 0; 393 tfp->tf_match2 = 0; 394 395 #ifdef GEMINI_TIMER_DEBUG 396 tfprint(sc->sc_timerno, tfp); 397 Debugger(); 398 #endif 399 } 400 401 #ifdef GEMINI_TIMER_DEBUG 402 void 403 tfprint(uint n, timer_factors_t *tfp) 404 { 405 printf("%s: timer# %d\n", __FUNCTION__, n); 406 printf("\ttf_counts_per_usec: %#x\n", tfp->tf_counts_per_usec); 407 printf("\ttf_tmcr: %#x\n", tfp->tf_tmcr); 408 printf("\ttf_counter: %#x\n", tfp->tf_counter); 409 printf("\ttf_reload: %#x\n", tfp->tf_reload); 410 printf("\ttf_match1: %#x\n", tfp->tf_match1); 411 printf("\ttf_match2: %#x\n", tfp->tf_match2); 412 } 413 #endif 414