1 /* $NetBSD: pwmclock.c,v 1.12 2020/05/29 12:30:41 rin Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: pwmclock.c,v 1.12 2020/05/29 12:30:41 rin Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/device.h> 35 #include <sys/cpu.h> 36 #include <sys/timetc.h> 37 #include <sys/sysctl.h> 38 39 #include <dev/pci/voyagervar.h> 40 #include <dev/ic/sm502reg.h> 41 42 #include <mips/mips3_clock.h> 43 #include <mips/locore.h> 44 #include <mips/bonito/bonitoreg.h> 45 #include <mips/bonito/bonitovar.h> 46 47 #include "opt_pwmclock.h" 48 49 #ifdef PWMCLOCK_DEBUG 50 #define DPRINTF aprint_error 51 #else 52 #define DPRINTF while (0) printf 53 #endif 54 55 int pwmclock_intr(void *); 56 57 struct pwmclock_softc { 58 device_t sc_dev; 59 bus_space_tag_t sc_memt; 60 bus_space_handle_t sc_regh; 61 uint32_t sc_reg, sc_last; 62 uint32_t sc_scale[8]; 63 uint32_t sc_count; /* should probably be 64 bit */ 64 int sc_step; 65 int sc_step_wanted; 66 void *sc_shutdown_cookie; 67 }; 68 69 static int pwmclock_match(device_t, cfdata_t, void *); 70 static void pwmclock_attach(device_t, device_t, void *); 71 72 CFATTACH_DECL_NEW(pwmclock, sizeof(struct pwmclock_softc), 73 pwmclock_match, pwmclock_attach, NULL, NULL); 74 75 static void pwmclock_start(void); 76 static u_int get_pwmclock_timecount(struct timecounter *); 77 78 struct pwmclock_softc *pwmclock; 79 extern void (*initclocks_ptr)(void); 80 81 /* 0, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1 */ 82 static int scale_m[] = {1, 1, 3, 1, 5, 3, 7, 1}; 83 static int scale_d[] = {0, 4, 8, 2, 8, 4, 8, 1}; 84 85 #define scale(x, f) (x * scale_d[f] / scale_m[f]) 86 87 void pwmclock_set_speed(struct pwmclock_softc *, int); 88 static int pwmclock_cpuspeed_temp(SYSCTLFN_ARGS); 89 static int pwmclock_cpuspeed_cur(SYSCTLFN_ARGS); 90 static int pwmclock_cpuspeed_available(SYSCTLFN_ARGS); 91 92 static void pwmclock_shutdown(void *); 93 94 static struct timecounter pwmclock_timecounter = { 95 .tc_get_timecount = get_pwmclock_timecount, 96 .tc_counter_mask = 0xffffffff, 97 .tc_name = "pwm", 98 .tc_quality = 100, 99 }; 100 101 static int 102 pwmclock_match(device_t parent, cfdata_t match, void *aux) 103 { 104 struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux; 105 106 if (strcmp(vaa->vaa_name, "pwmclock") == 0) return 100; 107 return 0; 108 } 109 110 static uint32_t 111 pwmclock_wait_edge(struct pwmclock_softc *sc) 112 { 113 /* clear interrupt */ 114 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, sc->sc_reg); 115 while ((bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PWM1) & 116 SM502_PWM_INTR_PENDING) == 0); 117 return mips3_cp0_count_read(); 118 } 119 120 static void 121 pwmclock_attach(device_t parent, device_t self, void *aux) 122 { 123 struct pwmclock_softc *sc = device_private(self); 124 struct voyager_attach_args *vaa = aux; 125 const struct sysctlnode *sysctl_node, *me, *freq; 126 uint32_t reg, last, curr, diff, acc; 127 int i, clk; 128 129 sc->sc_dev = self; 130 sc->sc_memt = vaa->vaa_tag; 131 sc->sc_regh = vaa->vaa_regh; 132 133 aprint_normal("\n"); 134 135 /* NULL here gets us the clockframe */ 136 voyager_establish_intr(parent, 22, pwmclock_intr, NULL); 137 reg = voyager_set_pwm(100, 100); /* 100Hz, 10% duty cycle */ 138 reg |= SM502_PWM_ENABLE | SM502_PWM_ENABLE_INTR | 139 SM502_PWM_INTR_PENDING; 140 sc->sc_reg = reg; 141 pwmclock = sc; 142 initclocks_ptr = pwmclock_start; 143 144 /* 145 * Establish a hook so on shutdown we can set the CPU clock back to 146 * full speed. This is necessary because PMON doesn't change the 147 * clock scale register on a warm boot, the MIPS clock code gets 148 * confused if we're too slow and the loongson-specific bits run 149 * too late in the boot process 150 */ 151 sc->sc_shutdown_cookie = shutdownhook_establish(pwmclock_shutdown, sc); 152 153 /* ok, let's see how far the cycle counter gets between interrupts */ 154 DPRINTF("calibrating CPU timer...\n"); 155 for (clk = 1; clk < 8; clk++) { 156 157 REGVAL(LS2F_CHIPCFG0) = 158 (REGVAL(LS2F_CHIPCFG0) & ~LS2FCFG_FREQSCALE_MASK) | clk; 159 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, 160 sc->sc_reg); 161 acc = 0; 162 last = pwmclock_wait_edge(sc); 163 for (i = 0; i < 16; i++) { 164 curr = pwmclock_wait_edge(sc); 165 diff = curr - last; 166 acc += diff; 167 last = curr; 168 } 169 sc->sc_scale[clk] = (acc >> 4) / 5000; 170 } 171 #ifdef PWMCLOCK_DEBUG 172 for (clk = 1; clk < 8; clk++) { 173 aprint_normal_dev(sc->sc_dev, "%d/8: %d\n", clk + 1, 174 sc->sc_scale[clk]); 175 } 176 #endif 177 sc->sc_step = 7; 178 sc->sc_step_wanted = 7; 179 180 /* now setup sysctl */ 181 if (sysctl_createv(NULL, 0, NULL, 182 &me, 183 CTLFLAG_READWRITE, CTLTYPE_NODE, "loongson", NULL, NULL, 184 0, NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL) != 0) 185 aprint_error_dev(sc->sc_dev, 186 "couldn't create 'loongson' node\n"); 187 188 if (sysctl_createv(NULL, 0, NULL, 189 &freq, 190 CTLFLAG_READWRITE, CTLTYPE_NODE, "frequency", NULL, NULL, 0, NULL, 191 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL) != 0) 192 aprint_error_dev(sc->sc_dev, 193 "couldn't create 'frequency' node\n"); 194 195 if (sysctl_createv(NULL, 0, NULL, 196 &sysctl_node, 197 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 198 CTLTYPE_INT, "target", "CPU speed", pwmclock_cpuspeed_temp, 199 0, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 200 CTL_CREATE, CTL_EOL) == 0) { 201 } else 202 aprint_error_dev(sc->sc_dev, 203 "couldn't create 'target' node\n"); 204 205 if (sysctl_createv(NULL, 0, NULL, 206 &sysctl_node, 207 CTLFLAG_READWRITE, 208 CTLTYPE_INT, "current", NULL, pwmclock_cpuspeed_cur, 209 1, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 210 CTL_CREATE, CTL_EOL) == 0) { 211 } else 212 aprint_error_dev(sc->sc_dev, 213 "couldn't create 'current' node\n"); 214 215 if (sysctl_createv(NULL, 0, NULL, 216 &sysctl_node, 217 CTLFLAG_READWRITE, 218 CTLTYPE_STRING, "available", NULL, pwmclock_cpuspeed_available, 219 2, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 220 CTL_CREATE, CTL_EOL) == 0) { 221 } else 222 aprint_error_dev(sc->sc_dev, 223 "couldn't create 'available' node\n"); 224 } 225 226 static void 227 pwmclock_shutdown(void *cookie) 228 { 229 struct pwmclock_softc *sc = cookie; 230 231 /* just in case the interrupt handler runs again after this */ 232 sc->sc_step_wanted = 7; 233 /* set the clock to full speed */ 234 REGVAL(LS2F_CHIPCFG0) = 235 (REGVAL(LS2F_CHIPCFG0) & ~LS2FCFG_FREQSCALE_MASK) | 7; 236 } 237 238 void 239 pwmclock_set_speed(struct pwmclock_softc *sc, int speed) 240 { 241 242 if ((speed < 1) || (speed > 7)) 243 return; 244 sc->sc_step_wanted = speed; 245 DPRINTF("%s: %d\n", __func__, speed); 246 } 247 248 /* 249 * the PWM interrupt handler 250 * we don't have a CPU clock independent, high resolution counter so we're 251 * stuck with a PWM that can't count and a CP0 counter that slows down or 252 * speeds up with the actual CPU speed. In order to still get halfway 253 * accurate time we do the following: 254 * - only change CPU speed in the timer interrupt 255 * - each timer interrupt we measure how many CP0 cycles passed since last 256 * time, adjust for CPU speed since we can be sure it didn't change, use 257 * that to update a separate counter 258 * - when reading the time counter we take the number of CP0 ticks since 259 * the last timer interrupt, scale it to CPU clock, return that plus the 260 * interrupt updated counter mentioned above to get something close to 261 * CP0 running at full speed 262 * - when changing CPU speed do it as close to taking the time from CP0 as 263 * possible to keep the period of time we spend with CP0 running at the 264 * wrong frequency as short as possible - hopefully short enough to stay 265 * insignificant compared to other noise since switching speeds isn't 266 * going to happen all that often 267 */ 268 269 int 270 pwmclock_intr(void *cookie) 271 { 272 struct clockframe *cf = cookie; 273 struct pwmclock_softc *sc = pwmclock; 274 uint32_t reg, now, diff; 275 276 /* is it us? */ 277 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PWM1); 278 if ((reg & SM502_PWM_INTR_PENDING) == 0) 279 return 0; 280 281 /* yes, it's us, so clear the interrupt */ 282 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, sc->sc_reg); 283 284 /* 285 * this looks kinda funny but what we want here is this: 286 * - reading the counter and changing the CPU clock should be as 287 * close together as possible in order to remain halfway accurate 288 * - we need to use the previous sc_step in order to scale the 289 * interval passed since the last clock interrupt correctly, so 290 * we only change sc_step after doing that 291 */ 292 if (sc->sc_step_wanted != sc->sc_step) { 293 294 REGVAL(LS2F_CHIPCFG0) = 295 (REGVAL(LS2F_CHIPCFG0) & ~LS2FCFG_FREQSCALE_MASK) | 296 sc->sc_step_wanted; 297 } 298 299 now = mips3_cp0_count_read(); 300 diff = now - sc->sc_last; 301 sc->sc_count += scale(diff, sc->sc_step); 302 sc->sc_last = now; 303 if (sc->sc_step_wanted != sc->sc_step) { 304 sc->sc_step = sc->sc_step_wanted; 305 } 306 307 hardclock(cf); 308 309 return 1; 310 } 311 312 static void 313 pwmclock_start(void) 314 { 315 struct pwmclock_softc *sc = pwmclock; 316 sc->sc_count = 0; 317 sc->sc_last = mips3_cp0_count_read(); 318 pwmclock_timecounter.tc_frequency = curcpu()->ci_cpu_freq / 2; 319 tc_init(&pwmclock_timecounter); 320 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, sc->sc_reg); 321 } 322 323 static u_int 324 get_pwmclock_timecount(struct timecounter *tc) 325 { 326 struct pwmclock_softc *sc = pwmclock; 327 uint32_t now, diff; 328 329 now = mips3_cp0_count_read(); 330 diff = now - sc->sc_last; 331 return sc->sc_count + scale(diff, sc->sc_step); 332 } 333 334 static int 335 pwmclock_cpuspeed_temp(SYSCTLFN_ARGS) 336 { 337 struct sysctlnode node = *rnode; 338 struct pwmclock_softc *sc = node.sysctl_data; 339 int mhz, i; 340 341 mhz = sc->sc_scale[sc->sc_step_wanted]; 342 343 node.sysctl_data = &mhz; 344 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 345 int new_reg; 346 347 new_reg = *(int *)node.sysctl_data; 348 i = 1; 349 while ((i < 8) && (sc->sc_scale[i] != new_reg)) 350 i++; 351 if (i > 7) 352 return EINVAL; 353 pwmclock_set_speed(sc, i); 354 return 0; 355 } 356 return EINVAL; 357 } 358 359 static int 360 pwmclock_cpuspeed_cur(SYSCTLFN_ARGS) 361 { 362 struct sysctlnode node = *rnode; 363 struct pwmclock_softc *sc = node.sysctl_data; 364 int mhz; 365 366 mhz = sc->sc_scale[sc->sc_step]; 367 node.sysctl_data = &mhz; 368 return sysctl_lookup(SYSCTLFN_CALL(&node)); 369 } 370 371 static int 372 pwmclock_cpuspeed_available(SYSCTLFN_ARGS) 373 { 374 struct sysctlnode node = *rnode; 375 struct pwmclock_softc *sc = node.sysctl_data; 376 char buf[128]; 377 378 snprintf(buf, 128, "%d %d %d %d %d %d %d", sc->sc_scale[1], 379 sc->sc_scale[2], sc->sc_scale[3], sc->sc_scale[4], 380 sc->sc_scale[5], sc->sc_scale[6], sc->sc_scale[7]); 381 node.sysctl_data = buf; 382 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 383 } 384 385 SYSCTL_SETUP(sysctl_ams_setup, "sysctl obio subtree setup") 386 { 387 388 sysctl_createv(NULL, 0, NULL, NULL, 389 CTLFLAG_PERMANENT, 390 CTLTYPE_NODE, "machdep", NULL, 391 NULL, 0, NULL, 0, 392 CTL_MACHDEP, CTL_EOL); 393 } 394