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