Home | History | Annotate | Line # | Download | only in gemini
      1 /*	$NetBSD: gemini_timer.c,v 1.7 2014/03/18 12:54:29 martin 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.7 2014/03/18 12:54:29 martin 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 <sys/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 	restore_interrupts(psw);
    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