xref: /freebsd/sys/arm/nvidia/tegra124/tegra124_cpufreq.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
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 static struct cpu_volt_def tegra124_cpu_volt_pllx_def =
142 {
143 	.min_uvolt = 1000000,		/* XXX 0.9 V doesn't work on all boards */
144 	.max_uvolt = 1260000,		/* 1.26 */
145 	.step_uvolt =  10000,		/* 10 mV */
146 	.speedo_scale = 100,
147 	.speedo_nitems = nitems(tegra124_speedo_pllx_tbl),
148 	.speedo_tbl = tegra124_speedo_pllx_tbl,
149 };
150 
151 static uint64_t cpu_freq_tbl[] = {
152 	 204000000ULL,
153 	 306000000ULL,
154 	 408000000ULL,
155 	 510000000ULL,
156 	 612000000ULL,
157 	 714000000ULL,
158 	 816000000ULL,
159 	 918000000ULL,
160 	1020000000ULL,
161 	1122000000ULL,
162 	1224000000ULL,
163 	1326000000ULL,
164 	1428000000ULL,
165 	1530000000ULL,
166 	1632000000ULL,
167 	1734000000ULL,
168 	1836000000ULL,
169 	1938000000ULL,
170 	2014000000ULL,
171 	2116000000ULL,
172 	2218000000ULL,
173 	2320000000ULL,
174 	2422000000ULL,
175 	2524000000ULL,
176 };
177 
178 static uint64_t cpu_max_freq[] = {
179 	2014500000ULL,
180 	2320500000ULL,
181 	2116500000ULL,
182 	2524500000ULL,
183 };
184 
185 struct tegra124_cpufreq_softc {
186 	device_t		dev;
187 	phandle_t		node;
188 
189 	regulator_t		supply_vdd_cpu;
190 	clk_t			clk_cpu_g;
191 	clk_t			clk_cpu_lp;
192 	clk_t			clk_pll_x;
193 	clk_t			clk_pll_p;
194 	clk_t			clk_dfll;
195 
196 	int 			process_id;
197 	int 			speedo_id;
198 	int 			speedo_value;
199 
200 	uint64_t		cpu_max_freq;
201 	struct cpu_volt_def	*cpu_def;
202 	struct cpu_speed_point	*speed_points;
203 	int			nspeed_points;
204 
205 	struct cpu_speed_point	*act_speed_point;
206 
207 	int			latency;
208 };
209 
210 static int cpufreq_lowest_freq = 1;
211 TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq);
212 
213 #define	DIV_ROUND_CLOSEST(val, div)	(((val) + ((div) / 2)) / (div))
214 
215 #define	ROUND_UP(val, div)	roundup(val, div)
216 #define	ROUND_DOWN(val, div)	rounddown(val, div)
217 
218 /*
219  * Compute requesetd voltage for given frequency and SoC process variations,
220  * - compute base voltage from speedo value using speedo table
221  * - round up voltage to next regulator step
222  * - clamp it to regulator limits
223  */
224 static int
225 freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq)
226 {
227 	int uv, scale, min_uvolt, max_uvolt, step_uvolt;
228 	struct speedo_entry *ent;
229 	int i;
230 
231 	/* Get speedo entry with higher frequency */
232 	ent = NULL;
233 	for (i = 0; i < sc->cpu_def->speedo_nitems; i++) {
234 		if (sc->cpu_def->speedo_tbl[i].freq >= freq) {
235 			ent = &sc->cpu_def->speedo_tbl[i];
236 			break;
237 		}
238 	}
239 	if (ent == NULL)
240 		ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1];
241 	scale = sc->cpu_def->speedo_scale;
242 
243 	/* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */
244 	uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale);
245 	uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) +
246 	    ent->c0;
247 	step_uvolt = sc->cpu_def->step_uvolt;
248 	/* Round up it to next regulator step */
249 	uv = ROUND_UP(uv, step_uvolt);
250 
251 	/* Clamp result */
252 	min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt);
253 	max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt);
254 	if (uv < min_uvolt)
255 		uv =  min_uvolt;
256 	if (uv > max_uvolt)
257 		uv =  max_uvolt;
258 	return (uv);
259 
260 }
261 
262 static void
263 build_speed_points(struct tegra124_cpufreq_softc *sc) {
264 	int i;
265 
266 	sc->nspeed_points = nitems(cpu_freq_tbl);
267 	sc->speed_points = malloc(sizeof(struct cpu_speed_point) *
268 	    sc->nspeed_points, M_DEVBUF, M_NOWAIT);
269 	for (i = 0; i < sc->nspeed_points; i++) {
270 		sc->speed_points[i].freq = cpu_freq_tbl[i];
271 		sc->speed_points[i].uvolt = freq_to_voltage(sc,
272 		    cpu_freq_tbl[i]);
273 	}
274 }
275 
276 static struct cpu_speed_point *
277 get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq)
278 {
279 	int i;
280 
281 	if (sc->speed_points[0].freq >= freq)
282 		return (sc->speed_points + 0);
283 
284 	for (i = 0; i < sc->nspeed_points - 1; i++) {
285 		if (sc->speed_points[i + 1].freq > freq)
286 			return (sc->speed_points + i);
287 	}
288 
289 	return (sc->speed_points + sc->nspeed_points - 1);
290 }
291 
292 static int
293 tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)
294 {
295 	struct tegra124_cpufreq_softc *sc;
296 	int i, j;
297 
298 	if (sets == NULL || count == NULL)
299 		return (EINVAL);
300 
301 	sc = device_get_softc(dev);
302 	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));
303 
304 	for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) {
305 		if (sc->cpu_max_freq < sc->speed_points[j].freq)
306 			continue;
307 		sets[i].freq = sc->speed_points[j].freq / 1000000;
308 		sets[i].volts = sc->speed_points[j].uvolt / 1000;
309 		sets[i].lat = sc->latency;
310 		sets[i].dev = dev;
311 		i++;
312 	}
313 	*count = i;
314 
315 	return (0);
316 }
317 
318 static int
319 set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq)
320 {
321 	struct cpu_speed_point *point;
322 	int rv;
323 
324 	point = get_speed_point(sc, freq);
325 
326 	if (sc->act_speed_point->uvolt < point->uvolt) {
327 		/* set cpu voltage */
328 		rv = regulator_set_voltage(sc->supply_vdd_cpu,
329 		    point->uvolt, point->uvolt);
330 		DELAY(10000);
331 		if (rv != 0)
332 			return (rv);
333 	}
334 
335 	/* Switch supermux to PLLP first */
336 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p);
337 	if (rv != 0) {
338 		device_printf(sc->dev, "Can't set parent to PLLP\n");
339 		return (rv);
340 	}
341 
342 	/* Set PLLX frequency */
343 	rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
344 	if (rv != 0) {
345 		device_printf(sc->dev, "Can't set CPU clock frequency\n");
346 		return (rv);
347 	}
348 
349 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x);
350 	if (rv != 0) {
351 		device_printf(sc->dev, "Can't set parent to PLLX\n");
352 		return (rv);
353 	}
354 
355 	if (sc->act_speed_point->uvolt > point->uvolt) {
356 		/* set cpu voltage */
357 		rv = regulator_set_voltage(sc->supply_vdd_cpu,
358 		    point->uvolt, point->uvolt);
359 		if (rv != 0)
360 			return (rv);
361 	}
362 
363 	sc->act_speed_point = point;
364 
365 	return (0);
366 }
367 
368 static int
369 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf)
370 {
371 	struct tegra124_cpufreq_softc *sc;
372 	uint64_t freq;
373 	int rv;
374 
375 	if (cf == NULL || cf->freq < 0)
376 		return (EINVAL);
377 
378 	sc = device_get_softc(dev);
379 
380 	freq = cf->freq;
381 	if (freq < cpufreq_lowest_freq)
382 		freq = cpufreq_lowest_freq;
383 	freq *= 1000000;
384 	if (freq >= sc->cpu_max_freq)
385 		freq = sc->cpu_max_freq;
386 	rv = set_cpu_freq(sc, freq);
387 
388 	return (rv);
389 }
390 
391 static int
392 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf)
393 {
394 	struct tegra124_cpufreq_softc *sc;
395 
396 	if (cf == NULL)
397 		return (EINVAL);
398 
399 	sc = device_get_softc(dev);
400 	memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
401 	cf->dev = NULL;
402 	cf->freq = sc->act_speed_point->freq / 1000000;
403 	cf->volts = sc->act_speed_point->uvolt / 1000;
404 	/* Transition latency in us. */
405 	cf->lat = sc->latency;
406 	/* Driver providing this setting. */
407 	cf->dev = dev;
408 
409 	return (0);
410 }
411 
412 static int
413 tegra124_cpufreq_type(device_t dev, int *type)
414 {
415 
416 	if (type == NULL)
417 		return (EINVAL);
418 	*type = CPUFREQ_TYPE_ABSOLUTE;
419 
420 	return (0);
421 }
422 
423 static int
424 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node)
425 {
426 	int rv;
427 	device_t parent_dev;
428 
429 	parent_dev =  device_get_parent(sc->dev);
430 	rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply",
431 	    &sc->supply_vdd_cpu);
432 	if (rv != 0) {
433 		device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n");
434 		return (rv);
435 	}
436 
437 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g);
438 	if (rv != 0) {
439 		device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
440 		return (ENXIO);
441 	}
442 
443 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp);
444 	if (rv != 0) {
445 		device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n");
446 		return (ENXIO);
447 	}
448 
449 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x);
450 	if (rv != 0) {
451 		device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
452 		return (ENXIO);
453 	}
454 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p);
455 	if (rv != 0) {
456 		device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
457 		return (ENXIO);
458 	}
459 	rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll);
460 	if (rv != 0) {
461 		/* XXX DPLL is not implemented yet */
462 /*
463 		device_printf(sc->dev, "Cannot get 'dfll' clock\n");
464 		return (ENXIO);
465 */
466 	}
467 	return (0);
468 }
469 
470 static void
471 tegra124_cpufreq_identify(driver_t *driver, device_t parent)
472 {
473 	phandle_t root;
474 
475 	root = OF_finddevice("/");
476 	if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124"))
477 		return;
478 
479 	if (device_get_unit(parent) != 0)
480 		return;
481 	if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
482 		return;
483 	if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
484 		device_printf(parent, "add child failed\n");
485 }
486 
487 static int
488 tegra124_cpufreq_probe(device_t dev)
489 {
490 
491 	device_set_desc(dev, "CPU Frequency Control");
492 
493 	return (0);
494 }
495 
496 static int
497 tegra124_cpufreq_attach(device_t dev)
498 {
499 	struct tegra124_cpufreq_softc *sc;
500 	uint64_t freq;
501 	int rv;
502 
503 	sc = device_get_softc(dev);
504 	sc->dev = dev;
505 	sc->node = ofw_bus_get_node(device_get_parent(dev));
506 
507 	sc->process_id = tegra_sku_info.cpu_process_id;
508 	sc->speedo_id = tegra_sku_info.cpu_speedo_id;
509 	sc->speedo_value = tegra_sku_info.cpu_speedo_value;
510 
511 	/* Tegra 124 */
512 	/* XXX DPLL is not implemented yet */
513 	if (1)
514 		sc->cpu_def = &tegra124_cpu_volt_pllx_def;
515 	else
516 		sc->cpu_def = &tegra124_cpu_volt_dpll_def;
517 
518 	rv = get_fdt_resources(sc, sc->node);
519 	if (rv !=  0) {
520 		return (rv);
521 	}
522 
523 	build_speed_points(sc);
524 
525 	rv = clk_get_freq(sc->clk_cpu_g, &freq);
526 	if (rv != 0) {
527 		device_printf(dev, "Can't get CPU clock frequency\n");
528 		return (rv);
529 	}
530 	if (sc->speedo_id < nitems(cpu_max_freq))
531 		sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
532 	else
533 		sc->cpu_max_freq = cpu_max_freq[0];
534 	sc->act_speed_point = get_speed_point(sc, freq);
535 
536 	/* Set safe startup CPU frequency. */
537 	rv = set_cpu_freq(sc, 1632000000);
538 	if (rv != 0) {
539 		device_printf(dev, "Can't set initial CPU clock frequency\n");
540 		return (rv);
541 	}
542 
543 	/* This device is controlled by cpufreq(4). */
544 	cpufreq_register(dev);
545 
546 	return (0);
547 }
548 
549 static int
550 tegra124_cpufreq_detach(device_t dev)
551 {
552 	struct tegra124_cpufreq_softc *sc;
553 
554 	sc = device_get_softc(dev);
555 	cpufreq_unregister(dev);
556 
557 	if (sc->supply_vdd_cpu != NULL)
558 		regulator_release(sc->supply_vdd_cpu);
559 
560 	if (sc->clk_cpu_g != NULL)
561 		clk_release(sc->clk_cpu_g);
562 	if (sc->clk_cpu_lp != NULL)
563 		clk_release(sc->clk_cpu_lp);
564 	if (sc->clk_pll_x != NULL)
565 		clk_release(sc->clk_pll_x);
566 	if (sc->clk_pll_p != NULL)
567 		clk_release(sc->clk_pll_p);
568 	if (sc->clk_dfll != NULL)
569 		clk_release(sc->clk_dfll);
570 	return (0);
571 }
572 
573 static device_method_t tegra124_cpufreq_methods[] = {
574 	/* Device interface */
575 	DEVMETHOD(device_identify,	tegra124_cpufreq_identify),
576 	DEVMETHOD(device_probe,		tegra124_cpufreq_probe),
577 	DEVMETHOD(device_attach,	tegra124_cpufreq_attach),
578 	DEVMETHOD(device_detach,	tegra124_cpufreq_detach),
579 
580 	/* cpufreq interface */
581 	DEVMETHOD(cpufreq_drv_set,	tegra124_cpufreq_set),
582 	DEVMETHOD(cpufreq_drv_get,	tegra124_cpufreq_get),
583 	DEVMETHOD(cpufreq_drv_settings,	tegra124_cpufreq_settings),
584 	DEVMETHOD(cpufreq_drv_type,	tegra124_cpufreq_type),
585 
586 	DEVMETHOD_END
587 };
588 
589 static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver,
590     tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc));
591 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver, NULL, NULL);
592