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