1 /*- 2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3 * All rights reserved. 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 AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, 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 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/bus.h> 33 #include <sys/cpu.h> 34 #include <sys/kernel.h> 35 #include <sys/lock.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 39 #include <machine/bus.h> 40 #include <machine/cpu.h> 41 42 #include <dev/extres/clk/clk.h> 43 #include <dev/extres/regulator/regulator.h> 44 #include <dev/ofw/ofw_bus_subr.h> 45 46 #include <arm/nvidia/tegra_efuse.h> 47 48 #include "cpufreq_if.h" 49 50 #define XXX 51 52 /* CPU voltage table entry */ 53 struct speedo_entry { 54 uint64_t freq; /* Frequency point */ 55 int c0; /* Coeeficient values for */ 56 int c1; /* quadratic equation: */ 57 int c2; /* c2 * speedo^2 + c1 * speedo + c0 */ 58 }; 59 60 struct cpu_volt_def { 61 int min_uvolt; /* Min allowed CPU voltage */ 62 int max_uvolt; /* Max allowed CPU voltage */ 63 int step_uvolt; /* Step of CPU voltage */ 64 int speedo_scale; /* Scaling factor for cvt */ 65 int speedo_nitems; /* Size of speedo table */ 66 struct speedo_entry *speedo_tbl; /* CPU voltage table */ 67 }; 68 69 struct cpu_speed_point { 70 uint64_t freq; /* Frequecy */ 71 int uvolt; /* Requested voltage */ 72 }; 73 74 static struct speedo_entry tegra124_speedo_dpll_tbl[] = 75 { 76 { 204000000ULL, 1112619, -29295, 402}, 77 { 306000000ULL, 1150460, -30585, 402}, 78 { 408000000ULL, 1190122, -31865, 402}, 79 { 510000000ULL, 1231606, -33155, 402}, 80 { 612000000ULL, 1274912, -34435, 402}, 81 { 714000000ULL, 1320040, -35725, 402}, 82 { 816000000ULL, 1366990, -37005, 402}, 83 { 918000000ULL, 1415762, -38295, 402}, 84 {1020000000ULL, 1466355, -39575, 402}, 85 {1122000000ULL, 1518771, -40865, 402}, 86 {1224000000ULL, 1573009, -42145, 402}, 87 {1326000000ULL, 1629068, -43435, 402}, 88 {1428000000ULL, 1686950, -44715, 402}, 89 {1530000000ULL, 1746653, -46005, 402}, 90 {1632000000ULL, 1808179, -47285, 402}, 91 {1734000000ULL, 1871526, -48575, 402}, 92 {1836000000ULL, 1936696, -49855, 402}, 93 {1938000000ULL, 2003687, -51145, 402}, 94 {2014500000ULL, 2054787, -52095, 402}, 95 {2116500000ULL, 2124957, -53385, 402}, 96 {2218500000ULL, 2196950, -54665, 402}, 97 {2320500000ULL, 2270765, -55955, 402}, 98 {2320500000ULL, 2270765, -55955, 402}, 99 {2422500000ULL, 2346401, -57235, 402}, 100 {2524500000ULL, 2437299, -58535, 402}, 101 }; 102 103 static struct cpu_volt_def tegra124_cpu_volt_dpll_def = 104 { 105 .min_uvolt = 900000, /* 0.9 V */ 106 .max_uvolt = 1260000, /* 1.26 */ 107 .step_uvolt = 10000, /* 10 mV */ 108 .speedo_scale = 100, 109 .speedo_nitems = nitems(tegra124_speedo_dpll_tbl), 110 .speedo_tbl = tegra124_speedo_dpll_tbl, 111 }; 112 113 static struct speedo_entry tegra124_speedo_pllx_tbl[] = 114 { 115 { 204000000ULL, 800000, 0, 0}, 116 { 306000000ULL, 800000, 0, 0}, 117 { 408000000ULL, 800000, 0, 0}, 118 { 510000000ULL, 800000, 0, 0}, 119 { 612000000ULL, 800000, 0, 0}, 120 { 714000000ULL, 800000, 0, 0}, 121 { 816000000ULL, 820000, 0, 0}, 122 { 918000000ULL, 840000, 0, 0}, 123 {1020000000ULL, 880000, 0, 0}, 124 {1122000000ULL, 900000, 0, 0}, 125 {1224000000ULL, 930000, 0, 0}, 126 {1326000000ULL, 960000, 0, 0}, 127 {1428000000ULL, 990000, 0, 0}, 128 {1530000000ULL, 1020000, 0, 0}, 129 {1632000000ULL, 1070000, 0, 0}, 130 {1734000000ULL, 1100000, 0, 0}, 131 {1836000000ULL, 1140000, 0, 0}, 132 {1938000000ULL, 1180000, 0, 0}, 133 {2014500000ULL, 1220000, 0, 0}, 134 {2116500000ULL, 1260000, 0, 0}, 135 {2218500000ULL, 1310000, 0, 0}, 136 {2320500000ULL, 1360000, 0, 0}, 137 {2397000000ULL, 1400000, 0, 0}, 138 {2499000000ULL, 1400000, 0, 0}, 139 }; 140 141 static struct cpu_volt_def tegra124_cpu_volt_pllx_def = 142 { 143 .min_uvolt = 1000000, /* XXX 0.9 V doesn't work on all boards */ 144 .max_uvolt = 1260000, /* 1.26 */ 145 .step_uvolt = 10000, /* 10 mV */ 146 .speedo_scale = 100, 147 .speedo_nitems = nitems(tegra124_speedo_pllx_tbl), 148 .speedo_tbl = tegra124_speedo_pllx_tbl, 149 }; 150 151 static uint64_t cpu_freq_tbl[] = { 152 204000000ULL, 153 306000000ULL, 154 408000000ULL, 155 510000000ULL, 156 612000000ULL, 157 714000000ULL, 158 816000000ULL, 159 918000000ULL, 160 1020000000ULL, 161 1122000000ULL, 162 1224000000ULL, 163 1326000000ULL, 164 1428000000ULL, 165 1530000000ULL, 166 1632000000ULL, 167 1734000000ULL, 168 1836000000ULL, 169 1938000000ULL, 170 2014000000ULL, 171 2116000000ULL, 172 2218000000ULL, 173 2320000000ULL, 174 2422000000ULL, 175 2524000000ULL, 176 }; 177 178 static uint64_t cpu_max_freq[] = { 179 2014500000ULL, 180 2320500000ULL, 181 2116500000ULL, 182 2524500000ULL, 183 }; 184 185 struct tegra124_cpufreq_softc { 186 device_t dev; 187 phandle_t node; 188 189 regulator_t supply_vdd_cpu; 190 clk_t clk_cpu_g; 191 clk_t clk_cpu_lp; 192 clk_t clk_pll_x; 193 clk_t clk_pll_p; 194 clk_t clk_dfll; 195 196 int process_id; 197 int speedo_id; 198 int speedo_value; 199 200 uint64_t cpu_max_freq; 201 struct cpu_volt_def *cpu_def; 202 struct cpu_speed_point *speed_points; 203 int nspeed_points; 204 205 struct cpu_speed_point *act_speed_point; 206 207 int latency; 208 }; 209 210 static int cpufreq_lowest_freq = 1; 211 TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq); 212 213 #define DIV_ROUND_CLOSEST(val, div) (((val) + ((div) / 2)) / (div)) 214 215 #define ROUND_UP(val, div) roundup(val, div) 216 #define ROUND_DOWN(val, div) rounddown(val, div) 217 218 /* 219 * Compute requesetd voltage for given frequency and SoC process variations, 220 * - compute base voltage from speedo value using speedo table 221 * - round up voltage to next regulator step 222 * - clamp it to regulator limits 223 */ 224 static int 225 freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq) 226 { 227 int uv, scale, min_uvolt, max_uvolt, step_uvolt; 228 struct speedo_entry *ent; 229 int i; 230 231 /* Get speedo entry with higher frequency */ 232 ent = NULL; 233 for (i = 0; i < sc->cpu_def->speedo_nitems; i++) { 234 if (sc->cpu_def->speedo_tbl[i].freq >= freq) { 235 ent = &sc->cpu_def->speedo_tbl[i]; 236 break; 237 } 238 } 239 if (ent == NULL) 240 ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1]; 241 scale = sc->cpu_def->speedo_scale; 242 243 /* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */ 244 uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale); 245 uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) + 246 ent->c0; 247 step_uvolt = sc->cpu_def->step_uvolt; 248 /* Round up it to next regulator step */ 249 uv = ROUND_UP(uv, step_uvolt); 250 251 /* Clamp result */ 252 min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt); 253 max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt); 254 if (uv < min_uvolt) 255 uv = min_uvolt; 256 if (uv > max_uvolt) 257 uv = max_uvolt; 258 return (uv); 259 260 } 261 262 static void 263 build_speed_points(struct tegra124_cpufreq_softc *sc) { 264 int i; 265 266 sc->nspeed_points = nitems(cpu_freq_tbl); 267 sc->speed_points = malloc(sizeof(struct cpu_speed_point) * 268 sc->nspeed_points, M_DEVBUF, M_NOWAIT); 269 for (i = 0; i < sc->nspeed_points; i++) { 270 sc->speed_points[i].freq = cpu_freq_tbl[i]; 271 sc->speed_points[i].uvolt = freq_to_voltage(sc, 272 cpu_freq_tbl[i]); 273 } 274 } 275 276 static struct cpu_speed_point * 277 get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq) 278 { 279 int i; 280 281 if (sc->speed_points[0].freq >= freq) 282 return (sc->speed_points + 0); 283 284 for (i = 0; i < sc->nspeed_points - 1; i++) { 285 if (sc->speed_points[i + 1].freq > freq) 286 return (sc->speed_points + i); 287 } 288 289 return (sc->speed_points + sc->nspeed_points - 1); 290 } 291 292 static int 293 tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count) 294 { 295 struct tegra124_cpufreq_softc *sc; 296 int i, j; 297 298 if (sets == NULL || count == NULL) 299 return (EINVAL); 300 301 sc = device_get_softc(dev); 302 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count)); 303 304 for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) { 305 if (sc->cpu_max_freq < sc->speed_points[j].freq) 306 continue; 307 sets[i].freq = sc->speed_points[j].freq / 1000000; 308 sets[i].volts = sc->speed_points[j].uvolt / 1000; 309 sets[i].lat = sc->latency; 310 sets[i].dev = dev; 311 i++; 312 } 313 *count = i; 314 315 return (0); 316 } 317 318 static int 319 set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq) 320 { 321 struct cpu_speed_point *point; 322 int rv; 323 324 point = get_speed_point(sc, freq); 325 326 if (sc->act_speed_point->uvolt < point->uvolt) { 327 /* set cpu voltage */ 328 rv = regulator_set_voltage(sc->supply_vdd_cpu, 329 point->uvolt, point->uvolt); 330 DELAY(10000); 331 if (rv != 0) 332 return (rv); 333 } 334 335 /* Switch supermux to PLLP first */ 336 rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p); 337 if (rv != 0) { 338 device_printf(sc->dev, "Can't set parent to PLLP\n"); 339 return (rv); 340 } 341 342 /* Set PLLX frequency */ 343 rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN); 344 if (rv != 0) { 345 device_printf(sc->dev, "Can't set CPU clock frequency\n"); 346 return (rv); 347 } 348 349 rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x); 350 if (rv != 0) { 351 device_printf(sc->dev, "Can't set parent to PLLX\n"); 352 return (rv); 353 } 354 355 if (sc->act_speed_point->uvolt > point->uvolt) { 356 /* set cpu voltage */ 357 rv = regulator_set_voltage(sc->supply_vdd_cpu, 358 point->uvolt, point->uvolt); 359 if (rv != 0) 360 return (rv); 361 } 362 363 sc->act_speed_point = point; 364 365 return (0); 366 } 367 368 static int 369 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf) 370 { 371 struct tegra124_cpufreq_softc *sc; 372 uint64_t freq; 373 int rv; 374 375 if (cf == NULL || cf->freq < 0) 376 return (EINVAL); 377 378 sc = device_get_softc(dev); 379 380 freq = cf->freq; 381 if (freq < cpufreq_lowest_freq) 382 freq = cpufreq_lowest_freq; 383 freq *= 1000000; 384 if (freq >= sc->cpu_max_freq) 385 freq = sc->cpu_max_freq; 386 rv = set_cpu_freq(sc, freq); 387 388 return (rv); 389 } 390 391 static int 392 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf) 393 { 394 struct tegra124_cpufreq_softc *sc; 395 396 if (cf == NULL) 397 return (EINVAL); 398 399 sc = device_get_softc(dev); 400 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 401 cf->dev = NULL; 402 cf->freq = sc->act_speed_point->freq / 1000000; 403 cf->volts = sc->act_speed_point->uvolt / 1000; 404 /* Transition latency in us. */ 405 cf->lat = sc->latency; 406 /* Driver providing this setting. */ 407 cf->dev = dev; 408 409 return (0); 410 } 411 412 static int 413 tegra124_cpufreq_type(device_t dev, int *type) 414 { 415 416 if (type == NULL) 417 return (EINVAL); 418 *type = CPUFREQ_TYPE_ABSOLUTE; 419 420 return (0); 421 } 422 423 static int 424 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node) 425 { 426 int rv; 427 device_t parent_dev; 428 429 parent_dev = device_get_parent(sc->dev); 430 rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply", 431 &sc->supply_vdd_cpu); 432 if (rv != 0) { 433 device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n"); 434 return (rv); 435 } 436 437 rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g); 438 if (rv != 0) { 439 device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv); 440 return (ENXIO); 441 } 442 443 rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp); 444 if (rv != 0) { 445 device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n"); 446 return (ENXIO); 447 } 448 449 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x); 450 if (rv != 0) { 451 device_printf(sc->dev, "Cannot get 'pll_x' clock\n"); 452 return (ENXIO); 453 } 454 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p); 455 if (rv != 0) { 456 device_printf(parent_dev, "Cannot get 'pll_p' clock\n"); 457 return (ENXIO); 458 } 459 rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll); 460 if (rv != 0) { 461 /* XXX DPLL is not implemented yet */ 462 /* 463 device_printf(sc->dev, "Cannot get 'dfll' clock\n"); 464 return (ENXIO); 465 */ 466 } 467 return (0); 468 } 469 470 static void 471 tegra124_cpufreq_identify(driver_t *driver, device_t parent) 472 { 473 phandle_t root; 474 475 root = OF_finddevice("/"); 476 if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124")) 477 return; 478 479 if (device_get_unit(parent) != 0) 480 return; 481 if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL) 482 return; 483 if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL) 484 device_printf(parent, "add child failed\n"); 485 } 486 487 static int 488 tegra124_cpufreq_probe(device_t dev) 489 { 490 491 device_set_desc(dev, "CPU Frequency Control"); 492 493 return (0); 494 } 495 496 static int 497 tegra124_cpufreq_attach(device_t dev) 498 { 499 struct tegra124_cpufreq_softc *sc; 500 uint64_t freq; 501 int rv; 502 503 sc = device_get_softc(dev); 504 sc->dev = dev; 505 sc->node = ofw_bus_get_node(device_get_parent(dev)); 506 507 sc->process_id = tegra_sku_info.cpu_process_id; 508 sc->speedo_id = tegra_sku_info.cpu_speedo_id; 509 sc->speedo_value = tegra_sku_info.cpu_speedo_value; 510 511 /* Tegra 124 */ 512 /* XXX DPLL is not implemented yet */ 513 if (1) 514 sc->cpu_def = &tegra124_cpu_volt_pllx_def; 515 else 516 sc->cpu_def = &tegra124_cpu_volt_dpll_def; 517 518 rv = get_fdt_resources(sc, sc->node); 519 if (rv != 0) { 520 return (rv); 521 } 522 523 build_speed_points(sc); 524 525 rv = clk_get_freq(sc->clk_cpu_g, &freq); 526 if (rv != 0) { 527 device_printf(dev, "Can't get CPU clock frequency\n"); 528 return (rv); 529 } 530 if (sc->speedo_id < nitems(cpu_max_freq)) 531 sc->cpu_max_freq = cpu_max_freq[sc->speedo_id]; 532 else 533 sc->cpu_max_freq = cpu_max_freq[0]; 534 sc->act_speed_point = get_speed_point(sc, freq); 535 536 /* Set safe startup CPU frequency. */ 537 rv = set_cpu_freq(sc, 1632000000); 538 if (rv != 0) { 539 device_printf(dev, "Can't set initial CPU clock frequency\n"); 540 return (rv); 541 } 542 543 /* This device is controlled by cpufreq(4). */ 544 cpufreq_register(dev); 545 546 return (0); 547 } 548 549 static int 550 tegra124_cpufreq_detach(device_t dev) 551 { 552 struct tegra124_cpufreq_softc *sc; 553 554 sc = device_get_softc(dev); 555 cpufreq_unregister(dev); 556 557 if (sc->supply_vdd_cpu != NULL) 558 regulator_release(sc->supply_vdd_cpu); 559 560 if (sc->clk_cpu_g != NULL) 561 clk_release(sc->clk_cpu_g); 562 if (sc->clk_cpu_lp != NULL) 563 clk_release(sc->clk_cpu_lp); 564 if (sc->clk_pll_x != NULL) 565 clk_release(sc->clk_pll_x); 566 if (sc->clk_pll_p != NULL) 567 clk_release(sc->clk_pll_p); 568 if (sc->clk_dfll != NULL) 569 clk_release(sc->clk_dfll); 570 return (0); 571 } 572 573 static device_method_t tegra124_cpufreq_methods[] = { 574 /* Device interface */ 575 DEVMETHOD(device_identify, tegra124_cpufreq_identify), 576 DEVMETHOD(device_probe, tegra124_cpufreq_probe), 577 DEVMETHOD(device_attach, tegra124_cpufreq_attach), 578 DEVMETHOD(device_detach, tegra124_cpufreq_detach), 579 580 /* cpufreq interface */ 581 DEVMETHOD(cpufreq_drv_set, tegra124_cpufreq_set), 582 DEVMETHOD(cpufreq_drv_get, tegra124_cpufreq_get), 583 DEVMETHOD(cpufreq_drv_settings, tegra124_cpufreq_settings), 584 DEVMETHOD(cpufreq_drv_type, tegra124_cpufreq_type), 585 586 DEVMETHOD_END 587 }; 588 589 static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver, 590 tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc)); 591 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver, NULL, NULL); 592