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) ((((val) + ((div) - 1)) / (div)) * (div)) 218 #define ROUND_DOWN(val, div) (((val) / (div)) * (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 rv = clk_set_freq(sc->clk_cpu_g, point->freq, CLK_SET_ROUND_DOWN); 339 if (rv != 0) { 340 device_printf(sc->dev, "Can't set CPU clock frequency\n"); 341 return (rv); 342 } 343 344 if (sc->act_speed_point->uvolt > point->uvolt) { 345 /* set cpu voltage */ 346 rv = regulator_set_voltage(sc->supply_vdd_cpu, 347 point->uvolt, point->uvolt); 348 if (rv != 0) 349 return (rv); 350 } 351 352 sc->act_speed_point = point; 353 354 return (0); 355 } 356 357 static int 358 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf) 359 { 360 struct tegra124_cpufreq_softc *sc; 361 uint64_t freq; 362 int rv; 363 364 if (cf == NULL || cf->freq < 0) 365 return (EINVAL); 366 367 sc = device_get_softc(dev); 368 369 freq = cf->freq; 370 if (freq < cpufreq_lowest_freq) 371 freq = cpufreq_lowest_freq; 372 freq *= 1000000; 373 if (freq >= sc->cpu_max_freq) 374 freq = sc->cpu_max_freq; 375 rv = set_cpu_freq(sc, freq); 376 377 return (rv); 378 } 379 380 static int 381 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf) 382 { 383 struct tegra124_cpufreq_softc *sc; 384 385 if (cf == NULL) 386 return (EINVAL); 387 388 sc = device_get_softc(dev); 389 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 390 cf->dev = NULL; 391 cf->freq = sc->act_speed_point->freq / 1000000; 392 cf->volts = sc->act_speed_point->uvolt / 1000; 393 /* Transition latency in us. */ 394 cf->lat = sc->latency; 395 /* Driver providing this setting. */ 396 cf->dev = dev; 397 398 return (0); 399 } 400 401 402 static int 403 tegra124_cpufreq_type(device_t dev, int *type) 404 { 405 406 if (type == NULL) 407 return (EINVAL); 408 *type = CPUFREQ_TYPE_ABSOLUTE; 409 410 return (0); 411 } 412 413 static int 414 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node) 415 { 416 int rv; 417 device_t parent_dev; 418 419 parent_dev = device_get_parent(sc->dev); 420 rv = regulator_get_by_ofw_property(parent_dev, "vdd-cpu-supply", 421 &sc->supply_vdd_cpu); 422 if (rv != 0) { 423 device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n"); 424 return (rv); 425 } 426 427 rv = clk_get_by_ofw_name(parent_dev, "cpu_g", &sc->clk_cpu_g); 428 if (rv != 0) { 429 device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv); 430 return (ENXIO); 431 } 432 433 rv = clk_get_by_ofw_name(parent_dev, "cpu_lp", &sc->clk_cpu_lp); 434 if (rv != 0) { 435 device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n"); 436 return (ENXIO); 437 } 438 439 rv = clk_get_by_ofw_name(parent_dev, "pll_x", &sc->clk_pll_x); 440 if (rv != 0) { 441 device_printf(sc->dev, "Cannot get 'pll_x' clock\n"); 442 return (ENXIO); 443 } 444 rv = clk_get_by_ofw_name(parent_dev, "pll_p", &sc->clk_pll_p); 445 if (rv != 0) { 446 device_printf(parent_dev, "Cannot get 'pll_p' clock\n"); 447 return (ENXIO); 448 } 449 rv = clk_get_by_ofw_name(parent_dev, "dfll", &sc->clk_dfll); 450 if (rv != 0) { 451 /* XXX DPLL is not implemented yet */ 452 /* 453 device_printf(sc->dev, "Cannot get 'dfll' clock\n"); 454 return (ENXIO); 455 */ 456 } 457 return (0); 458 } 459 460 static void 461 tegra124_cpufreq_identify(driver_t *driver, device_t parent) 462 { 463 464 if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL) 465 return; 466 if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL) 467 device_printf(parent, "add child failed\n"); 468 } 469 470 static int 471 tegra124_cpufreq_probe(device_t dev) 472 { 473 474 if (device_get_unit(dev) != 0) 475 return (ENXIO); 476 device_set_desc(dev, "CPU Frequency Control"); 477 478 return (0); 479 } 480 481 static int 482 tegra124_cpufreq_attach(device_t dev) 483 { 484 struct tegra124_cpufreq_softc *sc; 485 uint64_t freq; 486 int rv; 487 488 sc = device_get_softc(dev); 489 sc->dev = dev; 490 sc->node = ofw_bus_get_node(device_get_parent(dev)); 491 492 sc->process_id = tegra_sku_info.cpu_process_id; 493 sc->speedo_id = tegra_sku_info.cpu_speedo_id; 494 sc->speedo_value = tegra_sku_info.cpu_speedo_value; 495 496 /* Tegra 124 */ 497 /* XXX DPLL is not implemented yet */ 498 if (1) 499 sc->cpu_def = &tegra124_cpu_volt_pllx_def; 500 else 501 sc->cpu_def = &tegra124_cpu_volt_dpll_def; 502 503 504 rv = get_fdt_resources(sc, sc->node); 505 if (rv != 0) { 506 return (rv); 507 } 508 509 build_speed_points(sc); 510 511 rv = clk_get_freq(sc->clk_cpu_g, &freq); 512 if (rv != 0) { 513 device_printf(dev, "Can't get CPU clock frequency\n"); 514 return (rv); 515 } 516 if (sc->speedo_id < nitems(cpu_max_freq)) 517 sc->cpu_max_freq = cpu_max_freq[sc->speedo_id]; 518 else 519 sc->cpu_max_freq = cpu_max_freq[0]; 520 sc->act_speed_point = get_speed_point(sc, freq); 521 522 /* Set safe startup CPU frequency. */ 523 rv = set_cpu_freq(sc, 1632000000); 524 if (rv != 0) { 525 device_printf(dev, "Can't set initial CPU clock frequency\n"); 526 return (rv); 527 } 528 529 /* This device is controlled by cpufreq(4). */ 530 cpufreq_register(dev); 531 532 return (0); 533 } 534 535 static int 536 tegra124_cpufreq_detach(device_t dev) 537 { 538 struct tegra124_cpufreq_softc *sc; 539 540 sc = device_get_softc(dev); 541 cpufreq_unregister(dev); 542 543 if (sc->supply_vdd_cpu != NULL) 544 regulator_release(sc->supply_vdd_cpu); 545 546 if (sc->clk_cpu_g != NULL) 547 clk_release(sc->clk_cpu_g); 548 if (sc->clk_cpu_lp != NULL) 549 clk_release(sc->clk_cpu_lp); 550 if (sc->clk_pll_x != NULL) 551 clk_release(sc->clk_pll_x); 552 if (sc->clk_pll_p != NULL) 553 clk_release(sc->clk_pll_p); 554 if (sc->clk_dfll != NULL) 555 clk_release(sc->clk_dfll); 556 return (0); 557 } 558 559 static device_method_t tegra124_cpufreq_methods[] = { 560 /* Device interface */ 561 DEVMETHOD(device_identify, tegra124_cpufreq_identify), 562 DEVMETHOD(device_probe, tegra124_cpufreq_probe), 563 DEVMETHOD(device_attach, tegra124_cpufreq_attach), 564 DEVMETHOD(device_detach, tegra124_cpufreq_detach), 565 566 /* cpufreq interface */ 567 DEVMETHOD(cpufreq_drv_set, tegra124_cpufreq_set), 568 DEVMETHOD(cpufreq_drv_get, tegra124_cpufreq_get), 569 DEVMETHOD(cpufreq_drv_settings, tegra124_cpufreq_settings), 570 DEVMETHOD(cpufreq_drv_type, tegra124_cpufreq_type), 571 572 DEVMETHOD_END 573 }; 574 575 static devclass_t tegra124_cpufreq_devclass; 576 static driver_t tegra124_cpufreq_driver = { 577 "tegra124_cpufreq", 578 tegra124_cpufreq_methods, 579 sizeof(struct tegra124_cpufreq_softc), 580 }; 581 582 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver, 583 tegra124_cpufreq_devclass, 0, 0); 584