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 142 static struct cpu_volt_def tegra124_cpu_volt_pllx_def = 143 { 144 .min_uvolt = 900000, /* 0.9 V */ 145 .max_uvolt = 1260000, /* 1.26 */ 146 .step_uvolt = 10000, /* 10 mV */ 147 .speedo_scale = 100, 148 .speedo_nitems = nitems(tegra124_speedo_pllx_tbl), 149 .speedo_tbl = tegra124_speedo_pllx_tbl, 150 }; 151 152 static uint64_t cpu_freq_tbl[] = { 153 204000000ULL, 154 306000000ULL, 155 408000000ULL, 156 510000000ULL, 157 612000000ULL, 158 714000000ULL, 159 816000000ULL, 160 918000000ULL, 161 1020000000ULL, 162 1122000000ULL, 163 1224000000ULL, 164 1326000000ULL, 165 1428000000ULL, 166 1530000000ULL, 167 1632000000ULL, 168 1734000000ULL, 169 1836000000ULL, 170 1938000000ULL, 171 2014000000ULL, 172 2116000000ULL, 173 2218000000ULL, 174 2320000000ULL, 175 2320000000ULL, 176 2422000000ULL, 177 2524000000ULL, 178 }; 179 180 static uint64_t cpu_max_freq[] = { 181 2014500000ULL, 182 2320500000ULL, 183 2116500000ULL, 184 2524500000ULL, 185 }; 186 187 struct tegra124_cpufreq_softc { 188 device_t dev; 189 phandle_t node; 190 191 regulator_t supply_vdd_cpu; 192 clk_t clk_cpu_g; 193 clk_t clk_cpu_lp; 194 clk_t clk_pll_x; 195 clk_t clk_pll_p; 196 clk_t clk_dfll; 197 198 int process_id; 199 int speedo_id; 200 int speedo_value; 201 202 uint64_t cpu_max_freq; 203 struct cpu_volt_def *cpu_def; 204 struct cpu_speed_point *speed_points; 205 int nspeed_points; 206 207 struct cpu_speed_point *act_speed_point; 208 209 int latency; 210 }; 211 212 static int cpufreq_lowest_freq = 1; 213 TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq); 214 215 #define DIV_ROUND_CLOSEST(val, div) (((val) + ((div) / 2)) / (div)) 216 217 #define ROUND_UP(val, div) roundup(val, div) 218 #define ROUND_DOWN(val, div) rounddown(val, div) 219 220 /* 221 * Compute requesetd voltage for given frequency and SoC process variations, 222 * - compute base voltage from speedo value using speedo table 223 * - round up voltage to next regulator step 224 * - clamp it to regulator limits 225 */ 226 static int 227 freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq) 228 { 229 int uv, scale, min_uvolt, max_uvolt, step_uvolt; 230 struct speedo_entry *ent; 231 int i; 232 233 /* Get speedo entry with higher frequency */ 234 ent = NULL; 235 for (i = 0; i < sc->cpu_def->speedo_nitems; i++) { 236 if (sc->cpu_def->speedo_tbl[i].freq >= freq) { 237 ent = &sc->cpu_def->speedo_tbl[i]; 238 break; 239 } 240 } 241 if (ent == NULL) 242 ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1]; 243 scale = sc->cpu_def->speedo_scale; 244 245 246 /* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */ 247 uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale); 248 uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) + 249 ent->c0; 250 step_uvolt = sc->cpu_def->step_uvolt; 251 /* Round up it to next regulator step */ 252 uv = ROUND_UP(uv, step_uvolt); 253 254 /* Clamp result */ 255 min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt); 256 max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt); 257 if (uv < min_uvolt) 258 uv = min_uvolt; 259 if (uv > max_uvolt) 260 uv = max_uvolt; 261 return (uv); 262 263 } 264 265 static void 266 build_speed_points(struct tegra124_cpufreq_softc *sc) { 267 int i; 268 269 sc->nspeed_points = nitems(cpu_freq_tbl); 270 sc->speed_points = malloc(sizeof(struct cpu_speed_point) * 271 sc->nspeed_points, M_DEVBUF, M_NOWAIT); 272 for (i = 0; i < sc->nspeed_points; i++) { 273 sc->speed_points[i].freq = cpu_freq_tbl[i]; 274 sc->speed_points[i].uvolt = freq_to_voltage(sc, 275 cpu_freq_tbl[i]); 276 } 277 } 278 279 static struct cpu_speed_point * 280 get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq) 281 { 282 int i; 283 284 if (sc->speed_points[0].freq >= freq) 285 return (sc->speed_points + 0); 286 287 for (i = 0; i < sc->nspeed_points - 1; i++) { 288 if (sc->speed_points[i + 1].freq > freq) 289 return (sc->speed_points + i); 290 } 291 292 return (sc->speed_points + sc->nspeed_points - 1); 293 } 294 295 static int 296 tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count) 297 { 298 struct tegra124_cpufreq_softc *sc; 299 int i, j, max_cnt; 300 301 if (sets == NULL || count == NULL) 302 return (EINVAL); 303 304 sc = device_get_softc(dev); 305 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count)); 306 307 max_cnt = min(sc->nspeed_points, *count); 308 for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) { 309 if (sc->cpu_max_freq < sc->speed_points[j].freq) 310 continue; 311 sets[i].freq = sc->speed_points[j].freq / 1000000; 312 sets[i].volts = sc->speed_points[j].uvolt / 1000; 313 sets[i].lat = sc->latency; 314 sets[i].dev = dev; 315 i++; 316 } 317 *count = i; 318 319 return (0); 320 } 321 322 static int 323 set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq) 324 { 325 struct cpu_speed_point *point; 326 int rv; 327 328 point = get_speed_point(sc, freq); 329 330 if (sc->act_speed_point->uvolt < point->uvolt) { 331 /* set cpu voltage */ 332 rv = regulator_set_voltage(sc->supply_vdd_cpu, 333 point->uvolt, point->uvolt); 334 DELAY(10000); 335 if (rv != 0) 336 return (rv); 337 } 338 339 /* Switch supermux to PLLP first */ 340 rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p); 341 if (rv != 0) { 342 device_printf(sc->dev, "Can't set parent to PLLP\n"); 343 return (rv); 344 } 345 346 /* Set PLLX frequency */ 347 rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN); 348 if (rv != 0) { 349 device_printf(sc->dev, "Can't set CPU clock frequency\n"); 350 return (rv); 351 } 352 353 rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x); 354 if (rv != 0) { 355 device_printf(sc->dev, "Can't set parent to PLLX\n"); 356 return (rv); 357 } 358 359 if (sc->act_speed_point->uvolt > point->uvolt) { 360 /* set cpu voltage */ 361 rv = regulator_set_voltage(sc->supply_vdd_cpu, 362 point->uvolt, point->uvolt); 363 if (rv != 0) 364 return (rv); 365 } 366 367 sc->act_speed_point = point; 368 369 return (0); 370 } 371 372 static int 373 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf) 374 { 375 struct tegra124_cpufreq_softc *sc; 376 uint64_t freq; 377 int rv; 378 379 if (cf == NULL || cf->freq < 0) 380 return (EINVAL); 381 382 sc = device_get_softc(dev); 383 384 freq = cf->freq; 385 if (freq < cpufreq_lowest_freq) 386 freq = cpufreq_lowest_freq; 387 freq *= 1000000; 388 if (freq >= sc->cpu_max_freq) 389 freq = sc->cpu_max_freq; 390 rv = set_cpu_freq(sc, freq); 391 392 return (rv); 393 } 394 395 static int 396 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf) 397 { 398 struct tegra124_cpufreq_softc *sc; 399 400 if (cf == NULL) 401 return (EINVAL); 402 403 sc = device_get_softc(dev); 404 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 405 cf->dev = NULL; 406 cf->freq = sc->act_speed_point->freq / 1000000; 407 cf->volts = sc->act_speed_point->uvolt / 1000; 408 /* Transition latency in us. */ 409 cf->lat = sc->latency; 410 /* Driver providing this setting. */ 411 cf->dev = dev; 412 413 return (0); 414 } 415 416 417 static int 418 tegra124_cpufreq_type(device_t dev, int *type) 419 { 420 421 if (type == NULL) 422 return (EINVAL); 423 *type = CPUFREQ_TYPE_ABSOLUTE; 424 425 return (0); 426 } 427 428 static int 429 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node) 430 { 431 int rv; 432 device_t parent_dev; 433 434 parent_dev = device_get_parent(sc->dev); 435 rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply", 436 &sc->supply_vdd_cpu); 437 if (rv != 0) { 438 device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n"); 439 return (rv); 440 } 441 442 rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g); 443 if (rv != 0) { 444 device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv); 445 return (ENXIO); 446 } 447 448 rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp); 449 if (rv != 0) { 450 device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n"); 451 return (ENXIO); 452 } 453 454 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x); 455 if (rv != 0) { 456 device_printf(sc->dev, "Cannot get 'pll_x' clock\n"); 457 return (ENXIO); 458 } 459 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p); 460 if (rv != 0) { 461 device_printf(parent_dev, "Cannot get 'pll_p' clock\n"); 462 return (ENXIO); 463 } 464 rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll); 465 if (rv != 0) { 466 /* XXX DPLL is not implemented yet */ 467 /* 468 device_printf(sc->dev, "Cannot get 'dfll' clock\n"); 469 return (ENXIO); 470 */ 471 } 472 return (0); 473 } 474 475 static void 476 tegra124_cpufreq_identify(driver_t *driver, device_t parent) 477 { 478 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 if (device_get_unit(dev) != 0) 490 return (ENXIO); 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 519 rv = get_fdt_resources(sc, sc->node); 520 if (rv != 0) { 521 return (rv); 522 } 523 524 build_speed_points(sc); 525 526 rv = clk_get_freq(sc->clk_cpu_g, &freq); 527 if (rv != 0) { 528 device_printf(dev, "Can't get CPU clock frequency\n"); 529 return (rv); 530 } 531 if (sc->speedo_id < nitems(cpu_max_freq)) 532 sc->cpu_max_freq = cpu_max_freq[sc->speedo_id]; 533 else 534 sc->cpu_max_freq = cpu_max_freq[0]; 535 sc->act_speed_point = get_speed_point(sc, freq); 536 537 /* Set safe startup CPU frequency. */ 538 rv = set_cpu_freq(sc, 1632000000); 539 if (rv != 0) { 540 device_printf(dev, "Can't set initial CPU clock frequency\n"); 541 return (rv); 542 } 543 544 /* This device is controlled by cpufreq(4). */ 545 cpufreq_register(dev); 546 547 return (0); 548 } 549 550 static int 551 tegra124_cpufreq_detach(device_t dev) 552 { 553 struct tegra124_cpufreq_softc *sc; 554 555 sc = device_get_softc(dev); 556 cpufreq_unregister(dev); 557 558 if (sc->supply_vdd_cpu != NULL) 559 regulator_release(sc->supply_vdd_cpu); 560 561 if (sc->clk_cpu_g != NULL) 562 clk_release(sc->clk_cpu_g); 563 if (sc->clk_cpu_lp != NULL) 564 clk_release(sc->clk_cpu_lp); 565 if (sc->clk_pll_x != NULL) 566 clk_release(sc->clk_pll_x); 567 if (sc->clk_pll_p != NULL) 568 clk_release(sc->clk_pll_p); 569 if (sc->clk_dfll != NULL) 570 clk_release(sc->clk_dfll); 571 return (0); 572 } 573 574 static device_method_t tegra124_cpufreq_methods[] = { 575 /* Device interface */ 576 DEVMETHOD(device_identify, tegra124_cpufreq_identify), 577 DEVMETHOD(device_probe, tegra124_cpufreq_probe), 578 DEVMETHOD(device_attach, tegra124_cpufreq_attach), 579 DEVMETHOD(device_detach, tegra124_cpufreq_detach), 580 581 /* cpufreq interface */ 582 DEVMETHOD(cpufreq_drv_set, tegra124_cpufreq_set), 583 DEVMETHOD(cpufreq_drv_get, tegra124_cpufreq_get), 584 DEVMETHOD(cpufreq_drv_settings, tegra124_cpufreq_settings), 585 DEVMETHOD(cpufreq_drv_type, tegra124_cpufreq_type), 586 587 DEVMETHOD_END 588 }; 589 590 static devclass_t tegra124_cpufreq_devclass; 591 static driver_t tegra124_cpufreq_driver = { 592 "tegra124_cpufreq", 593 tegra124_cpufreq_methods, 594 sizeof(struct tegra124_cpufreq_softc), 595 }; 596 597 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver, 598 tegra124_cpufreq_devclass, 0, 0); 599