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