1 /*- 2 * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.Org> 3 * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * Generic DT based cpufreq driver 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/bus.h> 34 #include <sys/rman.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 #include <sys/cpu.h> 38 #include <sys/cpuset.h> 39 #include <sys/smp.h> 40 41 #include <dev/ofw/ofw_bus.h> 42 #include <dev/ofw/ofw_bus_subr.h> 43 44 #include <dev/extres/clk/clk.h> 45 #include <dev/extres/regulator/regulator.h> 46 47 #include "cpufreq_if.h" 48 49 #if 0 50 #define DPRINTF(dev, msg...) device_printf(dev, "cpufreq_dt: " msg); 51 #else 52 #define DPRINTF(dev, msg...) 53 #endif 54 55 enum opp_version { 56 OPP_V1 = 1, 57 OPP_V2, 58 }; 59 60 struct cpufreq_dt_opp { 61 uint64_t freq; 62 uint32_t uvolt_target; 63 uint32_t uvolt_min; 64 uint32_t uvolt_max; 65 uint32_t uamps; 66 uint32_t clk_latency; 67 bool turbo_mode; 68 bool opp_suspend; 69 }; 70 71 #define CPUFREQ_DT_HAVE_REGULATOR(sc) ((sc)->reg != NULL) 72 73 struct cpufreq_dt_softc { 74 device_t dev; 75 clk_t clk; 76 regulator_t reg; 77 78 struct cpufreq_dt_opp *opp; 79 ssize_t nopp; 80 81 int cpu; 82 cpuset_t cpus; 83 }; 84 85 static void 86 cpufreq_dt_notify(device_t dev, uint64_t freq) 87 { 88 struct cpufreq_dt_softc *sc; 89 struct pcpu *pc; 90 int cpu; 91 92 sc = device_get_softc(dev); 93 94 CPU_FOREACH(cpu) { 95 if (CPU_ISSET(cpu, &sc->cpus)) { 96 pc = pcpu_find(cpu); 97 pc->pc_clock = freq; 98 } 99 } 100 } 101 102 static const struct cpufreq_dt_opp * 103 cpufreq_dt_find_opp(device_t dev, uint64_t freq) 104 { 105 struct cpufreq_dt_softc *sc; 106 uint64_t diff, best_diff; 107 ssize_t n, best_n; 108 109 sc = device_get_softc(dev); 110 111 diff = 0; 112 best_diff = ~0; 113 DPRINTF(dev, "Looking for freq %ju\n", freq); 114 for (n = 0; n < sc->nopp; n++) { 115 diff = abs64((int64_t)sc->opp[n].freq - (int64_t)freq); 116 DPRINTF(dev, "Testing %ju, diff is %ju\n", sc->opp[n].freq, diff); 117 if (diff < best_diff) { 118 best_diff = diff; 119 best_n = n; 120 DPRINTF(dev, "%ju is best for now\n", sc->opp[n].freq); 121 } 122 } 123 124 DPRINTF(dev, "Will use %ju\n", sc->opp[best_n].freq); 125 return (&sc->opp[best_n]); 126 } 127 128 static void 129 cpufreq_dt_opp_to_setting(device_t dev, const struct cpufreq_dt_opp *opp, 130 struct cf_setting *set) 131 { 132 133 memset(set, 0, sizeof(*set)); 134 set->freq = opp->freq / 1000000; 135 set->volts = opp->uvolt_target / 1000; 136 set->power = CPUFREQ_VAL_UNKNOWN; 137 set->lat = opp->clk_latency; 138 set->dev = dev; 139 } 140 141 static int 142 cpufreq_dt_get(device_t dev, struct cf_setting *set) 143 { 144 struct cpufreq_dt_softc *sc; 145 const struct cpufreq_dt_opp *opp; 146 uint64_t freq; 147 148 sc = device_get_softc(dev); 149 150 DPRINTF(dev, "cpufreq_dt_get\n"); 151 if (clk_get_freq(sc->clk, &freq) != 0) 152 return (ENXIO); 153 154 opp = cpufreq_dt_find_opp(dev, freq); 155 if (opp == NULL) { 156 device_printf(dev, "Can't find the current freq in opp\n"); 157 return (ENOENT); 158 } 159 160 cpufreq_dt_opp_to_setting(dev, opp, set); 161 162 DPRINTF(dev, "Current freq %dMhz\n", set->freq); 163 return (0); 164 } 165 166 static int 167 cpufreq_dt_set(device_t dev, const struct cf_setting *set) 168 { 169 struct cpufreq_dt_softc *sc; 170 const struct cpufreq_dt_opp *opp, *copp; 171 uint64_t freq; 172 int uvolt, error; 173 174 sc = device_get_softc(dev); 175 176 DPRINTF(dev, "Working on cpu %d\n", sc->cpu); 177 DPRINTF(dev, "We have %d cpu on this dev\n", CPU_COUNT(&sc->cpus)); 178 if (!CPU_ISSET(sc->cpu, &sc->cpus)) { 179 DPRINTF(dev, "Not for this CPU\n"); 180 return (0); 181 } 182 183 if (clk_get_freq(sc->clk, &freq) != 0) { 184 device_printf(dev, "Can't get current clk freq\n"); 185 return (ENXIO); 186 } 187 188 /* 189 * Only do the regulator work if it's required. 190 */ 191 if (CPUFREQ_DT_HAVE_REGULATOR(sc)) { 192 /* Try to get current valtage by using regulator first. */ 193 error = regulator_get_voltage(sc->reg, &uvolt); 194 if (error != 0) { 195 /* 196 * Try oppoints table as backup way. However, 197 * this is insufficient because the actual processor 198 * frequency may not be in the table. PLL frequency 199 * granularity can be different that granularity of 200 * oppoint table. 201 */ 202 copp = cpufreq_dt_find_opp(sc->dev, freq); 203 if (copp == NULL) { 204 device_printf(dev, 205 "Can't find the current freq in opp\n"); 206 return (ENOENT); 207 } 208 uvolt = copp->uvolt_target; 209 } 210 } else 211 uvolt = 0; 212 213 opp = cpufreq_dt_find_opp(sc->dev, set->freq * 1000000); 214 if (opp == NULL) { 215 device_printf(dev, "Couldn't find an opp for this freq\n"); 216 return (EINVAL); 217 } 218 DPRINTF(sc->dev, "Current freq %ju, uvolt: %d\n", freq, uvolt); 219 DPRINTF(sc->dev, "Target freq %ju, , uvolt: %d\n", 220 opp->freq, opp->uvolt_target); 221 222 if (CPUFREQ_DT_HAVE_REGULATOR(sc) && (uvolt < opp->uvolt_target)) { 223 DPRINTF(dev, "Changing regulator from %u to %u\n", 224 uvolt, opp->uvolt_target); 225 error = regulator_set_voltage(sc->reg, 226 opp->uvolt_min, 227 opp->uvolt_max); 228 if (error != 0) { 229 DPRINTF(dev, "Failed, backout\n"); 230 return (ENXIO); 231 } 232 } 233 234 DPRINTF(dev, "Setting clk to %ju\n", opp->freq); 235 error = clk_set_freq(sc->clk, opp->freq, CLK_SET_ROUND_DOWN); 236 if (error != 0) { 237 DPRINTF(dev, "Failed, backout\n"); 238 /* Restore previous voltage (best effort) */ 239 if (CPUFREQ_DT_HAVE_REGULATOR(sc)) 240 error = regulator_set_voltage(sc->reg, 241 copp->uvolt_min, 242 copp->uvolt_max); 243 return (ENXIO); 244 } 245 246 if (CPUFREQ_DT_HAVE_REGULATOR(sc) && (uvolt > opp->uvolt_target)) { 247 DPRINTF(dev, "Changing regulator from %u to %u\n", 248 uvolt, opp->uvolt_target); 249 error = regulator_set_voltage(sc->reg, 250 opp->uvolt_min, 251 opp->uvolt_max); 252 if (error != 0) { 253 DPRINTF(dev, "Failed to switch regulator to %d\n", 254 opp->uvolt_target); 255 /* Restore previous CPU frequency (best effort) */ 256 (void)clk_set_freq(sc->clk, copp->freq, 0); 257 return (ENXIO); 258 } 259 } 260 261 if (clk_get_freq(sc->clk, &freq) == 0) 262 cpufreq_dt_notify(dev, freq); 263 264 return (0); 265 } 266 267 static int 268 cpufreq_dt_type(device_t dev, int *type) 269 { 270 if (type == NULL) 271 return (EINVAL); 272 273 *type = CPUFREQ_TYPE_ABSOLUTE; 274 return (0); 275 } 276 277 static int 278 cpufreq_dt_settings(device_t dev, struct cf_setting *sets, int *count) 279 { 280 struct cpufreq_dt_softc *sc; 281 ssize_t n; 282 283 DPRINTF(dev, "cpufreq_dt_settings\n"); 284 if (sets == NULL || count == NULL) 285 return (EINVAL); 286 287 sc = device_get_softc(dev); 288 289 if (*count < sc->nopp) { 290 *count = (int)sc->nopp; 291 return (E2BIG); 292 } 293 294 for (n = 0; n < sc->nopp; n++) 295 cpufreq_dt_opp_to_setting(dev, &sc->opp[n], &sets[n]); 296 297 *count = (int)sc->nopp; 298 299 return (0); 300 } 301 302 static void 303 cpufreq_dt_identify(driver_t *driver, device_t parent) 304 { 305 phandle_t node; 306 307 /* Properties must be listed under node /cpus/cpu@0 */ 308 node = ofw_bus_get_node(parent); 309 310 /* The cpu@0 node must have the following properties */ 311 if (!OF_hasprop(node, "clocks")) 312 return; 313 314 if (!OF_hasprop(node, "operating-points") && 315 !OF_hasprop(node, "operating-points-v2")) 316 return; 317 318 if (device_find_child(parent, "cpufreq_dt", -1) != NULL) 319 return; 320 321 if (BUS_ADD_CHILD(parent, 0, "cpufreq_dt", device_get_unit(parent)) 322 == NULL) 323 device_printf(parent, "add cpufreq_dt child failed\n"); 324 } 325 326 static int 327 cpufreq_dt_probe(device_t dev) 328 { 329 phandle_t node; 330 331 node = ofw_bus_get_node(device_get_parent(dev)); 332 333 /* 334 * Note - supply isn't required here for probe; we'll check 335 * it out in more detail during attach. 336 */ 337 if (!OF_hasprop(node, "clocks")) 338 return (ENXIO); 339 340 if (!OF_hasprop(node, "operating-points") && 341 !OF_hasprop(node, "operating-points-v2")) 342 return (ENXIO); 343 344 device_set_desc(dev, "Generic cpufreq driver"); 345 return (BUS_PROBE_GENERIC); 346 } 347 348 static int 349 cpufreq_dt_oppv1_parse(struct cpufreq_dt_softc *sc, phandle_t node) 350 { 351 uint32_t *opp, lat; 352 ssize_t n; 353 354 sc->nopp = OF_getencprop_alloc_multi(node, "operating-points", 355 sizeof(uint32_t) * 2, (void **)&opp); 356 if (sc->nopp == -1) 357 return (ENXIO); 358 359 if (OF_getencprop(node, "clock-latency", &lat, sizeof(lat)) == -1) 360 lat = CPUFREQ_VAL_UNKNOWN; 361 362 sc->opp = malloc(sizeof(*sc->opp) * sc->nopp, M_DEVBUF, M_WAITOK); 363 364 for (n = 0; n < sc->nopp; n++) { 365 sc->opp[n].freq = opp[n * 2 + 0] * 1000; 366 sc->opp[n].uvolt_min = opp[n * 2 + 1]; 367 sc->opp[n].uvolt_max = sc->opp[n].uvolt_min; 368 sc->opp[n].uvolt_target = sc->opp[n].uvolt_min; 369 sc->opp[n].clk_latency = lat; 370 371 if (bootverbose) 372 device_printf(sc->dev, "%ju.%03ju MHz, %u uV\n", 373 sc->opp[n].freq / 1000000, 374 sc->opp[n].freq % 1000000, 375 sc->opp[n].uvolt_target); 376 } 377 free(opp, M_OFWPROP); 378 379 return (0); 380 } 381 382 static int 383 cpufreq_dt_oppv2_parse(struct cpufreq_dt_softc *sc, phandle_t node) 384 { 385 phandle_t opp, opp_table, opp_xref; 386 pcell_t cell[2]; 387 uint32_t *volts, lat; 388 int nvolt, i; 389 390 /* 391 * operating-points-v2 does not require the voltage entries 392 * and a regulator. So, it's OK if they're not there. 393 */ 394 if (OF_getencprop(node, "operating-points-v2", &opp_xref, 395 sizeof(opp_xref)) == -1) { 396 device_printf(sc->dev, "Cannot get xref to oppv2 table\n"); 397 return (ENXIO); 398 } 399 400 opp_table = OF_node_from_xref(opp_xref); 401 if (opp_table == opp_xref) 402 return (ENXIO); 403 404 if (!OF_hasprop(opp_table, "opp-shared")) { 405 device_printf(sc->dev, "Only opp-shared is supported\n"); 406 return (ENXIO); 407 } 408 409 for (opp = OF_child(opp_table); opp > 0; opp = OF_peer(opp)) 410 sc->nopp += 1; 411 412 sc->opp = malloc(sizeof(*sc->opp) * sc->nopp, M_DEVBUF, M_WAITOK); 413 414 for (i = 0, opp_table = OF_child(opp_table); opp_table > 0; 415 opp_table = OF_peer(opp_table), i++) { 416 /* opp-hz is a required property */ 417 if (OF_getencprop(opp_table, "opp-hz", cell, 418 sizeof(cell)) == -1) 419 continue; 420 421 sc->opp[i].freq = cell[0]; 422 sc->opp[i].freq <<= 32; 423 sc->opp[i].freq |= cell[1]; 424 425 if (OF_getencprop(opp_table, "clock-latency", &lat, 426 sizeof(lat)) == -1) 427 sc->opp[i].clk_latency = CPUFREQ_VAL_UNKNOWN; 428 else 429 sc->opp[i].clk_latency = (int)lat; 430 431 if (OF_hasprop(opp_table, "turbo-mode")) 432 sc->opp[i].turbo_mode = true; 433 if (OF_hasprop(opp_table, "opp-suspend")) 434 sc->opp[i].opp_suspend = true; 435 436 if (CPUFREQ_DT_HAVE_REGULATOR(sc)) { 437 nvolt = OF_getencprop_alloc_multi(opp_table, 438 "opp-microvolt", sizeof(*volts), (void **)&volts); 439 if (nvolt == 1) { 440 sc->opp[i].uvolt_target = volts[0]; 441 sc->opp[i].uvolt_min = volts[0]; 442 sc->opp[i].uvolt_max = volts[0]; 443 } else if (nvolt == 3) { 444 sc->opp[i].uvolt_target = volts[0]; 445 sc->opp[i].uvolt_min = volts[1]; 446 sc->opp[i].uvolt_max = volts[2]; 447 } else { 448 device_printf(sc->dev, 449 "Wrong count of opp-microvolt property\n"); 450 OF_prop_free(volts); 451 free(sc->opp, M_DEVBUF); 452 return (ENXIO); 453 } 454 OF_prop_free(volts); 455 } else { 456 /* No regulator required; don't add anything */ 457 sc->opp[i].uvolt_target = 0; 458 sc->opp[i].uvolt_min = 0; 459 sc->opp[i].uvolt_max = 0; 460 } 461 462 if (bootverbose) 463 device_printf(sc->dev, "%ju.%03ju Mhz (%u uV)\n", 464 sc->opp[i].freq / 1000000, 465 sc->opp[i].freq % 1000000, 466 sc->opp[i].uvolt_target); 467 } 468 return (0); 469 } 470 471 static int 472 cpufreq_dt_attach(device_t dev) 473 { 474 struct cpufreq_dt_softc *sc; 475 phandle_t node; 476 phandle_t cnode, opp, copp; 477 int cpu; 478 uint64_t freq; 479 int rv = 0; 480 char device_type[16]; 481 enum opp_version version; 482 483 sc = device_get_softc(dev); 484 sc->dev = dev; 485 node = ofw_bus_get_node(device_get_parent(dev)); 486 sc->cpu = device_get_unit(device_get_parent(dev)); 487 sc->reg = NULL; 488 489 DPRINTF(dev, "cpu=%d\n", sc->cpu); 490 if (sc->cpu >= mp_ncpus) { 491 device_printf(dev, "Not attaching as cpu is not present\n"); 492 rv = ENXIO; 493 goto error; 494 } 495 496 /* 497 * Cache if we have the regulator supply but don't error out 498 * quite yet. If it's operating-points-v2 then regulator 499 * and voltage entries are optional. 500 */ 501 if (regulator_get_by_ofw_property(dev, node, "cpu-supply", 502 &sc->reg) == 0) 503 device_printf(dev, "Found cpu-supply\n"); 504 else if (regulator_get_by_ofw_property(dev, node, "cpu0-supply", 505 &sc->reg) == 0) 506 device_printf(dev, "Found cpu0-supply\n"); 507 508 /* 509 * Determine which operating mode we're in. Error out if we expect 510 * a regulator but we're not getting it. 511 */ 512 if (OF_hasprop(node, "operating-points")) 513 version = OPP_V1; 514 else if (OF_hasprop(node, "operating-points-v2")) 515 version = OPP_V2; 516 else { 517 device_printf(dev, 518 "didn't find a valid operating-points or v2 node\n"); 519 rv = ENXIO; 520 goto error; 521 } 522 523 /* 524 * Now, we only enforce needing a regulator for v1. 525 */ 526 if ((version == OPP_V1) && !CPUFREQ_DT_HAVE_REGULATOR(sc)) { 527 device_printf(dev, "no regulator for %s\n", 528 ofw_bus_get_name(device_get_parent(dev))); 529 rv = ENXIO; 530 goto error; 531 } 532 533 if (clk_get_by_ofw_index(dev, node, 0, &sc->clk) != 0) { 534 device_printf(dev, "no clock for %s\n", 535 ofw_bus_get_name(device_get_parent(dev))); 536 rv = ENXIO; 537 goto error; 538 } 539 540 if (version == OPP_V1) { 541 rv = cpufreq_dt_oppv1_parse(sc, node); 542 if (rv != 0) { 543 device_printf(dev, "Failed to parse opp-v1 table\n"); 544 goto error; 545 } 546 OF_getencprop(node, "operating-points", &opp, 547 sizeof(opp)); 548 } else if (version == OPP_V2) { 549 rv = cpufreq_dt_oppv2_parse(sc, node); 550 if (rv != 0) { 551 device_printf(dev, "Failed to parse opp-v2 table\n"); 552 goto error; 553 } 554 OF_getencprop(node, "operating-points-v2", &opp, 555 sizeof(opp)); 556 } else { 557 device_printf(dev, "operating points version is incorrect\n"); 558 goto error; 559 } 560 561 /* 562 * Find all CPUs that share the same opp table 563 */ 564 CPU_ZERO(&sc->cpus); 565 cnode = OF_parent(node); 566 for (cpu = 0, cnode = OF_child(cnode); cnode > 0; cnode = OF_peer(cnode)) { 567 if (OF_getprop(cnode, "device_type", device_type, sizeof(device_type)) <= 0) 568 continue; 569 if (strcmp(device_type, "cpu") != 0) 570 continue; 571 if (cpu == sc->cpu) { 572 DPRINTF(dev, "Skipping our cpu\n"); 573 CPU_SET(cpu, &sc->cpus); 574 cpu++; 575 continue; 576 } 577 DPRINTF(dev, "Testing CPU %d\n", cpu); 578 copp = -1; 579 if (version == OPP_V1) 580 OF_getencprop(cnode, "operating-points", &copp, 581 sizeof(copp)); 582 else if (version == OPP_V2) 583 OF_getencprop(cnode, "operating-points-v2", 584 &copp, sizeof(copp)); 585 if (opp == copp) { 586 DPRINTF(dev, "CPU %d is using the same opp as this one (%d)\n", 587 cpu, sc->cpu); 588 CPU_SET(cpu, &sc->cpus); 589 } 590 cpu++; 591 } 592 593 if (clk_get_freq(sc->clk, &freq) == 0) 594 cpufreq_dt_notify(dev, freq); 595 596 cpufreq_register(dev); 597 598 return (0); 599 error: 600 if (CPUFREQ_DT_HAVE_REGULATOR(sc)) 601 regulator_release(sc->reg); 602 return (rv); 603 } 604 605 static device_method_t cpufreq_dt_methods[] = { 606 /* Device interface */ 607 DEVMETHOD(device_identify, cpufreq_dt_identify), 608 DEVMETHOD(device_probe, cpufreq_dt_probe), 609 DEVMETHOD(device_attach, cpufreq_dt_attach), 610 611 /* cpufreq interface */ 612 DEVMETHOD(cpufreq_drv_get, cpufreq_dt_get), 613 DEVMETHOD(cpufreq_drv_set, cpufreq_dt_set), 614 DEVMETHOD(cpufreq_drv_type, cpufreq_dt_type), 615 DEVMETHOD(cpufreq_drv_settings, cpufreq_dt_settings), 616 617 DEVMETHOD_END 618 }; 619 620 static driver_t cpufreq_dt_driver = { 621 "cpufreq_dt", 622 cpufreq_dt_methods, 623 sizeof(struct cpufreq_dt_softc), 624 }; 625 626 DRIVER_MODULE(cpufreq_dt, cpu, cpufreq_dt_driver, 0, 0); 627 MODULE_VERSION(cpufreq_dt, 1); 628