1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $ 34 */ 35 /* 36 * Copyright (C) 2001 Benno Rice. 37 * All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 */ 59 60 #include <sys/cdefs.h> 61 __FBSDID("$FreeBSD$"); 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/kernel.h> 66 #include <sys/bus.h> 67 #include <sys/interrupt.h> 68 #include <sys/pcpu.h> 69 #include <sys/sysctl.h> 70 #include <sys/timeet.h> 71 #include <sys/timetc.h> 72 73 #include <dev/ofw/openfirm.h> 74 75 #include <machine/clock.h> 76 #include <machine/cpu.h> 77 #include <machine/intr_machdep.h> 78 #include <machine/md_var.h> 79 #include <machine/smp.h> 80 81 /* 82 * Initially we assume a processor with a bus frequency of 12.5 MHz. 83 */ 84 static int initialized = 0; 85 static uint64_t ps_per_tick = 80000; 86 static u_long ticks_per_sec = 12500000; 87 static u_long *decr_counts[MAXCPU]; 88 89 static int decr_et_start(struct eventtimer *et, 90 sbintime_t first, sbintime_t period); 91 static int decr_et_stop(struct eventtimer *et); 92 static timecounter_get_t decr_get_timecount; 93 94 struct decr_state { 95 int mode; /* 0 - off, 1 - periodic, 2 - one-shot. */ 96 int32_t div; /* Periodic divisor. */ 97 }; 98 DPCPU_DEFINE_STATIC(struct decr_state, decr_state); 99 100 static struct eventtimer decr_et; 101 static struct timecounter decr_tc = { 102 decr_get_timecount, /* get_timecount */ 103 0, /* no poll_pps */ 104 ~0u, /* counter_mask */ 105 0, /* frequency */ 106 "timebase" /* name */ 107 }; 108 109 /* 110 * Decrementer interrupt handler. 111 */ 112 void 113 decr_intr(struct trapframe *frame) 114 { 115 struct decr_state *s = DPCPU_PTR(decr_state); 116 int nticks = 0; 117 int32_t val; 118 119 if (!initialized) 120 return; 121 122 (*decr_counts[curcpu])++; 123 124 #ifdef BOOKE 125 /* 126 * Interrupt handler must reset DIS to avoid getting another 127 * interrupt once EE is enabled. 128 */ 129 mtspr(SPR_TSR, TSR_DIS); 130 #endif 131 132 if (s->mode == 1) { 133 /* 134 * Based on the actual time delay since the last decrementer 135 * reload, we arrange for earlier interrupt next time. 136 */ 137 __asm ("mfdec %0" : "=r"(val)); 138 while (val < 0) { 139 val += s->div; 140 nticks++; 141 } 142 mtdec(val); 143 } else if (s->mode == 2) { 144 nticks = 1; 145 decr_et_stop(NULL); 146 } else if (s->mode == 0) { 147 /* Potemkin timer ran out without an event. Just reset it. */ 148 decr_et_stop(NULL); 149 } 150 151 while (nticks-- > 0) { 152 if (decr_et.et_active) 153 decr_et.et_event_cb(&decr_et, decr_et.et_arg); 154 } 155 } 156 157 void 158 cpu_initclocks(void) 159 { 160 161 decr_tc_init(); 162 cpu_initclocks_bsp(); 163 } 164 165 /* 166 * BSP early initialization. 167 */ 168 void 169 decr_init(void) 170 { 171 struct cpuref cpu; 172 char buf[32]; 173 174 /* 175 * Check the BSP's timebase frequency. Sometimes we can't find the BSP, 176 * so fall back to the first CPU in this case. 177 */ 178 if (platform_smp_get_bsp(&cpu) != 0) 179 platform_smp_first_cpu(&cpu); 180 ticks_per_sec = platform_timebase_freq(&cpu); 181 ps_per_tick = 1000000000000 / ticks_per_sec; 182 183 set_cputicker(mftb, ticks_per_sec, 0); 184 snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); 185 intrcnt_add(buf, &decr_counts[curcpu]); 186 decr_et_stop(NULL); 187 initialized = 1; 188 } 189 190 #ifdef SMP 191 /* 192 * AP early initialization. 193 */ 194 void 195 decr_ap_init(void) 196 { 197 char buf[32]; 198 199 snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); 200 intrcnt_add(buf, &decr_counts[curcpu]); 201 decr_et_stop(NULL); 202 } 203 #endif 204 205 /* 206 * Final initialization. 207 */ 208 void 209 decr_tc_init(void) 210 { 211 212 decr_tc.tc_frequency = ticks_per_sec; 213 tc_init(&decr_tc); 214 decr_et.et_name = "decrementer"; 215 decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | 216 ET_FLAGS_PERCPU; 217 decr_et.et_quality = 1000; 218 decr_et.et_frequency = ticks_per_sec; 219 decr_et.et_min_period = (0x00000002LLU << 32) / ticks_per_sec; 220 decr_et.et_max_period = (0x7fffffffLLU << 32) / ticks_per_sec; 221 decr_et.et_start = decr_et_start; 222 decr_et.et_stop = decr_et_stop; 223 decr_et.et_priv = NULL; 224 et_register(&decr_et); 225 } 226 227 /* 228 * Event timer start method. 229 */ 230 static int 231 decr_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 232 { 233 struct decr_state *s = DPCPU_PTR(decr_state); 234 uint32_t fdiv; 235 #ifdef BOOKE 236 uint32_t tcr; 237 #endif 238 239 if (period != 0) { 240 s->mode = 1; 241 s->div = (decr_et.et_frequency * period) >> 32; 242 } else { 243 s->mode = 2; 244 s->div = 0; 245 } 246 if (first != 0) 247 fdiv = (decr_et.et_frequency * first) >> 32; 248 else 249 fdiv = s->div; 250 251 #ifdef BOOKE 252 tcr = mfspr(SPR_TCR); 253 tcr |= TCR_DIE; 254 if (s->mode == 1) { 255 mtspr(SPR_DECAR, s->div); 256 tcr |= TCR_ARE; 257 } else 258 tcr &= ~TCR_ARE; 259 mtdec(fdiv); 260 mtspr(SPR_TCR, tcr); 261 #else 262 mtdec(fdiv); 263 #endif 264 265 return (0); 266 } 267 268 /* 269 * Event timer stop method. 270 */ 271 static int 272 decr_et_stop(struct eventtimer *et) 273 { 274 struct decr_state *s = DPCPU_PTR(decr_state); 275 #ifdef BOOKE 276 uint32_t tcr; 277 #endif 278 279 s->mode = 0; 280 s->div = 0x7fffffff; 281 #ifdef BOOKE 282 tcr = mfspr(SPR_TCR); 283 tcr &= ~(TCR_DIE | TCR_ARE); 284 mtspr(SPR_TCR, tcr); 285 #else 286 mtdec(s->div); 287 #endif 288 return (0); 289 } 290 291 /* 292 * Timecounter get method. 293 */ 294 static unsigned 295 decr_get_timecount(struct timecounter *tc) 296 { 297 return (mftb()); 298 } 299 300 /* 301 * Wait for about n microseconds (at least!). 302 */ 303 void 304 DELAY(int n) 305 { 306 u_quad_t tb, ttb; 307 308 TSENTER(); 309 tb = mftb(); 310 ttb = tb + howmany((uint64_t)n * 1000000, ps_per_tick); 311 while (tb < ttb) 312 tb = mftb(); 313 TSEXIT(); 314 } 315 316