1 1.22 maxv /* $NetBSD: i80321_timer.c,v 1.22 2018/07/12 10:46:42 maxv Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 thorpej * 9 1.1 thorpej * Redistribution and use in source and binary forms, with or without 10 1.1 thorpej * modification, are permitted provided that the following conditions 11 1.1 thorpej * are met: 12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer. 14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 16 1.1 thorpej * documentation and/or other materials provided with the distribution. 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed for the NetBSD Project by 20 1.1 thorpej * Wasabi Systems, Inc. 21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 thorpej * or promote products derived from this software without specific prior 23 1.1 thorpej * written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 36 1.1 thorpej */ 37 1.1 thorpej 38 1.1 thorpej /* 39 1.1 thorpej * Timer/clock support for the Intel i80321 I/O processor. 40 1.1 thorpej */ 41 1.5 lukem 42 1.5 lukem #include <sys/cdefs.h> 43 1.22 maxv __KERNEL_RCSID(0, "$NetBSD: i80321_timer.c,v 1.22 2018/07/12 10:46:42 maxv Exp $"); 44 1.1 thorpej 45 1.8 rearnsha #include "opt_i80321.h" 46 1.2 briggs 47 1.1 thorpej #include <sys/param.h> 48 1.1 thorpej #include <sys/systm.h> 49 1.1 thorpej #include <sys/kernel.h> 50 1.1 thorpej #include <sys/time.h> 51 1.15 gavan #include <sys/timetc.h> 52 1.1 thorpej 53 1.6 thorpej #include <dev/clock_subr.h> 54 1.6 thorpej 55 1.20 dyoung #include <sys/bus.h> 56 1.1 thorpej #include <arm/cpufunc.h> 57 1.1 thorpej 58 1.1 thorpej #include <arm/xscale/i80321reg.h> 59 1.1 thorpej #include <arm/xscale/i80321var.h> 60 1.1 thorpej 61 1.1 thorpej void (*i80321_hardclock_hook)(void); 62 1.1 thorpej 63 1.8 rearnsha #ifndef COUNTS_PER_SEC 64 1.1 thorpej #define COUNTS_PER_SEC 200000000 /* 200MHz */ 65 1.8 rearnsha #endif 66 1.1 thorpej #define COUNTS_PER_USEC (COUNTS_PER_SEC / 1000000) 67 1.1 thorpej 68 1.15 gavan static void tmr1_tc_init(void); 69 1.15 gavan 70 1.1 thorpej static void *clock_ih; 71 1.1 thorpej 72 1.1 thorpej static uint32_t counts_per_hz; 73 1.1 thorpej 74 1.1 thorpej int clockhandler(void *); 75 1.1 thorpej 76 1.21 joerg __unused static inline uint32_t 77 1.1 thorpej tmr0_read(void) 78 1.1 thorpej { 79 1.1 thorpej uint32_t rv; 80 1.1 thorpej 81 1.13 perry __asm volatile("mrc p6, 0, %0, c0, c1, 0" 82 1.1 thorpej : "=r" (rv)); 83 1.1 thorpej return (rv); 84 1.1 thorpej } 85 1.1 thorpej 86 1.13 perry static inline void 87 1.1 thorpej tmr0_write(uint32_t val) 88 1.1 thorpej { 89 1.1 thorpej 90 1.13 perry __asm volatile("mcr p6, 0, %0, c0, c1, 0" 91 1.1 thorpej : 92 1.1 thorpej : "r" (val)); 93 1.1 thorpej } 94 1.1 thorpej 95 1.13 perry static inline uint32_t 96 1.1 thorpej tcr0_read(void) 97 1.1 thorpej { 98 1.1 thorpej uint32_t rv; 99 1.1 thorpej 100 1.13 perry __asm volatile("mrc p6, 0, %0, c2, c1, 0" 101 1.1 thorpej : "=r" (rv)); 102 1.1 thorpej return (rv); 103 1.1 thorpej } 104 1.1 thorpej 105 1.13 perry static inline void 106 1.1 thorpej tcr0_write(uint32_t val) 107 1.1 thorpej { 108 1.1 thorpej 109 1.13 perry __asm volatile("mcr p6, 0, %0, c2, c1, 0" 110 1.1 thorpej : 111 1.1 thorpej : "r" (val)); 112 1.1 thorpej } 113 1.1 thorpej 114 1.13 perry static inline void 115 1.1 thorpej trr0_write(uint32_t val) 116 1.1 thorpej { 117 1.1 thorpej 118 1.13 perry __asm volatile("mcr p6, 0, %0, c4, c1, 0" 119 1.1 thorpej : 120 1.1 thorpej : "r" (val)); 121 1.1 thorpej } 122 1.1 thorpej 123 1.21 joerg __unused static inline uint32_t 124 1.15 gavan tmr1_read(void) 125 1.15 gavan { 126 1.15 gavan uint32_t rv; 127 1.15 gavan 128 1.15 gavan __asm volatile("mrc p6, 0, %0, c1, c1, 0" 129 1.15 gavan : "=r" (rv)); 130 1.15 gavan return (rv); 131 1.15 gavan } 132 1.15 gavan 133 1.15 gavan static inline void 134 1.15 gavan tmr1_write(uint32_t val) 135 1.15 gavan { 136 1.15 gavan 137 1.15 gavan __asm volatile("mcr p6, 0, %0, c1, c1, 0" 138 1.15 gavan : 139 1.15 gavan : "r" (val)); 140 1.15 gavan } 141 1.15 gavan 142 1.15 gavan static inline uint32_t 143 1.15 gavan tcr1_read(void) 144 1.15 gavan { 145 1.15 gavan uint32_t rv; 146 1.15 gavan 147 1.15 gavan __asm volatile("mrc p6, 0, %0, c3, c1, 0" 148 1.15 gavan : "=r" (rv)); 149 1.15 gavan return (rv); 150 1.15 gavan } 151 1.15 gavan 152 1.15 gavan static inline void 153 1.15 gavan tcr1_write(uint32_t val) 154 1.15 gavan { 155 1.15 gavan 156 1.15 gavan __asm volatile("mcr p6, 0, %0, c3, c1, 0" 157 1.15 gavan : 158 1.15 gavan : "r" (val)); 159 1.15 gavan } 160 1.15 gavan 161 1.15 gavan static inline void 162 1.15 gavan trr1_write(uint32_t val) 163 1.15 gavan { 164 1.15 gavan 165 1.15 gavan __asm volatile("mcr p6, 0, %0, c5, c1, 0" 166 1.15 gavan : 167 1.15 gavan : "r" (val)); 168 1.15 gavan } 169 1.15 gavan 170 1.13 perry static inline void 171 1.1 thorpej tisr_write(uint32_t val) 172 1.1 thorpej { 173 1.1 thorpej 174 1.13 perry __asm volatile("mcr p6, 0, %0, c6, c1, 0" 175 1.1 thorpej : 176 1.1 thorpej : "r" (val)); 177 1.1 thorpej } 178 1.1 thorpej 179 1.1 thorpej /* 180 1.1 thorpej * i80321_calibrate_delay: 181 1.1 thorpej * 182 1.1 thorpej * Calibrate the delay loop. 183 1.1 thorpej */ 184 1.1 thorpej void 185 1.1 thorpej i80321_calibrate_delay(void) 186 1.1 thorpej { 187 1.1 thorpej 188 1.1 thorpej /* 189 1.1 thorpej * Just use hz=100 for now -- we'll adjust it, if necessary, 190 1.1 thorpej * in cpu_initclocks(). 191 1.1 thorpej */ 192 1.1 thorpej counts_per_hz = COUNTS_PER_SEC / 100; 193 1.1 thorpej 194 1.1 thorpej tmr0_write(0); /* stop timer */ 195 1.1 thorpej tisr_write(TISR_TMR0); /* clear interrupt */ 196 1.1 thorpej trr0_write(counts_per_hz); /* reload value */ 197 1.1 thorpej tcr0_write(counts_per_hz); /* current value */ 198 1.1 thorpej 199 1.1 thorpej tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); 200 1.1 thorpej } 201 1.1 thorpej 202 1.1 thorpej /* 203 1.1 thorpej * cpu_initclocks: 204 1.1 thorpej * 205 1.1 thorpej * Initialize the clock and get them going. 206 1.1 thorpej */ 207 1.1 thorpej void 208 1.1 thorpej cpu_initclocks(void) 209 1.1 thorpej { 210 1.1 thorpej u_int oldirqstate; 211 1.1 thorpej 212 1.1 thorpej if (hz < 50 || COUNTS_PER_SEC % hz) { 213 1.4 thorpej aprint_error("Cannot get %d Hz clock; using 100 Hz\n", hz); 214 1.1 thorpej hz = 100; 215 1.1 thorpej } 216 1.1 thorpej 217 1.1 thorpej /* 218 1.1 thorpej * We only have one timer available; stathz and profhz are 219 1.1 thorpej * always left as 0 (the upper-layer clock code deals with 220 1.1 thorpej * this situation). 221 1.1 thorpej */ 222 1.1 thorpej if (stathz != 0) 223 1.4 thorpej aprint_error("Cannot get %d Hz statclock\n", stathz); 224 1.1 thorpej stathz = 0; 225 1.1 thorpej 226 1.1 thorpej if (profhz != 0) 227 1.4 thorpej aprint_error("Cannot get %d Hz profclock\n", profhz); 228 1.1 thorpej profhz = 0; 229 1.1 thorpej 230 1.1 thorpej /* Report the clock frequency. */ 231 1.4 thorpej aprint_normal("clock: hz=%d stathz=%d profhz=%d\n", hz, stathz, profhz); 232 1.1 thorpej 233 1.1 thorpej oldirqstate = disable_interrupts(I32_bit); 234 1.1 thorpej 235 1.1 thorpej /* Hook up the clock interrupt handler. */ 236 1.1 thorpej clock_ih = i80321_intr_establish(ICU_INT_TMR0, IPL_CLOCK, 237 1.1 thorpej clockhandler, NULL); 238 1.1 thorpej if (clock_ih == NULL) 239 1.1 thorpej panic("cpu_initclocks: unable to register timer interrupt"); 240 1.2 briggs 241 1.1 thorpej /* Set up the new clock parameters. */ 242 1.1 thorpej 243 1.1 thorpej tmr0_write(0); /* stop timer */ 244 1.1 thorpej tisr_write(TISR_TMR0); /* clear interrupt */ 245 1.1 thorpej 246 1.1 thorpej counts_per_hz = COUNTS_PER_SEC / hz; 247 1.1 thorpej 248 1.1 thorpej trr0_write(counts_per_hz); /* reload value */ 249 1.1 thorpej tcr0_write(counts_per_hz); /* current value */ 250 1.1 thorpej 251 1.1 thorpej tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); 252 1.1 thorpej 253 1.1 thorpej restore_interrupts(oldirqstate); 254 1.15 gavan 255 1.15 gavan tmr1_tc_init(); 256 1.1 thorpej } 257 1.1 thorpej 258 1.1 thorpej /* 259 1.1 thorpej * setstatclockrate: 260 1.1 thorpej * 261 1.1 thorpej * Set the rate of the statistics clock. 262 1.1 thorpej * 263 1.1 thorpej * We assume that hz is either stathz or profhz, and that neither 264 1.1 thorpej * will change after being set by cpu_initclocks(). We could 265 1.1 thorpej * recalculate the intervals here, but that would be a pain. 266 1.1 thorpej */ 267 1.1 thorpej void 268 1.11 he setstatclockrate(int newhz) 269 1.1 thorpej { 270 1.1 thorpej 271 1.1 thorpej /* 272 1.1 thorpej * XXX Use TMR1? 273 1.1 thorpej */ 274 1.1 thorpej } 275 1.1 thorpej 276 1.15 gavan static inline uint32_t 277 1.15 gavan tmr1_tc_get(struct timecounter *tch) 278 1.15 gavan { 279 1.15 gavan return (~tcr1_read()); 280 1.15 gavan } 281 1.15 gavan 282 1.15 gavan void 283 1.15 gavan tmr1_tc_init(void) 284 1.15 gavan { 285 1.15 gavan static struct timecounter tmr1_tc = { 286 1.15 gavan .tc_get_timecount = tmr1_tc_get, 287 1.15 gavan .tc_frequency = COUNTS_PER_SEC, 288 1.15 gavan .tc_counter_mask = ~0, 289 1.15 gavan .tc_name = "tmr1_count", 290 1.15 gavan .tc_quality = 100, 291 1.15 gavan }; 292 1.15 gavan 293 1.15 gavan /* program the tc */ 294 1.15 gavan trr1_write(~0); /* reload value */ 295 1.15 gavan tcr1_write(~0); /* current value */ 296 1.15 gavan 297 1.15 gavan tmr1_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); 298 1.15 gavan 299 1.15 gavan 300 1.15 gavan trr1_write(~0); 301 1.15 gavan tc_init(&tmr1_tc); 302 1.15 gavan } 303 1.15 gavan 304 1.1 thorpej /* 305 1.1 thorpej * delay: 306 1.1 thorpej * 307 1.1 thorpej * Delay for at least N microseconds. 308 1.1 thorpej */ 309 1.1 thorpej void 310 1.1 thorpej delay(u_int n) 311 1.1 thorpej { 312 1.1 thorpej uint32_t cur, last, delta, usecs; 313 1.1 thorpej 314 1.1 thorpej /* 315 1.1 thorpej * This works by polling the timer and counting the 316 1.1 thorpej * number of microseconds that go by. 317 1.1 thorpej */ 318 1.1 thorpej last = tcr0_read(); 319 1.1 thorpej delta = usecs = 0; 320 1.1 thorpej 321 1.1 thorpej while (n > usecs) { 322 1.1 thorpej cur = tcr0_read(); 323 1.1 thorpej 324 1.1 thorpej /* Check to see if the timer has wrapped around. */ 325 1.1 thorpej if (last < cur) 326 1.1 thorpej delta += (last + (counts_per_hz - cur)); 327 1.1 thorpej else 328 1.1 thorpej delta += (last - cur); 329 1.1 thorpej 330 1.1 thorpej last = cur; 331 1.1 thorpej 332 1.1 thorpej if (delta >= COUNTS_PER_USEC) { 333 1.1 thorpej usecs += delta / COUNTS_PER_USEC; 334 1.1 thorpej delta %= COUNTS_PER_USEC; 335 1.1 thorpej } 336 1.1 thorpej } 337 1.1 thorpej } 338 1.1 thorpej 339 1.1 thorpej /* 340 1.1 thorpej * clockhandler: 341 1.1 thorpej * 342 1.1 thorpej * Handle the hardclock interrupt. 343 1.1 thorpej */ 344 1.1 thorpej int 345 1.1 thorpej clockhandler(void *arg) 346 1.1 thorpej { 347 1.1 thorpej struct clockframe *frame = arg; 348 1.1 thorpej 349 1.1 thorpej tisr_write(TISR_TMR0); 350 1.1 thorpej 351 1.1 thorpej hardclock(frame); 352 1.1 thorpej 353 1.1 thorpej if (i80321_hardclock_hook != NULL) 354 1.1 thorpej (*i80321_hardclock_hook)(); 355 1.1 thorpej 356 1.1 thorpej return (1); 357 1.1 thorpej } 358