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