xref: /freebsd/sys/arm/nvidia/tegra124/tegra124_cpufreq.c (revision aa24f48b361effe51163877d84f1b70d32b77e04)
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 = 1000000,		/* XXX 0.9 V doesn't work on all boards */
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 	2422000000ULL,
176 	2524000000ULL,
177 };
178 
179 static uint64_t cpu_max_freq[] = {
180 	2014500000ULL,
181 	2320500000ULL,
182 	2116500000ULL,
183 	2524500000ULL,
184 };
185 
186 struct tegra124_cpufreq_softc {
187 	device_t		dev;
188 	phandle_t		node;
189 
190 	regulator_t		supply_vdd_cpu;
191 	clk_t			clk_cpu_g;
192 	clk_t			clk_cpu_lp;
193 	clk_t			clk_pll_x;
194 	clk_t			clk_pll_p;
195 	clk_t			clk_dfll;
196 
197 	int 			process_id;
198 	int 			speedo_id;
199 	int 			speedo_value;
200 
201 	uint64_t		cpu_max_freq;
202 	struct cpu_volt_def	*cpu_def;
203 	struct cpu_speed_point	*speed_points;
204 	int			nspeed_points;
205 
206 	struct cpu_speed_point	*act_speed_point;
207 
208 	int			latency;
209 };
210 
211 static int cpufreq_lowest_freq = 1;
212 TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq);
213 
214 #define	DIV_ROUND_CLOSEST(val, div)	(((val) + ((div) / 2)) / (div))
215 
216 #define	ROUND_UP(val, div)	roundup(val, div)
217 #define	ROUND_DOWN(val, div)	rounddown(val, div)
218 
219 /*
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
224  */
225 static int
226 freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq)
227 {
228 	int uv, scale, min_uvolt, max_uvolt, step_uvolt;
229 	struct speedo_entry *ent;
230 	int i;
231 
232 	/* Get speedo entry with higher frequency */
233 	ent = NULL;
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];
237 			break;
238 		}
239 	}
240 	if (ent == NULL)
241 		ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1];
242 	scale = sc->cpu_def->speedo_scale;
243 
244 
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) +
248 	    ent->c0;
249 	step_uvolt = sc->cpu_def->step_uvolt;
250 	/* Round up it to next regulator step */
251 	uv = ROUND_UP(uv, step_uvolt);
252 
253 	/* Clamp result */
254 	min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt);
255 	max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt);
256 	if (uv < min_uvolt)
257 		uv =  min_uvolt;
258 	if (uv > max_uvolt)
259 		uv =  max_uvolt;
260 	return (uv);
261 
262 }
263 
264 static void
265 build_speed_points(struct tegra124_cpufreq_softc *sc) {
266 	int i;
267 
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,
274 		    cpu_freq_tbl[i]);
275 	}
276 }
277 
278 static struct cpu_speed_point *
279 get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq)
280 {
281 	int i;
282 
283 	if (sc->speed_points[0].freq >= freq)
284 		return (sc->speed_points + 0);
285 
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);
289 	}
290 
291 	return (sc->speed_points + sc->nspeed_points - 1);
292 }
293 
294 static int
295 tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)
296 {
297 	struct tegra124_cpufreq_softc *sc;
298 	int i, j, max_cnt;
299 
300 	if (sets == NULL || count == NULL)
301 		return (EINVAL);
302 
303 	sc = device_get_softc(dev);
304 	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));
305 
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)
309 			continue;
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;
313 		sets[i].dev = dev;
314 		i++;
315 	}
316 	*count = i;
317 
318 	return (0);
319 }
320 
321 static int
322 set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq)
323 {
324 	struct cpu_speed_point *point;
325 	int rv;
326 
327 	point = get_speed_point(sc, freq);
328 
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);
333 		DELAY(10000);
334 		if (rv != 0)
335 			return (rv);
336 	}
337 
338 	/* Switch supermux to PLLP first */
339 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p);
340 	if (rv != 0) {
341 		device_printf(sc->dev, "Can't set parent to PLLP\n");
342 		return (rv);
343 	}
344 
345 	/* Set PLLX frequency */
346 	rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
347 	if (rv != 0) {
348 		device_printf(sc->dev, "Can't set CPU clock frequency\n");
349 		return (rv);
350 	}
351 
352 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x);
353 	if (rv != 0) {
354 		device_printf(sc->dev, "Can't set parent to PLLX\n");
355 		return (rv);
356 	}
357 
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);
362 		if (rv != 0)
363 			return (rv);
364 	}
365 
366 	sc->act_speed_point = point;
367 
368 	return (0);
369 }
370 
371 static int
372 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf)
373 {
374 	struct tegra124_cpufreq_softc *sc;
375 	uint64_t freq;
376 	int rv;
377 
378 	if (cf == NULL || cf->freq < 0)
379 		return (EINVAL);
380 
381 	sc = device_get_softc(dev);
382 
383 	freq = cf->freq;
384 	if (freq < cpufreq_lowest_freq)
385 		freq = cpufreq_lowest_freq;
386 	freq *= 1000000;
387 	if (freq >= sc->cpu_max_freq)
388 		freq = sc->cpu_max_freq;
389 	rv = set_cpu_freq(sc, freq);
390 
391 	return (rv);
392 }
393 
394 static int
395 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf)
396 {
397 	struct tegra124_cpufreq_softc *sc;
398 
399 	if (cf == NULL)
400 		return (EINVAL);
401 
402 	sc = device_get_softc(dev);
403 	memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
404 	cf->dev = NULL;
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. */
410 	cf->dev = dev;
411 
412 	return (0);
413 }
414 
415 
416 static int
417 tegra124_cpufreq_type(device_t dev, int *type)
418 {
419 
420 	if (type == NULL)
421 		return (EINVAL);
422 	*type = CPUFREQ_TYPE_ABSOLUTE;
423 
424 	return (0);
425 }
426 
427 static int
428 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node)
429 {
430 	int rv;
431 	device_t parent_dev;
432 
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);
436 	if (rv != 0) {
437 		device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n");
438 		return (rv);
439 	}
440 
441 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g);
442 	if (rv != 0) {
443 		device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
444 		return (ENXIO);
445 	}
446 
447 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp);
448 	if (rv != 0) {
449 		device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n");
450 		return (ENXIO);
451 	}
452 
453 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x);
454 	if (rv != 0) {
455 		device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
456 		return (ENXIO);
457 	}
458 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p);
459 	if (rv != 0) {
460 		device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
461 		return (ENXIO);
462 	}
463 	rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll);
464 	if (rv != 0) {
465 		/* XXX DPLL is not implemented yet */
466 /*
467 		device_printf(sc->dev, "Cannot get 'dfll' clock\n");
468 		return (ENXIO);
469 */
470 	}
471 	return (0);
472 }
473 
474 static void
475 tegra124_cpufreq_identify(driver_t *driver, device_t parent)
476 {
477 	phandle_t root;
478 
479 	root = OF_finddevice("/");
480 	if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124"))
481 		return;
482 
483 	if (device_get_unit(parent) != 0)
484 		return;
485 	if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
486 		return;
487 	if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
488 		device_printf(parent, "add child failed\n");
489 }
490 
491 static int
492 tegra124_cpufreq_probe(device_t dev)
493 {
494 
495 	device_set_desc(dev, "CPU Frequency Control");
496 
497 	return (0);
498 }
499 
500 static int
501 tegra124_cpufreq_attach(device_t dev)
502 {
503 	struct tegra124_cpufreq_softc *sc;
504 	uint64_t freq;
505 	int rv;
506 
507 	sc = device_get_softc(dev);
508 	sc->dev = dev;
509 	sc->node = ofw_bus_get_node(device_get_parent(dev));
510 
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;
514 
515 	/* Tegra 124 */
516 	/* XXX DPLL is not implemented yet */
517 	if (1)
518 		sc->cpu_def = &tegra124_cpu_volt_pllx_def;
519 	else
520 		sc->cpu_def = &tegra124_cpu_volt_dpll_def;
521 
522 
523 	rv = get_fdt_resources(sc, sc->node);
524 	if (rv !=  0) {
525 		return (rv);
526 	}
527 
528 	build_speed_points(sc);
529 
530 	rv = clk_get_freq(sc->clk_cpu_g, &freq);
531 	if (rv != 0) {
532 		device_printf(dev, "Can't get CPU clock frequency\n");
533 		return (rv);
534 	}
535 	if (sc->speedo_id < nitems(cpu_max_freq))
536 		sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
537 	else
538 		sc->cpu_max_freq = cpu_max_freq[0];
539 	sc->act_speed_point = get_speed_point(sc, freq);
540 
541 	/* Set safe startup CPU frequency. */
542 	rv = set_cpu_freq(sc, 1632000000);
543 	if (rv != 0) {
544 		device_printf(dev, "Can't set initial CPU clock frequency\n");
545 		return (rv);
546 	}
547 
548 	/* This device is controlled by cpufreq(4). */
549 	cpufreq_register(dev);
550 
551 	return (0);
552 }
553 
554 static int
555 tegra124_cpufreq_detach(device_t dev)
556 {
557 	struct tegra124_cpufreq_softc *sc;
558 
559 	sc = device_get_softc(dev);
560 	cpufreq_unregister(dev);
561 
562 	if (sc->supply_vdd_cpu != NULL)
563 		regulator_release(sc->supply_vdd_cpu);
564 
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);
575 	return (0);
576 }
577 
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),
584 
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),
590 
591 	DEVMETHOD_END
592 };
593 
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);
599