1 /* $NetBSD: iq80310_timer.c,v 1.11 2002/04/14 19:47:03 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Timer/clock support for the Intel IQ80310. 40 * 41 * The IQ80310 has a 22-bit reloadable timer implemented in the CPLD. 42 * We use it to provide a hardclock interrupt. There is no RTC on 43 * the IQ80310. 44 * 45 * The timer uses the SPCI clock. The timer uses the 33MHz clock by 46 * reading the SPCI_66EN signal and dividing the clock if necessary. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/kernel.h> 52 #include <sys/time.h> 53 54 #include <machine/bus.h> 55 #include <arm/cpufunc.h> 56 57 #include <evbarm/iq80310/iq80310reg.h> 58 #include <evbarm/iq80310/iq80310var.h> 59 #include <evbarm/iq80310/obiovar.h> 60 61 /* 62 * Some IQ80310-based designs have fewer bits in the timer counter. 63 * Deal with them here. 64 */ 65 #if defined(IOP310_TEAMASA_NPWR) 66 #define COUNTER_MASK 0x0007ffff 67 #else /* Default to stock IQ80310 */ 68 #define COUNTER_MASK 0x003fffff 69 #endif /* list of IQ80310-based designs */ 70 71 #define COUNTS_PER_SEC 33000000 /* 33MHz */ 72 #define COUNTS_PER_USEC (COUNTS_PER_SEC / 1000000) 73 74 static void *clock_ih; 75 76 static uint32_t counts_per_hz; 77 78 int clockhandler(void *); 79 80 static __inline void 81 timer_enable(uint8_t bit) 82 { 83 84 CPLD_WRITE(IQ80310_TIMER_ENABLE, 85 CPLD_READ(IQ80310_TIMER_ENABLE) | bit); 86 } 87 88 static __inline void 89 timer_disable(uint8_t bit) 90 { 91 92 CPLD_WRITE(IQ80310_TIMER_ENABLE, 93 CPLD_READ(IQ80310_TIMER_ENABLE) & ~bit); 94 } 95 96 static __inline uint32_t 97 timer_read(void) 98 { 99 uint32_t rv; 100 uint8_t la0, la1, la2, la3; 101 102 /* 103 * First read latches count. 104 * 105 * From RedBoot: harware bug that causes invalid counts to be 106 * latched. The loop appears to work around the problem. 107 */ 108 do { 109 la0 = CPLD_READ(IQ80310_TIMER_LA0); 110 } while (la0 == 0); 111 la1 = CPLD_READ(IQ80310_TIMER_LA1); 112 la2 = CPLD_READ(IQ80310_TIMER_LA2); 113 la3 = CPLD_READ(IQ80310_TIMER_LA3); 114 115 rv = ((la0 & 0x40) >> 1) | (la0 & 0x1f); 116 rv |= (((la1 & 0x40) >> 1) | (la1 & 0x1f)) << 6; 117 rv |= (((la2 & 0x40) >> 1) | (la2 & 0x1f)) << 12; 118 rv |= (la3 & 0x0f) << 18; 119 120 return (rv); 121 } 122 123 static __inline void 124 timer_write(uint32_t x) 125 { 126 127 KASSERT((x & COUNTER_MASK) == x); 128 129 CPLD_WRITE(IQ80310_TIMER_LA0, x & 0xff); 130 CPLD_WRITE(IQ80310_TIMER_LA1, (x >> 8) & 0xff); 131 CPLD_WRITE(IQ80310_TIMER_LA2, (x >> 16) & 0x3f); 132 } 133 134 /* 135 * iq80310_calibrate_delay: 136 * 137 * Calibrate the delay loop. 138 */ 139 void 140 iq80310_calibrate_delay(void) 141 { 142 143 /* 144 * We'll use the CPLD timer for delay(), as well. We go 145 * ahead and start it up now, just don't enable interrupts 146 * until cpu_initclocks(). 147 * 148 * Just use hz=100 for now -- we'll adjust it, if necessary, 149 * in cpu_initclocks(). 150 */ 151 counts_per_hz = COUNTS_PER_SEC / 100; 152 153 timer_disable(TIMER_ENABLE_INTEN); 154 timer_disable(TIMER_ENABLE_EN); 155 156 timer_write(counts_per_hz); 157 158 timer_enable(TIMER_ENABLE_EN); 159 } 160 161 /* 162 * cpu_initclocks: 163 * 164 * Initialize the clock and get them going. 165 */ 166 void 167 cpu_initclocks(void) 168 { 169 u_int oldirqstate; 170 171 if (hz < 50 || COUNTS_PER_SEC % hz) { 172 printf("Cannot get %d Hz clock; using 100 Hz\n", hz); 173 hz = 100; 174 } 175 tick = 1000000 / hz; /* number of microseconds between interrupts */ 176 tickfix = 1000000 - (hz * tick); 177 if (tickfix) { 178 int ftp; 179 180 ftp = min(ffs(tickfix), ffs(hz)); 181 tickfix >>= (ftp - 1); 182 tickfixinterval = hz >> (ftp - 1); 183 } 184 185 /* 186 * We only have one timer available; stathz and profhz are 187 * always left as 0 (the upper-layer clock code deals with 188 * this situation). 189 */ 190 if (stathz != 0) 191 printf("Cannot get %d Hz statclock\n", stathz); 192 stathz = 0; 193 194 if (profhz != 0) 195 printf("Cannot get %d Hz profclock\n", profhz); 196 profhz = 0; 197 198 /* Report the clock frequency. */ 199 printf("clock: hz=%d stathz=%d profhz=%d\n", hz, stathz, profhz); 200 201 /* Hook up the clock interrupt handler. */ 202 clock_ih = iq80310_intr_establish(XINT3_IRQ(XINT3_TIMER), IPL_CLOCK, 203 clockhandler, NULL); 204 if (clock_ih == NULL) 205 panic("cpu_initclocks: unable to register timer interrupt"); 206 207 /* Set up the new clock parameters. */ 208 oldirqstate = disable_interrupts(I32_bit); 209 210 timer_disable(TIMER_ENABLE_EN); 211 212 counts_per_hz = COUNTS_PER_SEC / hz; 213 timer_write(counts_per_hz); 214 215 timer_enable(TIMER_ENABLE_INTEN); 216 timer_enable(TIMER_ENABLE_EN); 217 218 restore_interrupts(oldirqstate); 219 } 220 221 /* 222 * setstatclockrate: 223 * 224 * Set the rate of the statistics clock. 225 * 226 * We assume that hz is either stathz or profhz, and that neither 227 * will change after being set by cpu_initclocks(). We could 228 * recalculate the intervals here, but that would be a pain. 229 */ 230 void 231 setstatclockrate(int hz) 232 { 233 234 /* 235 * Nothing to do, here; we can't change the statclock 236 * rate on the IQ80310. 237 */ 238 } 239 240 /* 241 * microtime: 242 * 243 * Fill in the specified timeval struct with the current time 244 * accurate to the microsecond. 245 */ 246 void 247 microtime(struct timeval *tvp) 248 { 249 static struct timeval lasttv; 250 u_int oldirqstate; 251 uint32_t counts; 252 253 oldirqstate = disable_interrupts(I32_bit); 254 255 counts = timer_read(); 256 257 /* Fill in the timeval struct. */ 258 *tvp = time; 259 tvp->tv_usec += (counts / COUNTS_PER_USEC); 260 261 /* Make sure microseconds doesn't overflow. */ 262 while (tvp->tv_usec >= 1000000) { 263 tvp->tv_usec -= 1000000; 264 tvp->tv_sec++; 265 } 266 267 /* Make sure the time has advanced. */ 268 if (tvp->tv_sec == lasttv.tv_sec && 269 tvp->tv_usec <= lasttv.tv_usec) { 270 tvp->tv_usec = lasttv.tv_usec + 1; 271 if (tvp->tv_usec >= 1000000) { 272 tvp->tv_usec -= 1000000; 273 tvp->tv_sec++; 274 } 275 } 276 277 lasttv = *tvp; 278 279 restore_interrupts(oldirqstate); 280 } 281 282 /* 283 * delay: 284 * 285 * Delay for at least N microseconds. 286 */ 287 void 288 delay(u_int n) 289 { 290 uint32_t cur, last, delta, usecs; 291 292 /* 293 * This works by polling the timer and counting the 294 * number of microseconds that go by. 295 */ 296 last = timer_read(); 297 delta = usecs = 0; 298 299 while (n > usecs) { 300 cur = timer_read(); 301 302 /* Check to see if the timer has wrapped around. */ 303 if (cur < last) 304 delta += ((counts_per_hz - last) + cur); 305 else 306 delta += (cur - last); 307 308 last = cur; 309 310 if (delta >= COUNTS_PER_USEC) { 311 usecs += delta / COUNTS_PER_USEC; 312 delta %= COUNTS_PER_USEC; 313 } 314 } 315 } 316 317 /* 318 * inittodr: 319 * 320 * Initialize time from the time-of-day register. 321 */ 322 void 323 inittodr(time_t base) 324 { 325 326 time.tv_sec = base; 327 time.tv_usec = 0; 328 } 329 330 /* 331 * resettodr: 332 * 333 * Reset the time-of-day register with the current time. 334 */ 335 void 336 resettodr(void) 337 { 338 } 339 340 /* 341 * clockhandler: 342 * 343 * Handle the hardclock interrupt. 344 */ 345 int 346 clockhandler(void *arg) 347 { 348 struct clockframe *frame = arg; 349 350 timer_disable(TIMER_ENABLE_INTEN); 351 timer_enable(TIMER_ENABLE_INTEN); 352 353 hardclock(frame); 354 355 /* 356 * Don't run the snake on IOP310-based systems that 357 * don't have the 7-segment display. 358 */ 359 #if !defined(IOP310_TEAMASA_NPWR) 360 { 361 static int snakefreq; 362 363 if ((snakefreq++ & 15) == 0) 364 iq80310_7seg_snake(); 365 } 366 #endif 367 368 return (1); 369 } 370