1/* $NetBSD: omap2_mputmr.c,v 1.3 2010/06/19 19:44:58 matt Exp $ */ 2 3/* 4 * OMAP 2430 GP timers 5 */ 6 7/* 8 * Based on i80321_timer.c and arch/arm/sa11x0/sa11x0_ost.c 9 * 10 * Copyright (c) 1997 Mark Brinicombe. 11 * Copyright (c) 1997 Causality Limited. 12 * All rights reserved. 13 * 14 * This code is derived from software contributed to The NetBSD Foundation 15 * by IWAMOTO Toshihiro and Ichiro FUKUHARA. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the NetBSD 28 * Foundation, Inc. and its contributors. 29 * 4. Neither the name of The NetBSD Foundation nor the names of its 30 * contributors may be used to endorse or promote products derived 31 * from this software without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 34 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 35 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 37 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 38 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 39 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 40 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 41 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 * POSSIBILITY OF SUCH DAMAGE. 44 * 45 * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 46 * All rights reserved. 47 * 48 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 1. Redistributions of source code must retain the above copyright 54 * notice, this list of conditions and the following disclaimer. 55 * 2. Redistributions in binary form must reproduce the above copyright 56 * notice, this list of conditions and the following disclaimer in the 57 * documentation and/or other materials provided with the distribution. 58 * 3. All advertising materials mentioning features or use of this software 59 * must display the following acknowledgement: 60 * This product includes software developed for the NetBSD Project by 61 * Wasabi Systems, Inc. 62 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 63 * or promote products derived from this software without specific prior 64 * written permission. 65 * 66 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 67 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 68 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 69 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 70 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 71 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 72 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 73 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 74 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 75 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 76 * POSSIBILITY OF SUCH DAMAGE. 77 */ 78 79#include <sys/cdefs.h> 80__KERNEL_RCSID(0, "$NetBSD: omap2_mputmr.c,v 1.3 2010/06/19 19:44:58 matt Exp $"); 81 82#include "opt_omap.h" 83#include "opt_cpuoptions.h" 84 85#include <sys/types.h> 86#include <sys/param.h> 87#include <sys/systm.h> 88#include <sys/kernel.h> 89#include <sys/time.h> 90#include <sys/timetc.h> 91#include <sys/device.h> 92 93#include <dev/clock_subr.h> 94 95#include <sys/bus.h> 96#include <machine/intr.h> 97 98#include <arm/omap/omap_gptmrreg.h> 99#include <arm/omap/omap2_mputmrvar.h> 100 101#ifndef ARM11_PMC 102uint32_t counts_per_usec, counts_per_hz; 103#endif 104struct mputmr_softc *clock_sc; 105struct mputmr_softc *stat_sc; 106struct mputmr_softc *ref_sc; 107static uint32_t mpu_get_timecount(struct timecounter *); 108 109static struct timecounter mpu_timecounter = { 110 .tc_get_timecount = mpu_get_timecount, 111 .tc_counter_mask = 0xffffffff, 112 .tc_frequency = OMAP_MPU_TIMER_CLOCK_FREQ, 113 .tc_name = "gpt", 114 .tc_quality = 100, 115 .tc_priv = NULL 116}; 117 118static inline void 119_timer_intr_dis(struct mputmr_softc *sc) 120{ 121 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIER, 0); 122} 123 124static inline void 125_timer_intr_enb(struct mputmr_softc *sc) 126{ 127 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIER, TIER_OVF_IT_ENA); 128} 129 130static inline uint32_t 131_timer_intr_sts(struct mputmr_softc *sc) 132{ 133 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, TISR); 134} 135 136static inline void 137_timer_intr_ack(struct mputmr_softc *sc) 138{ 139 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TISR, TIER_OVF_IT_ENA); 140} 141 142static inline uint32_t 143_timer_read(struct mputmr_softc *sc) 144{ 145 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, TCRR); 146} 147 148static inline void 149_timer_stop(struct mputmr_softc *sc) 150{ 151 uint32_t r; 152 153 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TCLR); 154 r &= ~TCLR_ST; 155 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCLR, r); 156} 157 158static inline void 159_timer_reload(struct mputmr_softc *sc, uint32_t val) 160{ 161 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TLDR, val); 162 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCRR, val); 163} 164 165static inline void 166_timer_start(struct mputmr_softc *sc, timer_factors *tfp) 167{ 168 uint32_t r=0; 169 170 if (tfp->ptv != 0) { 171 r |= TCLR_PRE(1); 172 r |= (TCLR_PTV(tfp->ptv - 1) & TCLR_PTV_MASK); 173 } 174 r |= (TCLR_CE | TCLR_AR | TCLR_ST); 175 176 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCLR, r); 177} 178 179static uint32_t 180mpu_get_timecount(struct timecounter *tc) 181{ 182 return _timer_read(ref_sc); 183} 184 185int 186clockintr(void *frame) 187{ 188 _timer_intr_ack(clock_sc); 189 hardclock(frame); 190 return 1; 191} 192 193int 194statintr(void *frame) 195{ 196 _timer_intr_ack(stat_sc); 197 statclock(frame); 198 return 1; 199} 200 201static void 202setclockrate(struct mputmr_softc *sc, int schz) 203{ 204 timer_factors tf; 205 206 _timer_stop(sc); 207 calc_timer_factors(schz, &tf); 208 _timer_reload(sc, tf.reload); 209 _timer_start(sc, &tf); 210} 211 212void 213setstatclockrate(int schz) 214{ 215 setclockrate(stat_sc, schz); 216} 217 218void 219cpu_initclocks(void) 220{ 221 if (clock_sc == NULL) 222 panic("Clock timer was not configured."); 223 if (stat_sc == NULL) 224 panic("Statistics timer was not configured."); 225 if (ref_sc == NULL) 226 panic("Microtime reference timer was not configured."); 227 228 /* 229 * We already have the timers running, but not generating interrupts. 230 * In addition, we've set stathz and profhz. 231 */ 232 printf("clock: hz=%d stathz=%d\n", hz, stathz); 233 234 _timer_intr_dis(clock_sc); 235 _timer_intr_dis(stat_sc); 236 _timer_intr_dis(ref_sc); 237 238 setclockrate(clock_sc, hz); 239 setclockrate(stat_sc, stathz); 240 setclockrate(ref_sc, 0); 241 242 243 /* 244 * The "cookie" parameter must be zero to pass the interrupt frame 245 * through to hardclock() and statclock(). 246 */ 247 248 intr_establish(clock_sc->sc_intr, IPL_CLOCK, IST_LEVEL, clockintr, 0); 249 intr_establish(stat_sc->sc_intr, IPL_HIGH, IST_LEVEL, statintr, 0); 250 251 _timer_intr_enb(clock_sc); 252 _timer_intr_enb(stat_sc); 253 254 tc_init(&mpu_timecounter); 255} 256 257#if !(defined(ARM11_PMC) || defined(CORTEX_PMC)) 258void 259delay(u_int n) 260{ 261 uint32_t cur, last, delta, usecs; 262 263 if (clock_sc == NULL) 264 panic("The timer must be initialized sooner."); 265 266 /* 267 * This works by polling the timer and counting the 268 * number of microseconds that go by. 269 */ 270 last = _timer_read(clock_sc); 271 272 delta = usecs = 0; 273 274 while (n > usecs) { 275 cur = _timer_read(clock_sc); 276 277 /* Check to see if the timer has wrapped around. */ 278 if (last < cur) 279 delta += (last + (counts_per_hz - cur)); 280 else 281 delta += (last - cur); 282 283 last = cur; 284 285 if (delta >= counts_per_usec) { 286 usecs += delta / counts_per_usec; 287 delta %= counts_per_usec; 288 } 289 } 290} 291#endif /* ARM11_PMC || CORTEX_PMC */ 292 293/* 294 * OVF_Rate = 295 * (0xFFFFFFFF - GPTn.TLDR + 1) * (timer functional clock period) * PS 296 */ 297void 298calc_timer_factors(int ints_per_sec, timer_factors *tf) 299{ 300 uint32_t ptv_power; /* PS */ 301 uint32_t count_freq; 302 const uint32_t us_per_sec = 1000000; 303 304 if (ints_per_sec == 0) { 305 /* 306 * When ints_per_sec equal to zero there is mean full range 307 * timer usage. Nevertheless autoreload mode is still enabled. 308 */ 309 tf->ptv = 0; 310 tf->reload = 0; 311 tf->counts_per_usec = OMAP_MPU_TIMER_CLOCK_FREQ / us_per_sec; 312 return; 313 } 314 315 316 tf->ptv = 8; 317 for (;;) { 318 ptv_power = 1 << tf->ptv; 319 count_freq = OMAP_MPU_TIMER_CLOCK_FREQ; 320 count_freq /= hz; 321 count_freq /= ptv_power; 322 tf->reload = -count_freq; 323 tf->counts_per_usec = count_freq / us_per_sec; 324 if ((tf->reload * ptv_power * ints_per_sec 325 == OMAP_MPU_TIMER_CLOCK_FREQ) 326 && (tf->counts_per_usec * ptv_power * us_per_sec 327 == OMAP_MPU_TIMER_CLOCK_FREQ)) 328 { /* Exact match. Life is good. */ 329 /* Currently reload is MPU_LOAD_TIMER+1. Fix it. */ 330 tf->reload--; 331 return; 332 } 333 if (tf->ptv == 0) { 334 tf->counts_per_usec++; 335 return; 336 } 337 tf->ptv--; 338 } 339} 340