1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright 2020 Michal Meloun <mmel@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/bus.h> 32 #include <sys/cpu.h> 33 #include <sys/kernel.h> 34 #include <sys/lock.h> 35 #include <sys/malloc.h> 36 #include <sys/module.h> 37 38 #include <machine/bus.h> 39 #include <machine/cpu.h> 40 41 #include <dev/extres/clk/clk.h> 42 #include <dev/extres/regulator/regulator.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 45 #include <arm/nvidia/tegra_efuse.h> 46 47 #include "cpufreq_if.h" 48 49 /* CPU voltage table entry */ 50 struct speedo_entry { 51 uint64_t freq; /* Frequency point */ 52 int c0; /* Coeeficient values for */ 53 int c1; /* quadratic equation: */ 54 int c2; /* c2 * speedo^2 + c1 * speedo + c0 */ 55 }; 56 57 struct cpu_volt_def { 58 int min_uvolt; /* Min allowed CPU voltage */ 59 int max_uvolt; /* Max allowed CPU voltage */ 60 int step_uvolt; /* Step of CPU voltage */ 61 int speedo_scale; /* Scaling factor for cvt */ 62 int speedo_nitems; /* Size of speedo table */ 63 struct speedo_entry *speedo_tbl; /* CPU voltage table */ 64 }; 65 66 struct cpu_speed_point { 67 uint64_t freq; /* Frequecy */ 68 int uvolt; /* Requested voltage */ 69 }; 70 71 static struct speedo_entry tegra210_speedo_tbl[] = 72 { 73 {204000000UL, 1007452, -23865, 370}, 74 {306000000UL, 1052709, -24875, 370}, 75 {408000000UL, 1099069, -25895, 370}, 76 {510000000UL, 1146534, -26905, 370}, 77 {612000000UL, 1195102, -27915, 370}, 78 {714000000UL, 1244773, -28925, 370}, 79 {816000000UL, 1295549, -29935, 370}, 80 {918000000UL, 1347428, -30955, 370}, 81 {1020000000UL, 1400411, -31965, 370}, 82 {1122000000UL, 1454497, -32975, 370}, 83 {1224000000UL, 1509687, -33985, 370}, 84 {1326000000UL, 1565981, -35005, 370}, 85 {1428000000UL, 1623379, -36015, 370}, 86 {1530000000UL, 1681880, -37025, 370}, 87 {1632000000UL, 1741485, -38035, 370}, 88 {1734000000UL, 1802194, -39055, 370}, 89 {1836000000UL, 1864006, -40065, 370}, 90 {1912500000UL, 1910780, -40815, 370}, 91 {2014500000UL, 1227000, 0, 0}, 92 {2218500000UL, 1227000, 0, 0}, 93 }; 94 95 static struct cpu_volt_def tegra210_cpu_volt_def = 96 { 97 .min_uvolt = 900000, /* 0.9 V */ 98 .max_uvolt = 1227000, /* 1.227 */ 99 .step_uvolt = 10000, /* 10 mV */ 100 .speedo_scale = 100, 101 .speedo_nitems = nitems(tegra210_speedo_tbl), 102 .speedo_tbl = tegra210_speedo_tbl, 103 }; 104 105 static uint64_t cpu_max_freq[] = { 106 1912500000UL, 107 1912500000UL, 108 2218500000UL, 109 1785000000UL, 110 1632000000UL, 111 1912500000UL, 112 2014500000UL, 113 1734000000UL, 114 1683000000UL, 115 1555500000UL, 116 1504500000UL, 117 }; 118 119 static uint64_t cpu_freq_tbl[] = { 120 204000000UL, 121 306000000UL, 122 408000000UL, 123 510000000UL, 124 612000000UL, 125 714000000UL, 126 816000000UL, 127 918000000UL, 128 1020000000UL, 129 1122000000UL, 130 1224000000UL, 131 1326000000UL, 132 1428000000UL, 133 1530000000UL, 134 1632000000UL, 135 1734000000UL, 136 1836000000UL, 137 1912500000UL, 138 2014500000UL, 139 2218500000UL, 140 }; 141 142 struct tegra210_cpufreq_softc { 143 device_t dev; 144 phandle_t node; 145 146 clk_t clk_cpu_g; 147 clk_t clk_pll_x; 148 clk_t clk_pll_p; 149 clk_t clk_dfll; 150 151 int process_id; 152 int speedo_id; 153 int speedo_value; 154 155 uint64_t cpu_max_freq; 156 struct cpu_volt_def *cpu_def; 157 struct cpu_speed_point *speed_points; 158 int nspeed_points; 159 160 struct cpu_speed_point *act_speed_point; 161 162 int latency; 163 }; 164 165 static int cpufreq_lowest_freq = 1; 166 TUNABLE_INT("hw.tegra210.cpufreq.lowest_freq", &cpufreq_lowest_freq); 167 168 #define DIV_ROUND_CLOSEST(val, div) (((val) + ((div) / 2)) / (div)) 169 170 #define ROUND_UP(val, div) roundup(val, div) 171 #define ROUND_DOWN(val, div) rounddown(val, div) 172 173 /* 174 * Compute requesetd voltage for given frequency and SoC process variations, 175 * - compute base voltage from speedo value using speedo table 176 * - round up voltage to next regulator step 177 * - clamp it to regulator limits 178 */ 179 static int 180 freq_to_voltage(struct tegra210_cpufreq_softc *sc, uint64_t freq) 181 { 182 int uv, scale, min_uvolt, max_uvolt, step_uvolt; 183 struct speedo_entry *ent; 184 int i; 185 186 /* Get speedo entry with higher frequency */ 187 ent = NULL; 188 for (i = 0; i < sc->cpu_def->speedo_nitems; i++) { 189 if (sc->cpu_def->speedo_tbl[i].freq >= freq) { 190 ent = &sc->cpu_def->speedo_tbl[i]; 191 break; 192 } 193 } 194 if (ent == NULL) 195 ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1]; 196 scale = sc->cpu_def->speedo_scale; 197 198 199 /* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */ 200 uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale); 201 uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) + 202 ent->c0; 203 step_uvolt = sc->cpu_def->step_uvolt; 204 /* Round up it to next regulator step */ 205 uv = ROUND_UP(uv, step_uvolt); 206 207 /* Clamp result */ 208 min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt); 209 max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt); 210 if (uv < min_uvolt) 211 uv = min_uvolt; 212 if (uv > max_uvolt) 213 uv = max_uvolt; 214 return (uv); 215 216 } 217 218 static void 219 build_speed_points(struct tegra210_cpufreq_softc *sc) { 220 int i; 221 222 sc->nspeed_points = nitems(cpu_freq_tbl); 223 sc->speed_points = malloc(sizeof(struct cpu_speed_point) * 224 sc->nspeed_points, M_DEVBUF, M_NOWAIT); 225 for (i = 0; i < sc->nspeed_points; i++) { 226 sc->speed_points[i].freq = cpu_freq_tbl[i]; 227 sc->speed_points[i].uvolt = freq_to_voltage(sc, 228 cpu_freq_tbl[i]); 229 } 230 } 231 232 static struct cpu_speed_point * 233 get_speed_point(struct tegra210_cpufreq_softc *sc, uint64_t freq) 234 { 235 int i; 236 237 if (sc->speed_points[0].freq >= freq) 238 return (sc->speed_points + 0); 239 240 for (i = 0; i < sc->nspeed_points - 1; i++) { 241 if (sc->speed_points[i + 1].freq > freq) 242 return (sc->speed_points + i); 243 } 244 245 return (sc->speed_points + sc->nspeed_points - 1); 246 } 247 248 static int 249 tegra210_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count) 250 { 251 struct tegra210_cpufreq_softc *sc; 252 int i, j; 253 254 if (sets == NULL || count == NULL) 255 return (EINVAL); 256 257 sc = device_get_softc(dev); 258 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count)); 259 260 for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) { 261 if (sc->cpu_max_freq < sc->speed_points[j].freq) 262 continue; 263 sets[i].freq = sc->speed_points[j].freq / 1000000; 264 sets[i].volts = sc->speed_points[j].uvolt / 1000; 265 sets[i].lat = sc->latency; 266 sets[i].dev = dev; 267 i++; 268 } 269 *count = i; 270 271 return (0); 272 } 273 274 static int 275 set_cpu_freq(struct tegra210_cpufreq_softc *sc, uint64_t freq) 276 { 277 struct cpu_speed_point *point; 278 int rv; 279 280 point = get_speed_point(sc, freq); 281 282 /* Set PLLX frequency */ 283 rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN); 284 if (rv != 0) { 285 device_printf(sc->dev, "Can't set CPU clock frequency\n"); 286 return (rv); 287 } 288 289 sc->act_speed_point = point; 290 291 return (0); 292 } 293 294 static int 295 tegra210_cpufreq_set(device_t dev, const struct cf_setting *cf) 296 { 297 struct tegra210_cpufreq_softc *sc; 298 uint64_t freq; 299 int rv; 300 301 if (cf == NULL || cf->freq < 0) 302 return (EINVAL); 303 304 sc = device_get_softc(dev); 305 306 freq = cf->freq; 307 if (freq < cpufreq_lowest_freq) 308 freq = cpufreq_lowest_freq; 309 freq *= 1000000; 310 if (freq >= sc->cpu_max_freq) 311 freq = sc->cpu_max_freq; 312 rv = set_cpu_freq(sc, freq); 313 314 return (rv); 315 } 316 317 static int 318 tegra210_cpufreq_get(device_t dev, struct cf_setting *cf) 319 { 320 struct tegra210_cpufreq_softc *sc; 321 322 if (cf == NULL) 323 return (EINVAL); 324 325 sc = device_get_softc(dev); 326 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 327 cf->dev = NULL; 328 cf->freq = sc->act_speed_point->freq / 1000000; 329 cf->volts = sc->act_speed_point->uvolt / 1000; 330 /* Transition latency in us. */ 331 cf->lat = sc->latency; 332 /* Driver providing this setting. */ 333 cf->dev = dev; 334 335 return (0); 336 } 337 338 339 static int 340 tegra210_cpufreq_type(device_t dev, int *type) 341 { 342 343 if (type == NULL) 344 return (EINVAL); 345 *type = CPUFREQ_TYPE_ABSOLUTE; 346 347 return (0); 348 } 349 350 static int 351 get_fdt_resources(struct tegra210_cpufreq_softc *sc, phandle_t node) 352 { 353 int rv; 354 device_t parent_dev; 355 356 parent_dev = device_get_parent(sc->dev); 357 358 rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g); 359 if (rv != 0) { 360 device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv); 361 return (ENXIO); 362 } 363 364 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x); 365 if (rv != 0) { 366 device_printf(sc->dev, "Cannot get 'pll_x' clock\n"); 367 return (ENXIO); 368 } 369 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p); 370 if (rv != 0) { 371 device_printf(parent_dev, "Cannot get 'pll_p' clock\n"); 372 return (ENXIO); 373 } 374 rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll); 375 376 /* XXX DPLL is not implemented yet */ 377 #if 0 378 if (rv != 0) { 379 device_printf(sc->dev, "Cannot get 'dfll' clock\n"); 380 return (ENXIO); 381 } 382 #endif 383 return (0); 384 } 385 386 static void 387 tegra210_cpufreq_identify(driver_t *driver, device_t parent) 388 { 389 phandle_t root; 390 391 root = OF_finddevice("/"); 392 if (!ofw_bus_node_is_compatible(root, "nvidia,tegra210")) 393 return; 394 395 if (device_get_unit(parent) != 0) 396 return; 397 if (device_find_child(parent, "tegra210_cpufreq", -1) != NULL) 398 return; 399 if (BUS_ADD_CHILD(parent, 0, "tegra210_cpufreq", -1) == NULL) 400 device_printf(parent, "add child failed\n"); 401 } 402 403 static int 404 tegra210_cpufreq_probe(device_t dev) 405 { 406 407 device_set_desc(dev, "CPU Frequency Control"); 408 409 return (0); 410 } 411 412 static int 413 tegra210_cpufreq_attach(device_t dev) 414 { 415 struct tegra210_cpufreq_softc *sc; 416 uint64_t freq; 417 int rv; 418 419 sc = device_get_softc(dev); 420 sc->dev = dev; 421 sc->node = ofw_bus_get_node(device_get_parent(dev)); 422 423 sc->process_id = tegra_sku_info.cpu_process_id; 424 sc->speedo_id = tegra_sku_info.cpu_speedo_id; 425 sc->speedo_value = tegra_sku_info.cpu_speedo_value; 426 427 sc->cpu_def = &tegra210_cpu_volt_def; 428 429 rv = get_fdt_resources(sc, sc->node); 430 if (rv != 0) { 431 return (rv); 432 } 433 434 build_speed_points(sc); 435 436 rv = clk_get_freq(sc->clk_cpu_g, &freq); 437 if (rv != 0) { 438 device_printf(dev, "Can't get CPU clock frequency\n"); 439 return (rv); 440 } 441 if (sc->speedo_id < nitems(cpu_max_freq)) 442 sc->cpu_max_freq = cpu_max_freq[sc->speedo_id]; 443 else 444 sc->cpu_max_freq = cpu_max_freq[0]; 445 sc->act_speed_point = get_speed_point(sc, freq); 446 447 /* Set safe startup CPU frequency. */ 448 rv = set_cpu_freq(sc, 1632000000); 449 if (rv != 0) { 450 device_printf(dev, "Can't set initial CPU clock frequency\n"); 451 return (rv); 452 } 453 454 /* This device is controlled by cpufreq(4). */ 455 cpufreq_register(dev); 456 457 return (0); 458 } 459 460 static int 461 tegra210_cpufreq_detach(device_t dev) 462 { 463 struct tegra210_cpufreq_softc *sc; 464 465 sc = device_get_softc(dev); 466 cpufreq_unregister(dev); 467 468 if (sc->clk_cpu_g != NULL) 469 clk_release(sc->clk_cpu_g); 470 if (sc->clk_pll_x != NULL) 471 clk_release(sc->clk_pll_x); 472 if (sc->clk_pll_p != NULL) 473 clk_release(sc->clk_pll_p); 474 if (sc->clk_dfll != NULL) 475 clk_release(sc->clk_dfll); 476 return (0); 477 } 478 479 static device_method_t tegra210_cpufreq_methods[] = { 480 /* Device interface */ 481 DEVMETHOD(device_identify, tegra210_cpufreq_identify), 482 DEVMETHOD(device_probe, tegra210_cpufreq_probe), 483 DEVMETHOD(device_attach, tegra210_cpufreq_attach), 484 DEVMETHOD(device_detach, tegra210_cpufreq_detach), 485 486 /* cpufreq interface */ 487 DEVMETHOD(cpufreq_drv_set, tegra210_cpufreq_set), 488 DEVMETHOD(cpufreq_drv_get, tegra210_cpufreq_get), 489 DEVMETHOD(cpufreq_drv_settings, tegra210_cpufreq_settings), 490 DEVMETHOD(cpufreq_drv_type, tegra210_cpufreq_type), 491 492 DEVMETHOD_END 493 }; 494 495 static DEFINE_CLASS_0(tegra210_cpufreq, tegra210_cpufreq_driver, 496 tegra210_cpufreq_methods, sizeof(struct tegra210_cpufreq_softc)); 497 DRIVER_MODULE(tegra210_cpufreq, cpu, tegra210_cpufreq_driver, NULL, NULL); 498