1178172Simp/*- 2178172Simp * Copyright (c) 2006-2007 Bruce M. Simpson. 3178172Simp * Copyright (c) 2003-2004 Juli Mallett. 4178172Simp * All rights reserved. 5178172Simp * 6178172Simp * Redistribution and use in source and binary forms, with or without 7178172Simp * modification, are permitted provided that the following conditions 8178172Simp * are met: 9178172Simp * 1. Redistributions of source code must retain the above copyright 10178172Simp * notice, this list of conditions and the following disclaimer. 11178172Simp * 2. Redistributions in binary form must reproduce the above copyright 12178172Simp * notice, this list of conditions and the following disclaimer in the 13178172Simp * documentation and/or other materials provided with the distribution. 14178172Simp * 15178172Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18178172Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19178172Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25178172Simp * SUCH DAMAGE. 26178172Simp */ 27178172Simp 28178172Simp/* 29178172Simp * Simple driver for the 32-bit interval counter built in to all 30178172Simp * MIPS32 CPUs. 31178172Simp */ 32178172Simp 33178172Simp#include <sys/cdefs.h> 34178172Simp__FBSDID("$FreeBSD$"); 35178172Simp 36178172Simp#include <sys/param.h> 37178172Simp#include <sys/systm.h> 38178172Simp#include <sys/sysctl.h> 39178172Simp#include <sys/bus.h> 40178172Simp#include <sys/kernel.h> 41178172Simp#include <sys/module.h> 42178172Simp#include <sys/rman.h> 43178172Simp#include <sys/power.h> 44178172Simp#include <sys/smp.h> 45178172Simp#include <sys/time.h> 46210403Smav#include <sys/timeet.h> 47178172Simp#include <sys/timetc.h> 48178172Simp 49203746Sneel#include <machine/hwfunc.h> 50178172Simp#include <machine/clock.h> 51178172Simp#include <machine/locore.h> 52178172Simp#include <machine/md_var.h> 53178172Simp 54178172Simpuint64_t counter_freq; 55178172Simp 56205364Sneelstruct timecounter *platform_timecounter; 57205364Sneel 58215701Sdimstatic DPCPU_DEFINE(uint32_t, cycles_per_tick); 59210403Smavstatic uint32_t cycles_per_usec; 60178172Simp 61215701Sdimstatic DPCPU_DEFINE(volatile uint32_t, counter_upper); 62215701Sdimstatic DPCPU_DEFINE(volatile uint32_t, counter_lower_last); 63215701Sdimstatic DPCPU_DEFINE(uint32_t, compare_ticks); 64215701Sdimstatic DPCPU_DEFINE(uint32_t, lost_ticks); 65178172Simp 66210403Smavstruct clock_softc { 67210403Smav int intr_rid; 68210403Smav struct resource *intr_res; 69210403Smav void *intr_handler; 70210403Smav struct timecounter tc; 71210403Smav struct eventtimer et; 72210403Smav}; 73210403Smavstatic struct clock_softc *softc; 74210403Smav 75178172Simp/* 76178172Simp * Device methods 77178172Simp */ 78178172Simpstatic int clock_probe(device_t); 79178172Simpstatic void clock_identify(driver_t *, device_t); 80178172Simpstatic int clock_attach(device_t); 81178172Simpstatic unsigned counter_get_timecount(struct timecounter *tc); 82178172Simp 83178172Simpvoid 84178172Simpmips_timer_early_init(uint64_t clock_hz) 85178172Simp{ 86178172Simp /* Initialize clock early so that we can use DELAY sooner */ 87178172Simp counter_freq = clock_hz; 88178172Simp cycles_per_usec = (clock_hz / (1000 * 1000)); 89178172Simp} 90178172Simp 91178172Simpvoid 92202046Simpplatform_initclocks(void) 93178172Simp{ 94203746Sneel 95205364Sneel if (platform_timecounter != NULL) 96205364Sneel tc_init(platform_timecounter); 97178172Simp} 98178172Simp 99178172Simpstatic uint64_t 100178172Simptick_ticker(void) 101178172Simp{ 102178172Simp uint64_t ret; 103178172Simp uint32_t ticktock; 104210854Sneel uint32_t t_lower_last, t_upper; 105178172Simp 106178172Simp /* 107210854Sneel * Disable preemption because we are working with cpu specific data. 108178172Simp */ 109210854Sneel critical_enter(); 110210854Sneel 111210854Sneel /* 112210854Sneel * Note that even though preemption is disabled, interrupts are 113210854Sneel * still enabled. In particular there is a race with clock_intr() 114210854Sneel * reading the values of 'counter_upper' and 'counter_lower_last'. 115210854Sneel * 116210854Sneel * XXX this depends on clock_intr() being executed periodically 117210854Sneel * so that 'counter_upper' and 'counter_lower_last' are not stale. 118210854Sneel */ 119210854Sneel do { 120210854Sneel t_upper = DPCPU_GET(counter_upper); 121210854Sneel t_lower_last = DPCPU_GET(counter_lower_last); 122210854Sneel } while (t_upper != DPCPU_GET(counter_upper)); 123210854Sneel 124178172Simp ticktock = mips_rd_count(); 125210854Sneel 126178172Simp critical_exit(); 127178172Simp 128210854Sneel /* COUNT register wrapped around */ 129210854Sneel if (ticktock < t_lower_last) 130210854Sneel t_upper++; 131210854Sneel 132210854Sneel ret = ((uint64_t)t_upper << 32) | ticktock; 133178172Simp return (ret); 134178172Simp} 135178172Simp 136178172Simpvoid 137178172Simpmips_timer_init_params(uint64_t platform_counter_freq, int double_count) 138178172Simp{ 139178172Simp 140178172Simp /* 141178172Simp * XXX: Do not use printf here: uart code 8250 may use DELAY so this 142178172Simp * function should be called before cninit. 143178172Simp */ 144178172Simp counter_freq = platform_counter_freq; 145202046Simp /* 146202046Simp * XXX: Some MIPS32 cores update the Count register only every two 147202046Simp * pipeline cycles. 148202797Simp * We know this because of status registers in CP0, make it automatic. 149202046Simp */ 150202046Simp if (double_count != 0) 151202046Simp counter_freq /= 2; 152202046Simp 153178172Simp cycles_per_usec = counter_freq / (1 * 1000 * 1000); 154178172Simp set_cputicker(tick_ticker, counter_freq, 1); 155178172Simp} 156178172Simp 157178172Simpstatic int 158178172Simpsysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS) 159178172Simp{ 160178172Simp int error; 161178172Simp uint64_t freq; 162178172Simp 163210403Smav if (softc == NULL) 164178172Simp return (EOPNOTSUPP); 165178172Simp freq = counter_freq; 166217616Smdf error = sysctl_handle_64(oidp, &freq, sizeof(freq), req); 167178172Simp if (error == 0 && req->newptr != NULL) { 168178172Simp counter_freq = freq; 169210403Smav softc->et.et_frequency = counter_freq; 170210403Smav softc->tc.tc_frequency = counter_freq; 171178172Simp } 172178172Simp return (error); 173178172Simp} 174178172Simp 175217616SmdfSYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_U64 | CTLFLAG_RW, 176217616Smdf NULL, 0, sysctl_machdep_counter_freq, "QU", 177181236Strhodes "Timecounter frequency in Hz"); 178178172Simp 179178172Simpstatic unsigned 180178172Simpcounter_get_timecount(struct timecounter *tc) 181178172Simp{ 182178172Simp 183178172Simp return (mips_rd_count()); 184178172Simp} 185178172Simp 186178172Simp/* 187178172Simp * Wait for about n microseconds (at least!). 188178172Simp */ 189178172Simpvoid 190178172SimpDELAY(int n) 191178172Simp{ 192178172Simp uint32_t cur, last, delta, usecs; 193178172Simp 194178172Simp /* 195178172Simp * This works by polling the timer and counting the number of 196178172Simp * microseconds that go by. 197178172Simp */ 198178172Simp last = mips_rd_count(); 199178172Simp delta = usecs = 0; 200178172Simp 201178172Simp while (n > usecs) { 202178172Simp cur = mips_rd_count(); 203178172Simp 204178172Simp /* Check to see if the timer has wrapped around. */ 205178172Simp if (cur < last) 206202046Simp delta += cur + (0xffffffff - last) + 1; 207178172Simp else 208202046Simp delta += cur - last; 209178172Simp 210178172Simp last = cur; 211178172Simp 212178172Simp if (delta >= cycles_per_usec) { 213178172Simp usecs += delta / cycles_per_usec; 214178172Simp delta %= cycles_per_usec; 215178172Simp } 216178172Simp } 217178172Simp} 218178172Simp 219210403Smavstatic int 220247463Smavclock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 221210403Smav{ 222210403Smav uint32_t fdiv, div, next; 223210403Smav 224247463Smav if (period != 0) { 225247463Smav div = (et->et_frequency * period) >> 32; 226210403Smav } else 227210403Smav div = 0; 228247463Smav if (first != 0) 229247463Smav fdiv = (et->et_frequency * first) >> 32; 230247463Smav else 231210403Smav fdiv = div; 232210403Smav DPCPU_SET(cycles_per_tick, div); 233210403Smav next = mips_rd_count() + fdiv; 234210403Smav DPCPU_SET(compare_ticks, next); 235210403Smav mips_wr_compare(next); 236210403Smav return (0); 237210403Smav} 238210403Smav 239210403Smavstatic int 240210403Smavclock_stop(struct eventtimer *et) 241210403Smav{ 242210403Smav 243210403Smav DPCPU_SET(cycles_per_tick, 0); 244210403Smav mips_wr_compare(0xffffffff); 245210403Smav return (0); 246210403Smav} 247210403Smav 248178172Simp/* 249178172Simp * Device section of file below 250178172Simp */ 251178172Simpstatic int 252178172Simpclock_intr(void *arg) 253178172Simp{ 254210403Smav struct clock_softc *sc = (struct clock_softc *)arg; 255210403Smav uint32_t cycles_per_tick; 256208585Sneel uint32_t count, compare_last, compare_next, lost_ticks; 257205576Sneel 258210403Smav cycles_per_tick = DPCPU_GET(cycles_per_tick); 259178172Simp /* 260178172Simp * Set next clock edge. 261178172Simp */ 262205576Sneel count = mips_rd_count(); 263208585Sneel compare_last = DPCPU_GET(compare_ticks); 264210403Smav if (cycles_per_tick > 0) { 265210403Smav compare_next = count + cycles_per_tick; 266210403Smav DPCPU_SET(compare_ticks, compare_next); 267210403Smav mips_wr_compare(compare_next); 268210404Smav } else /* In one-shot mode timer should be stopped after the event. */ 269210403Smav mips_wr_compare(0xffffffff); 270208585Sneel 271210854Sneel /* COUNT register wrapped around */ 272210854Sneel if (count < DPCPU_GET(counter_lower_last)) { 273210854Sneel DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1); 274178172Simp } 275210854Sneel DPCPU_SET(counter_lower_last, count); 276208585Sneel 277210403Smav if (cycles_per_tick > 0) { 278178172Simp 279210403Smav /* 280210403Smav * Account for the "lost time" between when the timer interrupt 281210403Smav * fired and when 'clock_intr' actually started executing. 282210403Smav */ 283210403Smav lost_ticks = DPCPU_GET(lost_ticks); 284210403Smav lost_ticks += count - compare_last; 285210403Smav 286210403Smav /* 287210403Smav * If the COUNT and COMPARE registers are no longer in sync 288210403Smav * then make up some reasonable value for the 'lost_ticks'. 289210403Smav * 290210403Smav * This could happen, for e.g., after we resume normal 291210403Smav * operations after exiting the debugger. 292210403Smav */ 293210403Smav if (lost_ticks > 2 * cycles_per_tick) 294210403Smav lost_ticks = cycles_per_tick; 295205576Sneel 296210403Smav while (lost_ticks >= cycles_per_tick) { 297210403Smav if (sc->et.et_active) 298210403Smav sc->et.et_event_cb(&sc->et, sc->et.et_arg); 299210403Smav lost_ticks -= cycles_per_tick; 300210403Smav } 301210403Smav DPCPU_SET(lost_ticks, lost_ticks); 302208585Sneel } 303210403Smav if (sc->et.et_active) 304210403Smav sc->et.et_event_cb(&sc->et, sc->et.et_arg); 305178172Simp return (FILTER_HANDLED); 306178172Simp} 307178172Simp 308178172Simpstatic int 309178172Simpclock_probe(device_t dev) 310178172Simp{ 311178172Simp 312178172Simp if (device_get_unit(dev) != 0) 313178172Simp panic("can't attach more clocks"); 314178172Simp 315178172Simp device_set_desc(dev, "Generic MIPS32 ticker"); 316265999Sian return (BUS_PROBE_NOWILDCARD); 317178172Simp} 318178172Simp 319178172Simpstatic void 320178172Simpclock_identify(driver_t * drv, device_t parent) 321178172Simp{ 322178172Simp 323178172Simp BUS_ADD_CHILD(parent, 0, "clock", 0); 324178172Simp} 325178172Simp 326178172Simpstatic int 327178172Simpclock_attach(device_t dev) 328178172Simp{ 329210403Smav struct clock_softc *sc; 330178172Simp int error; 331178172Simp 332210403Smav softc = sc = device_get_softc(dev); 333210403Smav sc->intr_rid = 0; 334210403Smav sc->intr_res = bus_alloc_resource(dev, 335210403Smav SYS_RES_IRQ, &sc->intr_rid, 5, 5, 1, RF_ACTIVE); 336210403Smav if (sc->intr_res == NULL) { 337178172Simp device_printf(dev, "failed to allocate irq\n"); 338178172Simp return (ENXIO); 339178172Simp } 340210403Smav error = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK, 341210403Smav clock_intr, NULL, sc, &sc->intr_handler); 342178172Simp if (error != 0) { 343178172Simp device_printf(dev, "bus_setup_intr returned %d\n", error); 344178172Simp return (error); 345178172Simp } 346202046Simp 347210403Smav sc->tc.tc_get_timecount = counter_get_timecount; 348210403Smav sc->tc.tc_counter_mask = 0xffffffff; 349210403Smav sc->tc.tc_frequency = counter_freq; 350210403Smav sc->tc.tc_name = "MIPS32"; 351210403Smav sc->tc.tc_quality = 800; 352210403Smav sc->tc.tc_priv = sc; 353210403Smav tc_init(&sc->tc); 354210403Smav sc->et.et_name = "MIPS32"; 355210403Smav sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | 356210403Smav ET_FLAGS_PERCPU; 357210403Smav sc->et.et_quality = 800; 358210403Smav sc->et.et_frequency = counter_freq; 359247463Smav sc->et.et_min_period = 0x00004000LLU; /* To be safe. */ 360247463Smav sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 361210403Smav sc->et.et_start = clock_start; 362210403Smav sc->et.et_stop = clock_stop; 363210403Smav sc->et.et_priv = sc; 364210403Smav et_register(&sc->et); 365178172Simp return (0); 366178172Simp} 367178172Simp 368178172Simpstatic device_method_t clock_methods[] = { 369178172Simp /* Device interface */ 370178172Simp DEVMETHOD(device_probe, clock_probe), 371178172Simp DEVMETHOD(device_identify, clock_identify), 372178172Simp DEVMETHOD(device_attach, clock_attach), 373178172Simp DEVMETHOD(device_detach, bus_generic_detach), 374178172Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 375178172Simp 376178172Simp {0, 0} 377178172Simp}; 378178172Simp 379178172Simpstatic driver_t clock_driver = { 380210403Smav "clock", 381210403Smav clock_methods, 382210403Smav sizeof(struct clock_softc), 383178172Simp}; 384178172Simp 385178172Simpstatic devclass_t clock_devclass; 386178172Simp 387178172SimpDRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0); 388