1 /* $NetBSD: pwmclock.c,v 1.11 2016/08/26 15:45:48 skrll 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.11 2016/08/26 15:45:48 skrll 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 get_pwmclock_timecount, /* get_timecount */ 96 0, /* no poll_pps */ 97 0xffffffff, /* counter_mask */ 98 0, /* frequency */ 99 "pwm", /* name */ 100 100, /* quality */ 101 NULL, /* tc_priv */ 102 NULL /* tc_next */ 103 }; 104 105 static int 106 pwmclock_match(device_t parent, cfdata_t match, void *aux) 107 { 108 struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux; 109 110 if (strcmp(vaa->vaa_name, "pwmclock") == 0) return 100; 111 return 0; 112 } 113 114 static uint32_t 115 pwmclock_wait_edge(struct pwmclock_softc *sc) 116 { 117 /* clear interrupt */ 118 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, sc->sc_reg); 119 while ((bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PWM1) & 120 SM502_PWM_INTR_PENDING) == 0); 121 return mips3_cp0_count_read(); 122 } 123 124 static void 125 pwmclock_attach(device_t parent, device_t self, void *aux) 126 { 127 struct pwmclock_softc *sc = device_private(self); 128 struct voyager_attach_args *vaa = aux; 129 const struct sysctlnode *sysctl_node, *me, *freq; 130 uint32_t reg, last, curr, diff, acc; 131 int i, clk; 132 133 sc->sc_dev = self; 134 sc->sc_memt = vaa->vaa_tag; 135 sc->sc_regh = vaa->vaa_regh; 136 137 aprint_normal("\n"); 138 139 /* NULL here gets us the clockframe */ 140 voyager_establish_intr(parent, 22, pwmclock_intr, NULL); 141 reg = voyager_set_pwm(100, 100); /* 100Hz, 10% duty cycle */ 142 reg |= SM502_PWM_ENABLE | SM502_PWM_ENABLE_INTR | 143 SM502_PWM_INTR_PENDING; 144 sc->sc_reg = reg; 145 pwmclock = sc; 146 initclocks_ptr = pwmclock_start; 147 148 /* 149 * Establish a hook so on shutdown we can set the CPU clock back to 150 * full speed. This is necessary because PMON doesn't change the 151 * clock scale register on a warm boot, the MIPS clock code gets 152 * confused if we're too slow and the loongson-specific bits run 153 * too late in the boot process 154 */ 155 sc->sc_shutdown_cookie = shutdownhook_establish(pwmclock_shutdown, sc); 156 157 /* ok, let's see how far the cycle counter gets between interrupts */ 158 DPRINTF("calibrating CPU timer...\n"); 159 for (clk = 1; clk < 8; clk++) { 160 161 REGVAL(LS2F_CHIPCFG0) = 162 (REGVAL(LS2F_CHIPCFG0) & ~LS2FCFG_FREQSCALE_MASK) | clk; 163 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, 164 sc->sc_reg); 165 acc = 0; 166 last = pwmclock_wait_edge(sc); 167 for (i = 0; i < 16; i++) { 168 curr = pwmclock_wait_edge(sc); 169 diff = curr - last; 170 acc += diff; 171 last = curr; 172 } 173 sc->sc_scale[clk] = (acc >> 4) / 5000; 174 } 175 #ifdef PWMCLOCK_DEBUG 176 for (clk = 1; clk < 8; clk++) { 177 aprint_normal_dev(sc->sc_dev, "%d/8: %d\n", clk + 1, 178 sc->sc_scale[clk]); 179 } 180 #endif 181 sc->sc_step = 7; 182 sc->sc_step_wanted = 7; 183 184 /* now setup sysctl */ 185 if (sysctl_createv(NULL, 0, NULL, 186 &me, 187 CTLFLAG_READWRITE, CTLTYPE_NODE, "loongson", NULL, NULL, 188 0, NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL) != 0) 189 aprint_error_dev(sc->sc_dev, 190 "couldn't create 'loongson' node\n"); 191 192 if (sysctl_createv(NULL, 0, NULL, 193 &freq, 194 CTLFLAG_READWRITE, CTLTYPE_NODE, "frequency", NULL, NULL, 0, NULL, 195 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL) != 0) 196 aprint_error_dev(sc->sc_dev, 197 "couldn't create 'frequency' node\n"); 198 199 if (sysctl_createv(NULL, 0, NULL, 200 &sysctl_node, 201 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 202 CTLTYPE_INT, "target", "CPU speed", pwmclock_cpuspeed_temp, 203 0, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 204 CTL_CREATE, CTL_EOL) == 0) { 205 } else 206 aprint_error_dev(sc->sc_dev, 207 "couldn't create 'target' node\n"); 208 209 if (sysctl_createv(NULL, 0, NULL, 210 &sysctl_node, 211 CTLFLAG_READWRITE, 212 CTLTYPE_INT, "current", NULL, pwmclock_cpuspeed_cur, 213 1, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 214 CTL_CREATE, CTL_EOL) == 0) { 215 } else 216 aprint_error_dev(sc->sc_dev, 217 "couldn't create 'current' node\n"); 218 219 if (sysctl_createv(NULL, 0, NULL, 220 &sysctl_node, 221 CTLFLAG_READWRITE, 222 CTLTYPE_STRING, "available", NULL, pwmclock_cpuspeed_available, 223 2, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 224 CTL_CREATE, CTL_EOL) == 0) { 225 } else 226 aprint_error_dev(sc->sc_dev, 227 "couldn't create 'available' node\n"); 228 } 229 230 static void 231 pwmclock_shutdown(void *cookie) 232 { 233 struct pwmclock_softc *sc = cookie; 234 235 /* just in case the interrupt handler runs again after this */ 236 sc->sc_step_wanted = 7; 237 /* set the clock to full speed */ 238 REGVAL(LS2F_CHIPCFG0) = 239 (REGVAL(LS2F_CHIPCFG0) & ~LS2FCFG_FREQSCALE_MASK) | 7; 240 } 241 242 void 243 pwmclock_set_speed(struct pwmclock_softc *sc, int speed) 244 { 245 246 if ((speed < 1) || (speed > 7)) 247 return; 248 sc->sc_step_wanted = speed; 249 DPRINTF("%s: %d\n", __func__, speed); 250 } 251 252 /* 253 * the PWM interrupt handler 254 * we don't have a CPU clock independent, high resolution counter so we're 255 * stuck with a PWM that can't count and a CP0 counter that slows down or 256 * speeds up with the actual CPU speed. In order to still get halfway 257 * accurate time we do the following: 258 * - only change CPU speed in the timer interrupt 259 * - each timer interrupt we measure how many CP0 cycles passed since last 260 * time, adjust for CPU speed since we can be sure it didn't change, use 261 * that to update a separate counter 262 * - when reading the time counter we take the number of CP0 ticks since 263 * the last timer interrupt, scale it to CPU clock, return that plus the 264 * interrupt updated counter mentioned above to get something close to 265 * CP0 running at full speed 266 * - when changing CPU speed do it as close to taking the time from CP0 as 267 * possible to keep the period of time we spend with CP0 running at the 268 * wrong frequency as short as possible - hopefully short enough to stay 269 * insignificant compared to other noise since switching speeds isn't 270 * going to happen all that often 271 */ 272 273 int 274 pwmclock_intr(void *cookie) 275 { 276 struct clockframe *cf = cookie; 277 struct pwmclock_softc *sc = pwmclock; 278 uint32_t reg, now, diff; 279 280 /* is it us? */ 281 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PWM1); 282 if ((reg & SM502_PWM_INTR_PENDING) == 0) 283 return 0; 284 285 /* yes, it's us, so clear the interrupt */ 286 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, sc->sc_reg); 287 288 /* 289 * this looks kinda funny but what we want here is this: 290 * - reading the counter and changing the CPU clock should be as 291 * close together as possible in order to remain halfway accurate 292 * - we need to use the previous sc_step in order to scale the 293 * interval passed since the last clock interrupt correctly, so 294 * we only change sc_step after doing that 295 */ 296 if (sc->sc_step_wanted != sc->sc_step) { 297 298 REGVAL(LS2F_CHIPCFG0) = 299 (REGVAL(LS2F_CHIPCFG0) & ~LS2FCFG_FREQSCALE_MASK) | 300 sc->sc_step_wanted; 301 } 302 303 now = mips3_cp0_count_read(); 304 diff = now - sc->sc_last; 305 sc->sc_count += scale(diff, sc->sc_step); 306 sc->sc_last = now; 307 if (sc->sc_step_wanted != sc->sc_step) { 308 sc->sc_step = sc->sc_step_wanted; 309 } 310 311 hardclock(cf); 312 313 return 1; 314 } 315 316 static void 317 pwmclock_start(void) 318 { 319 struct pwmclock_softc *sc = pwmclock; 320 sc->sc_count = 0; 321 sc->sc_last = mips3_cp0_count_read(); 322 pwmclock_timecounter.tc_frequency = curcpu()->ci_cpu_freq / 2; 323 tc_init(&pwmclock_timecounter); 324 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM1, sc->sc_reg); 325 } 326 327 static u_int 328 get_pwmclock_timecount(struct timecounter *tc) 329 { 330 struct pwmclock_softc *sc = pwmclock; 331 uint32_t now, diff; 332 333 now = mips3_cp0_count_read(); 334 diff = now - sc->sc_last; 335 return sc->sc_count + scale(diff, sc->sc_step); 336 } 337 338 static int 339 pwmclock_cpuspeed_temp(SYSCTLFN_ARGS) 340 { 341 struct sysctlnode node = *rnode; 342 struct pwmclock_softc *sc = node.sysctl_data; 343 int mhz, i; 344 345 mhz = sc->sc_scale[sc->sc_step_wanted]; 346 347 node.sysctl_data = &mhz; 348 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 349 int new_reg; 350 351 new_reg = *(int *)node.sysctl_data; 352 i = 1; 353 while ((i < 8) && (sc->sc_scale[i] != new_reg)) 354 i++; 355 if (i > 7) 356 return EINVAL; 357 pwmclock_set_speed(sc, i); 358 return 0; 359 } 360 return EINVAL; 361 } 362 363 static int 364 pwmclock_cpuspeed_cur(SYSCTLFN_ARGS) 365 { 366 struct sysctlnode node = *rnode; 367 struct pwmclock_softc *sc = node.sysctl_data; 368 int mhz; 369 370 mhz = sc->sc_scale[sc->sc_step]; 371 node.sysctl_data = &mhz; 372 return sysctl_lookup(SYSCTLFN_CALL(&node)); 373 } 374 375 static int 376 pwmclock_cpuspeed_available(SYSCTLFN_ARGS) 377 { 378 struct sysctlnode node = *rnode; 379 struct pwmclock_softc *sc = node.sysctl_data; 380 char buf[128]; 381 382 snprintf(buf, 128, "%d %d %d %d %d %d %d", sc->sc_scale[1], 383 sc->sc_scale[2], sc->sc_scale[3], sc->sc_scale[4], 384 sc->sc_scale[5], sc->sc_scale[6], sc->sc_scale[7]); 385 node.sysctl_data = buf; 386 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 387 } 388 389 SYSCTL_SETUP(sysctl_ams_setup, "sysctl obio subtree setup") 390 { 391 392 sysctl_createv(NULL, 0, NULL, NULL, 393 CTLFLAG_PERMANENT, 394 CTLTYPE_NODE, "machdep", NULL, 395 NULL, 0, NULL, 0, 396 CTL_MACHDEP, CTL_EOL); 397 } 398