2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
34 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
39 #include <machine/bus.h>
40 #include <machine/cpu.h>
42 #include <dev/extres/clk/clk.h>
43 #include <dev/extres/regulator/regulator.h>
44 #include <dev/ofw/ofw_bus_subr.h>
46 #include <arm/nvidia/tegra_efuse.h>
48 #include "cpufreq_if.h"
52 /* CPU voltage table 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 */
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 */
69 struct cpu_speed_point {
70 uint64_t freq; /* Frequecy */
71 int uvolt; /* Requested voltage */
74 static struct speedo_entry tegra124_speedo_dpll_tbl[] =
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},
103 static struct cpu_volt_def tegra124_cpu_volt_dpll_def =
105 .min_uvolt = 900000, /* 0.9 V */
106 .max_uvolt = 1260000, /* 1.26 */
107 .step_uvolt = 10000, /* 10 mV */
109 .speedo_nitems = nitems(tegra124_speedo_dpll_tbl),
110 .speedo_tbl = tegra124_speedo_dpll_tbl,
113 static struct speedo_entry tegra124_speedo_pllx_tbl[] =
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},
142 static struct cpu_volt_def tegra124_cpu_volt_pllx_def =
144 .min_uvolt = 1000000, /* XXX 0.9 V doesn't work on all boards */
145 .max_uvolt = 1260000, /* 1.26 */
146 .step_uvolt = 10000, /* 10 mV */
148 .speedo_nitems = nitems(tegra124_speedo_pllx_tbl),
149 .speedo_tbl = tegra124_speedo_pllx_tbl,
152 static uint64_t cpu_freq_tbl[] = {
179 static uint64_t cpu_max_freq[] = {
186 struct tegra124_cpufreq_softc {
190 regulator_t supply_vdd_cpu;
201 uint64_t cpu_max_freq;
202 struct cpu_volt_def *cpu_def;
203 struct cpu_speed_point *speed_points;
206 struct cpu_speed_point *act_speed_point;
211 static int cpufreq_lowest_freq = 1;
212 TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq);
214 #define DIV_ROUND_CLOSEST(val, div) (((val) + ((div) / 2)) / (div))
216 #define ROUND_UP(val, div) roundup(val, div)
217 #define ROUND_DOWN(val, div) rounddown(val, div)
220 * Compute requesetd voltage for given frequency and SoC process variations,
221 * - compute base voltage from speedo value using speedo table
222 * - round up voltage to next regulator step
223 * - clamp it to regulator limits
226 freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq)
228 int uv, scale, min_uvolt, max_uvolt, step_uvolt;
229 struct speedo_entry *ent;
232 /* Get speedo entry with higher frequency */
234 for (i = 0; i < sc->cpu_def->speedo_nitems; i++) {
235 if (sc->cpu_def->speedo_tbl[i].freq >= freq) {
236 ent = &sc->cpu_def->speedo_tbl[i];
241 ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1];
242 scale = sc->cpu_def->speedo_scale;
245 /* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */
246 uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale);
247 uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) +
249 step_uvolt = sc->cpu_def->step_uvolt;
250 /* Round up it to next regulator step */
251 uv = ROUND_UP(uv, step_uvolt);
254 min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt);
255 max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt);
265 build_speed_points(struct tegra124_cpufreq_softc *sc) {
268 sc->nspeed_points = nitems(cpu_freq_tbl);
269 sc->speed_points = malloc(sizeof(struct cpu_speed_point) *
270 sc->nspeed_points, M_DEVBUF, M_NOWAIT);
271 for (i = 0; i < sc->nspeed_points; i++) {
272 sc->speed_points[i].freq = cpu_freq_tbl[i];
273 sc->speed_points[i].uvolt = freq_to_voltage(sc,
278 static struct cpu_speed_point *
279 get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq)
283 if (sc->speed_points[0].freq >= freq)
284 return (sc->speed_points + 0);
286 for (i = 0; i < sc->nspeed_points - 1; i++) {
287 if (sc->speed_points[i + 1].freq > freq)
288 return (sc->speed_points + i);
291 return (sc->speed_points + sc->nspeed_points - 1);
295 tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)
297 struct tegra124_cpufreq_softc *sc;
300 if (sets == NULL || count == NULL)
303 sc = device_get_softc(dev);
304 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));
306 max_cnt = min(sc->nspeed_points, *count);
307 for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) {
308 if (sc->cpu_max_freq < sc->speed_points[j].freq)
310 sets[i].freq = sc->speed_points[j].freq / 1000000;
311 sets[i].volts = sc->speed_points[j].uvolt / 1000;
312 sets[i].lat = sc->latency;
322 set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq)
324 struct cpu_speed_point *point;
327 point = get_speed_point(sc, freq);
329 if (sc->act_speed_point->uvolt < point->uvolt) {
330 /* set cpu voltage */
331 rv = regulator_set_voltage(sc->supply_vdd_cpu,
332 point->uvolt, point->uvolt);
338 /* Switch supermux to PLLP first */
339 rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p);
341 device_printf(sc->dev, "Can't set parent to PLLP\n");
345 /* Set PLLX frequency */
346 rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
348 device_printf(sc->dev, "Can't set CPU clock frequency\n");
352 rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x);
354 device_printf(sc->dev, "Can't set parent to PLLX\n");
358 if (sc->act_speed_point->uvolt > point->uvolt) {
359 /* set cpu voltage */
360 rv = regulator_set_voltage(sc->supply_vdd_cpu,
361 point->uvolt, point->uvolt);
366 sc->act_speed_point = point;
372 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf)
374 struct tegra124_cpufreq_softc *sc;
378 if (cf == NULL || cf->freq < 0)
381 sc = device_get_softc(dev);
384 if (freq < cpufreq_lowest_freq)
385 freq = cpufreq_lowest_freq;
387 if (freq >= sc->cpu_max_freq)
388 freq = sc->cpu_max_freq;
389 rv = set_cpu_freq(sc, freq);
395 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf)
397 struct tegra124_cpufreq_softc *sc;
402 sc = device_get_softc(dev);
403 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
405 cf->freq = sc->act_speed_point->freq / 1000000;
406 cf->volts = sc->act_speed_point->uvolt / 1000;
407 /* Transition latency in us. */
408 cf->lat = sc->latency;
409 /* Driver providing this setting. */
417 tegra124_cpufreq_type(device_t dev, int *type)
422 *type = CPUFREQ_TYPE_ABSOLUTE;
428 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node)
433 parent_dev = device_get_parent(sc->dev);
434 rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply",
435 &sc->supply_vdd_cpu);
437 device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n");
441 rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g);
443 device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
447 rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp);
449 device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n");
453 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x);
455 device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
458 rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p);
460 device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
463 rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll);
465 /* XXX DPLL is not implemented yet */
467 device_printf(sc->dev, "Cannot get 'dfll' clock\n");
475 tegra124_cpufreq_identify(driver_t *driver, device_t parent)
479 root = OF_finddevice("/");
480 if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124"))
483 if (device_get_unit(parent) != 0)
485 if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
487 if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
488 device_printf(parent, "add child failed\n");
492 tegra124_cpufreq_probe(device_t dev)
495 device_set_desc(dev, "CPU Frequency Control");
501 tegra124_cpufreq_attach(device_t dev)
503 struct tegra124_cpufreq_softc *sc;
507 sc = device_get_softc(dev);
509 sc->node = ofw_bus_get_node(device_get_parent(dev));
511 sc->process_id = tegra_sku_info.cpu_process_id;
512 sc->speedo_id = tegra_sku_info.cpu_speedo_id;
513 sc->speedo_value = tegra_sku_info.cpu_speedo_value;
516 /* XXX DPLL is not implemented yet */
518 sc->cpu_def = &tegra124_cpu_volt_pllx_def;
520 sc->cpu_def = &tegra124_cpu_volt_dpll_def;
523 rv = get_fdt_resources(sc, sc->node);
528 build_speed_points(sc);
530 rv = clk_get_freq(sc->clk_cpu_g, &freq);
532 device_printf(dev, "Can't get CPU clock frequency\n");
535 if (sc->speedo_id < nitems(cpu_max_freq))
536 sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
538 sc->cpu_max_freq = cpu_max_freq[0];
539 sc->act_speed_point = get_speed_point(sc, freq);
541 /* Set safe startup CPU frequency. */
542 rv = set_cpu_freq(sc, 1632000000);
544 device_printf(dev, "Can't set initial CPU clock frequency\n");
548 /* This device is controlled by cpufreq(4). */
549 cpufreq_register(dev);
555 tegra124_cpufreq_detach(device_t dev)
557 struct tegra124_cpufreq_softc *sc;
559 sc = device_get_softc(dev);
560 cpufreq_unregister(dev);
562 if (sc->supply_vdd_cpu != NULL)
563 regulator_release(sc->supply_vdd_cpu);
565 if (sc->clk_cpu_g != NULL)
566 clk_release(sc->clk_cpu_g);
567 if (sc->clk_cpu_lp != NULL)
568 clk_release(sc->clk_cpu_lp);
569 if (sc->clk_pll_x != NULL)
570 clk_release(sc->clk_pll_x);
571 if (sc->clk_pll_p != NULL)
572 clk_release(sc->clk_pll_p);
573 if (sc->clk_dfll != NULL)
574 clk_release(sc->clk_dfll);
578 static device_method_t tegra124_cpufreq_methods[] = {
579 /* Device interface */
580 DEVMETHOD(device_identify, tegra124_cpufreq_identify),
581 DEVMETHOD(device_probe, tegra124_cpufreq_probe),
582 DEVMETHOD(device_attach, tegra124_cpufreq_attach),
583 DEVMETHOD(device_detach, tegra124_cpufreq_detach),
585 /* cpufreq interface */
586 DEVMETHOD(cpufreq_drv_set, tegra124_cpufreq_set),
587 DEVMETHOD(cpufreq_drv_get, tegra124_cpufreq_get),
588 DEVMETHOD(cpufreq_drv_settings, tegra124_cpufreq_settings),
589 DEVMETHOD(cpufreq_drv_type, tegra124_cpufreq_type),
594 static devclass_t tegra124_cpufreq_devclass;
595 static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver,
596 tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc));
597 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver,
598 tegra124_cpufreq_devclass, NULL, NULL);