1193323Sed/* $NetBSD: i80321_timer.c,v 1.7 2003/07/27 04:52:28 thorpej Exp $ */ 2193323Sed 3193323Sed/*- 4193323Sed * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5193323Sed * All rights reserved. 6193323Sed * 7193323Sed * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8193323Sed * 9193323Sed * Redistribution and use in source and binary forms, with or without 10193323Sed * modification, are permitted provided that the following conditions 11193323Sed * are met: 12193323Sed * 1. Redistributions of source code must retain the above copyright 13193323Sed * notice, this list of conditions and the following disclaimer. 14193323Sed * 2. Redistributions in binary form must reproduce the above copyright 15193323Sed * notice, this list of conditions and the following disclaimer in the 16193323Sed * documentation and/or other materials provided with the distribution. 17193323Sed * 3. All advertising materials mentioning features or use of this software 18193323Sed * must display the following acknowledgement: 19193323Sed * This product includes software developed for the NetBSD Project by 20193323Sed * Wasabi Systems, Inc. 21193323Sed * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22193323Sed * or promote products derived from this software without specific prior 23198090Srdivacky * written permission. 24202375Srdivacky * 25193323Sed * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27193323Sed * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28193323Sed * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29193323Sed * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30198090Srdivacky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31198090Srdivacky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32207618Srdivacky * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33198090Srdivacky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34207618Srdivacky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35198090Srdivacky * POSSIBILITY OF SUCH DAMAGE. 36198090Srdivacky */ 37198090Srdivacky 38198090Srdivacky/* 39198090Srdivacky * Timer/clock support for the Intel i80321 I/O processor. 40193323Sed */ 41193323Sed 42193323Sed#include <sys/cdefs.h> 43193323Sed__FBSDID("$FreeBSD$"); 44193323Sed 45193323Sed#include <sys/param.h> 46193323Sed#include <sys/systm.h> 47193323Sed#include <sys/kernel.h> 48198090Srdivacky#include <sys/module.h> 49198090Srdivacky#include <sys/time.h> 50198090Srdivacky#include <sys/bus.h> 51198090Srdivacky#include <sys/resource.h> 52198090Srdivacky#include <sys/rman.h> 53198090Srdivacky#include <sys/timetc.h> 54198090Srdivacky 55198090Srdivacky#include <machine/bus.h> 56198090Srdivacky#include <machine/cpu.h> 57198090Srdivacky#include <machine/cpufunc.h> 58198090Srdivacky#include <machine/frame.h> 59198090Srdivacky#include <machine/resource.h> 60201360Srdivacky#include <machine/intr.h> 61198090Srdivacky#include <arm/xscale/i80321/i80321reg.h> 62198090Srdivacky#include <arm/xscale/i80321/i80321var.h> 63198090Srdivacky 64198090Srdivacky#ifdef CPU_XSCALE_81342 65198090Srdivacky#define ICU_INT_TIMER0 (8) /* XXX: Can't include i81342reg.h because 66198090Srdivacky definitions overrides the ones from i80321reg.h 67198090Srdivacky */ 68198090Srdivacky#endif 69198090Srdivacky#include "opt_timer.h" 70198090Srdivacky 71198090Srdivackyvoid (*i80321_hardclock_hook)(void) = NULL; 72198090Srdivackystruct i80321_timer_softc { 73198090Srdivacky device_t dev; 74198090Srdivacky} timer_softc; 75198090Srdivacky 76198090Srdivacky 77198090Srdivackystatic unsigned i80321_timer_get_timecount(struct timecounter *tc); 78198090Srdivacky 79198090Srdivacky 80198090Srdivackystatic uint32_t counts_per_hz; 81198090Srdivacky 82198090Srdivacky#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342) 83198090Srdivackystatic uint32_t offset; 84198090Srdivackystatic uint32_t last = -1; 85198090Srdivacky#endif 86198090Srdivacky 87198090Srdivackystatic int ticked = 0; 88198090Srdivacky 89198090Srdivacky#ifndef COUNTS_PER_SEC 90198090Srdivacky#define COUNTS_PER_SEC 200000000 /* 200MHz */ 91198090Srdivacky#endif 92198090Srdivacky 93198090Srdivacky#define COUNTS_PER_USEC (COUNTS_PER_SEC / 1000000) 94198090Srdivacky 95198090Srdivackystatic struct timecounter i80321_timer_timecounter = { 96198090Srdivacky i80321_timer_get_timecount, /* get_timecount */ 97198090Srdivacky NULL, /* no poll_pps */ 98198090Srdivacky ~0u, /* counter_mask */ 99198090Srdivacky#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342) 100198090Srdivacky COUNTS_PER_SEC, 101198090Srdivacky#else 102198090Srdivacky COUNTS_PER_SEC * 3, /* frequency */ 103198090Srdivacky#endif 104198090Srdivacky "i80321 timer", /* name */ 105198090Srdivacky 1000 /* quality */ 106198090Srdivacky}; 107198090Srdivacky 108198090Srdivackystatic int 109198090Srdivackyi80321_timer_probe(device_t dev) 110198090Srdivacky{ 111198090Srdivacky 112198090Srdivacky device_set_desc(dev, "i80321 timer"); 113198090Srdivacky return (0); 114198090Srdivacky} 115198090Srdivacky 116198090Srdivackystatic int 117198090Srdivackyi80321_timer_attach(device_t dev) 118198090Srdivacky{ 119198090Srdivacky timer_softc.dev = dev; 120198090Srdivacky 121198090Srdivacky return (0); 122198090Srdivacky} 123198090Srdivacky 124198090Srdivackystatic device_method_t i80321_timer_methods[] = { 125198090Srdivacky DEVMETHOD(device_probe, i80321_timer_probe), 126198090Srdivacky DEVMETHOD(device_attach, i80321_timer_attach), 127198090Srdivacky {0, 0}, 128198090Srdivacky}; 129198090Srdivacky 130198090Srdivackystatic driver_t i80321_timer_driver = { 131198090Srdivacky "itimer", 132198090Srdivacky i80321_timer_methods, 133198090Srdivacky sizeof(struct i80321_timer_softc), 134198090Srdivacky}; 135198090Srdivackystatic devclass_t i80321_timer_devclass; 136198090Srdivacky 137198090SrdivackyDRIVER_MODULE(itimer, iq, i80321_timer_driver, i80321_timer_devclass, 0, 0); 138198090Srdivacky 139198090Srdivackyint clockhandler(void *); 140198090Srdivacky 141198090Srdivacky 142198090Srdivackystatic __inline uint32_t 143198090Srdivackytmr1_read(void) 144198090Srdivacky{ 145198090Srdivacky uint32_t rv; 146198090Srdivacky 147198090Srdivacky#ifdef CPU_XSCALE_81342 148198090Srdivacky __asm __volatile("mrc p6, 0, %0, c1, c9, 0" 149198090Srdivacky#else 150198090Srdivacky __asm __volatile("mrc p6, 0, %0, c1, c1, 0" 151198090Srdivacky#endif 152198090Srdivacky : "=r" (rv)); 153198090Srdivacky return (rv); 154198090Srdivacky} 155198090Srdivacky 156198090Srdivackystatic __inline void 157198090Srdivackytmr1_write(uint32_t val) 158198090Srdivacky{ 159198090Srdivacky 160198090Srdivacky 161198090Srdivacky#ifdef CPU_XSCALE_81342 162198090Srdivacky __asm __volatile("mcr p6, 0, %0, c1, c9, 0" 163198090Srdivacky#else 164198090Srdivacky __asm __volatile("mcr p6, 0, %0, c1, c1, 0" 165198090Srdivacky#endif 166198090Srdivacky : 167198090Srdivacky : "r" (val)); 168198090Srdivacky} 169198090Srdivacky 170198090Srdivackystatic __inline uint32_t 171198090Srdivackytcr1_read(void) 172198090Srdivacky{ 173198090Srdivacky uint32_t rv; 174198090Srdivacky 175198090Srdivacky#ifdef CPU_XSCALE_81342 176198090Srdivacky __asm __volatile("mrc p6, 0, %0, c3, c9, 0" 177198090Srdivacky#else 178198090Srdivacky __asm __volatile("mrc p6, 0, %0, c3, c1, 0" 179198090Srdivacky#endif 180198090Srdivacky : "=r" (rv)); 181198090Srdivacky return (rv); 182198090Srdivacky} 183198090Srdivackystatic __inline void 184198090Srdivackytcr1_write(uint32_t val) 185198090Srdivacky{ 186198090Srdivacky 187198090Srdivacky#ifdef CPU_XSCALE_81342 188198090Srdivacky __asm __volatile("mcr p6, 0, %0, c3, c9, 0" 189198090Srdivacky#else 190198090Srdivacky __asm __volatile("mcr p6, 0, %0, c3, c1, 0" 191198090Srdivacky#endif 192198090Srdivacky : 193198090Srdivacky : "r" (val)); 194198090Srdivacky} 195198090Srdivacky 196198090Srdivackystatic __inline void 197198090Srdivackytrr1_write(uint32_t val) 198198090Srdivacky{ 199198090Srdivacky 200198090Srdivacky#ifdef CPU_XSCALE_81342 201198090Srdivacky __asm __volatile("mcr p6, 0, %0, c5, c9, 0" 202198090Srdivacky#else 203198090Srdivacky __asm __volatile("mcr p6, 0, %0, c5, c1, 0" 204198090Srdivacky#endif 205198090Srdivacky : 206198090Srdivacky : "r" (val)); 207198090Srdivacky} 208198090Srdivacky 209198090Srdivackystatic __inline uint32_t 210198090Srdivackytmr0_read(void) 211198090Srdivacky{ 212198090Srdivacky uint32_t rv; 213198090Srdivacky 214198090Srdivacky#ifdef CPU_XSCALE_81342 215198090Srdivacky __asm __volatile("mrc p6, 0, %0, c0, c9, 0" 216198090Srdivacky#else 217198090Srdivacky __asm __volatile("mrc p6, 0, %0, c0, c1, 0" 218198090Srdivacky#endif 219198090Srdivacky : "=r" (rv)); 220198090Srdivacky return (rv); 221198090Srdivacky} 222198090Srdivacky 223198090Srdivackystatic __inline void 224198090Srdivackytmr0_write(uint32_t val) 225198090Srdivacky{ 226198090Srdivacky 227198090Srdivacky#ifdef CPU_XSCALE_81342 228198090Srdivacky __asm __volatile("mcr p6, 0, %0, c0, c9, 0" 229198090Srdivacky#else 230198090Srdivacky __asm __volatile("mcr p6, 0, %0, c0, c1, 0" 231198090Srdivacky#endif 232198090Srdivacky : 233198090Srdivacky : "r" (val)); 234198090Srdivacky} 235198090Srdivacky 236198090Srdivackystatic __inline uint32_t 237198090Srdivackytcr0_read(void) 238198090Srdivacky{ 239198090Srdivacky uint32_t rv; 240198090Srdivacky 241198090Srdivacky#ifdef CPU_XSCALE_81342 242198090Srdivacky __asm __volatile("mrc p6, 0, %0, c2, c9, 0" 243198090Srdivacky#else 244198090Srdivacky __asm __volatile("mrc p6, 0, %0, c2, c1, 0" 245198090Srdivacky#endif 246198090Srdivacky : "=r" (rv)); 247199989Srdivacky return (rv); 248199989Srdivacky} 249199989Srdivackystatic __inline void 250199989Srdivackytcr0_write(uint32_t val) 251199989Srdivacky{ 252198090Srdivacky 253198090Srdivacky#ifdef CPU_XSCALE_81342 254198090Srdivacky __asm __volatile("mcr p6, 0, %0, c2, c9, 0" 255198090Srdivacky#else 256198090Srdivacky __asm __volatile("mcr p6, 0, %0, c2, c1, 0" 257198090Srdivacky#endif 258198090Srdivacky : 259198090Srdivacky : "r" (val)); 260198090Srdivacky} 261198090Srdivacky 262198090Srdivackystatic __inline void 263198090Srdivackytrr0_write(uint32_t val) 264198090Srdivacky{ 265198090Srdivacky 266205218Srdivacky#ifdef CPU_XSCALE_81342 267198090Srdivacky __asm __volatile("mcr p6, 0, %0, c4, c9, 0" 268198090Srdivacky#else 269210299Sed __asm __volatile("mcr p6, 0, %0, c4, c1, 0" 270198090Srdivacky#endif 271198090Srdivacky : 272199481Srdivacky : "r" (val)); 273199481Srdivacky} 274198090Srdivacky 275198090Srdivackystatic __inline void 276210299Sedtisr_write(uint32_t val) 277210299Sed{ 278210299Sed 279198090Srdivacky#ifdef CPU_XSCALE_81342 280198090Srdivacky __asm __volatile("mcr p6, 0, %0, c6, c9, 0" 281204961Srdivacky#else 282204961Srdivacky __asm __volatile("mcr p6, 0, %0, c6, c1, 0" 283204961Srdivacky#endif 284204961Srdivacky : 285204961Srdivacky : "r" (val)); 286204961Srdivacky} 287205218Srdivacky 288198090Srdivackystatic __inline uint32_t 289198090Srdivackytisr_read(void) 290198090Srdivacky{ 291198090Srdivacky int ret; 292198090Srdivacky 293198090Srdivacky#ifdef CPU_XSCALE_81342 294198090Srdivacky __asm __volatile("mrc p6, 0, %0, c6, c9, 0" : "=r" (ret)); 295198090Srdivacky#else 296198090Srdivacky __asm __volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret)); 297198090Srdivacky#endif 298198090Srdivacky return (ret); 299199481Srdivacky} 300199481Srdivacky 301199481Srdivackystatic unsigned 302199481Srdivackyi80321_timer_get_timecount(struct timecounter *tc) 303199481Srdivacky{ 304199481Srdivacky#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342) 305199481Srdivacky uint32_t cur = tcr0_read(); 306199481Srdivacky 307198396Srdivacky if (cur > last && last != -1) { 308198396Srdivacky offset += counts_per_hz; 309198396Srdivacky if (ticked > 0) 310198090Srdivacky ticked--; 311198090Srdivacky } 312198090Srdivacky if (ticked) { 313198090Srdivacky offset += ticked * counts_per_hz; 314198090Srdivacky ticked = 0; 315198090Srdivacky } 316198090Srdivacky return (counts_per_hz - cur + offset); 317198396Srdivacky#else 318198090Srdivacky uint32_t ret; 319198090Srdivacky 320198090Srdivacky __asm __volatile("mrc p14, 0, %0, c1, c0, 0\n" 321198090Srdivacky : "=r" (ret)); 322198090Srdivacky return (ret); 323198090Srdivacky#endif 324198090Srdivacky} 325200581Srdivacky 326198090Srdivacky/* 327198090Srdivacky * i80321_calibrate_delay: 328198090Srdivacky * 329200581Srdivacky * Calibrate the delay loop. 330200581Srdivacky */ 331198090Srdivackyvoid 332198090Srdivackyi80321_calibrate_delay(void) 333198090Srdivacky{ 334198090Srdivacky 335198090Srdivacky /* 336198090Srdivacky * Just use hz=100 for now -- we'll adjust it, if necessary, 337198090Srdivacky * in cpu_initclocks(). 338198090Srdivacky */ 339198090Srdivacky counts_per_hz = COUNTS_PER_SEC / 100; 340198090Srdivacky 341198090Srdivacky tmr0_write(0); /* stop timer */ 342198090Srdivacky tisr_write(TISR_TMR0); /* clear interrupt */ 343198090Srdivacky trr0_write(counts_per_hz); /* reload value */ 344198090Srdivacky tcr0_write(counts_per_hz); /* current value */ 345198090Srdivacky 346198090Srdivacky tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); 347198090Srdivacky} 348198090Srdivacky 349198090Srdivacky/* 350198090Srdivacky * cpu_initclocks: 351198090Srdivacky * 352198090Srdivacky * Initialize the clock and get them going. 353198090Srdivacky */ 354198090Srdivackyvoid 355198090Srdivackycpu_initclocks(void) 356198090Srdivacky{ 357198090Srdivacky u_int oldirqstate; 358198090Srdivacky struct resource *irq; 359198090Srdivacky int rid = 0; 360198090Srdivacky void *ihl; 361198090Srdivacky device_t dev = timer_softc.dev; 362198090Srdivacky 363198090Srdivacky if (hz < 50 || COUNTS_PER_SEC % hz) { 364198090Srdivacky printf("Cannot get %d Hz clock; using 100 Hz\n", hz); 365198090Srdivacky hz = 100; 366198090Srdivacky } 367198090Srdivacky tick = 1000000 / hz; /* number of microseconds between interrupts */ 368198090Srdivacky 369198090Srdivacky /* 370198090Srdivacky * We only have one timer available; stathz and profhz are 371198090Srdivacky * always left as 0 (the upper-layer clock code deals with 372198090Srdivacky * this situation). 373198090Srdivacky */ 374198090Srdivacky if (stathz != 0) 375198090Srdivacky printf("Cannot get %d Hz statclock\n", stathz); 376198090Srdivacky stathz = 0; 377198090Srdivacky 378198090Srdivacky if (profhz != 0) 379198090Srdivacky printf("Cannot get %d Hz profclock\n", profhz); 380198090Srdivacky profhz = 0; 381198090Srdivacky 382198090Srdivacky /* Report the clock frequency. */ 383198090Srdivacky 384198090Srdivacky oldirqstate = disable_interrupts(I32_bit); 385198090Srdivacky 386198090Srdivacky irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 387198090Srdivacky#ifdef CPU_XSCALE_81342 388198090Srdivacky ICU_INT_TIMER0, ICU_INT_TIMER0, 389198090Srdivacky#else 390198090Srdivacky ICU_INT_TMR0, ICU_INT_TMR0, 391198090Srdivacky#endif 392198090Srdivacky 1, RF_ACTIVE); 393198090Srdivacky if (!irq) 394202375Srdivacky panic("Unable to setup the clock irq handler.\n"); 395202375Srdivacky else 396202375Srdivacky bus_setup_intr(dev, irq, INTR_TYPE_CLK, clockhandler, NULL, 397202375Srdivacky NULL, &ihl); 398193323Sed tmr0_write(0); /* stop timer */ 399193323Sed tisr_write(TISR_TMR0); /* clear interrupt */ 400193323Sed 401193323Sed counts_per_hz = COUNTS_PER_SEC / hz; 402193323Sed 403195340Sed trr0_write(counts_per_hz); /* reload value */ 404193323Sed tcr0_write(counts_per_hz); /* current value */ 405193323Sed tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); 406193323Sed 407198090Srdivacky tc_init(&i80321_timer_timecounter); 408198090Srdivacky restore_interrupts(oldirqstate); 409198090Srdivacky rid = 0; 410198090Srdivacky#if !defined(XSCALE_DISABLE_CCNT) && !defined(CPU_XSCALE_81342) 411198090Srdivacky /* Enable the clock count register. */ 412198090Srdivacky __asm __volatile("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (rid)); 413198090Srdivacky rid &= ~(1 << 3); 414198090Srdivacky rid |= (1 << 2) | 1; 415198090Srdivacky __asm __volatile("mcr p14, 0, %0, c0, c0, 0\n" 416198090Srdivacky : : "r" (rid)); 417198090Srdivacky#endif 418198090Srdivacky} 419198090Srdivacky 420198090Srdivacky 421198090Srdivacky/* 422198090Srdivacky * DELAY: 423198090Srdivacky * 424193323Sed * Delay for at least N microseconds. 425193323Sed */ 426193323Sedvoid 427193323SedDELAY(int n) 428198090Srdivacky{ 429198090Srdivacky uint32_t cur, last, delta, usecs; 430198090Srdivacky 431198090Srdivacky /* 432198090Srdivacky * This works by polling the timer and counting the 433 * number of microseconds that go by. 434 */ 435 last = tcr0_read(); 436 delta = usecs = 0; 437 438 while (n > usecs) { 439 cur = tcr0_read(); 440 441 /* Check to see if the timer has wrapped around. */ 442 if (last < cur) 443 delta += (last + (counts_per_hz - cur)); 444 else 445 delta += (last - cur); 446 447 last = cur; 448 449 if (delta >= COUNTS_PER_USEC) { 450 usecs += delta / COUNTS_PER_USEC; 451 delta %= COUNTS_PER_USEC; 452 } 453 } 454} 455 456/* 457 * clockhandler: 458 * 459 * Handle the hardclock interrupt. 460 */ 461int 462clockhandler(void *arg) 463{ 464 struct trapframe *frame = arg; 465 466 ticked++; 467 tisr_write(TISR_TMR0); 468 hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); 469 470 if (i80321_hardclock_hook != NULL) 471 (*i80321_hardclock_hook)(); 472 return (FILTER_HANDLED); 473} 474 475void 476cpu_startprofclock(void) 477{ 478} 479 480void 481cpu_stopprofclock(void) 482{ 483 484} 485