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