xref: /freebsd/sys/arm/nvidia/tegra124/tegra124_cpufreq.c (revision d27ba3088424e53eabc0b0186ed122ec43119501)
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, max_cnt;
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 	max_cnt = min(sc->nspeed_points, *count);
305 	for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) {
306 		if (sc->cpu_max_freq < sc->speed_points[j].freq)
307 			continue;
308 		sets[i].freq = sc->speed_points[j].freq / 1000000;
309 		sets[i].volts = sc->speed_points[j].uvolt / 1000;
310 		sets[i].lat = sc->latency;
311 		sets[i].dev = dev;
312 		i++;
313 	}
314 	*count = i;
315 
316 	return (0);
317 }
318 
319 static int
320 set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq)
321 {
322 	struct cpu_speed_point *point;
323 	int rv;
324 
325 	point = get_speed_point(sc, freq);
326 
327 	if (sc->act_speed_point->uvolt < point->uvolt) {
328 		/* set cpu voltage */
329 		rv = regulator_set_voltage(sc->supply_vdd_cpu,
330 		    point->uvolt, point->uvolt);
331 		DELAY(10000);
332 		if (rv != 0)
333 			return (rv);
334 	}
335 
336 	/* Switch supermux to PLLP first */
337 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p);
338 	if (rv != 0) {
339 		device_printf(sc->dev, "Can't set parent to PLLP\n");
340 		return (rv);
341 	}
342 
343 	/* Set PLLX frequency */
344 	rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
345 	if (rv != 0) {
346 		device_printf(sc->dev, "Can't set CPU clock frequency\n");
347 		return (rv);
348 	}
349 
350 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x);
351 	if (rv != 0) {
352 		device_printf(sc->dev, "Can't set parent to PLLX\n");
353 		return (rv);
354 	}
355 
356 	if (sc->act_speed_point->uvolt > point->uvolt) {
357 		/* set cpu voltage */
358 		rv = regulator_set_voltage(sc->supply_vdd_cpu,
359 		    point->uvolt, point->uvolt);
360 		if (rv != 0)
361 			return (rv);
362 	}
363 
364 	sc->act_speed_point = point;
365 
366 	return (0);
367 }
368 
369 static int
370 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf)
371 {
372 	struct tegra124_cpufreq_softc *sc;
373 	uint64_t freq;
374 	int rv;
375 
376 	if (cf == NULL || cf->freq < 0)
377 		return (EINVAL);
378 
379 	sc = device_get_softc(dev);
380 
381 	freq = cf->freq;
382 	if (freq < cpufreq_lowest_freq)
383 		freq = cpufreq_lowest_freq;
384 	freq *= 1000000;
385 	if (freq >= sc->cpu_max_freq)
386 		freq = sc->cpu_max_freq;
387 	rv = set_cpu_freq(sc, freq);
388 
389 	return (rv);
390 }
391 
392 static int
393 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf)
394 {
395 	struct tegra124_cpufreq_softc *sc;
396 
397 	if (cf == NULL)
398 		return (EINVAL);
399 
400 	sc = device_get_softc(dev);
401 	memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
402 	cf->dev = NULL;
403 	cf->freq = sc->act_speed_point->freq / 1000000;
404 	cf->volts = sc->act_speed_point->uvolt / 1000;
405 	/* Transition latency in us. */
406 	cf->lat = sc->latency;
407 	/* Driver providing this setting. */
408 	cf->dev = dev;
409 
410 	return (0);
411 }
412 
413 static int
414 tegra124_cpufreq_type(device_t dev, int *type)
415 {
416 
417 	if (type == NULL)
418 		return (EINVAL);
419 	*type = CPUFREQ_TYPE_ABSOLUTE;
420 
421 	return (0);
422 }
423 
424 static int
425 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node)
426 {
427 	int rv;
428 	device_t parent_dev;
429 
430 	parent_dev =  device_get_parent(sc->dev);
431 	rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply",
432 	    &sc->supply_vdd_cpu);
433 	if (rv != 0) {
434 		device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n");
435 		return (rv);
436 	}
437 
438 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g);
439 	if (rv != 0) {
440 		device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
441 		return (ENXIO);
442 	}
443 
444 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp);
445 	if (rv != 0) {
446 		device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n");
447 		return (ENXIO);
448 	}
449 
450 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x);
451 	if (rv != 0) {
452 		device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
453 		return (ENXIO);
454 	}
455 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p);
456 	if (rv != 0) {
457 		device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
458 		return (ENXIO);
459 	}
460 	rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll);
461 	if (rv != 0) {
462 		/* XXX DPLL is not implemented yet */
463 /*
464 		device_printf(sc->dev, "Cannot get 'dfll' clock\n");
465 		return (ENXIO);
466 */
467 	}
468 	return (0);
469 }
470 
471 static void
472 tegra124_cpufreq_identify(driver_t *driver, device_t parent)
473 {
474 	phandle_t root;
475 
476 	root = OF_finddevice("/");
477 	if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124"))
478 		return;
479 
480 	if (device_get_unit(parent) != 0)
481 		return;
482 	if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
483 		return;
484 	if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
485 		device_printf(parent, "add child failed\n");
486 }
487 
488 static int
489 tegra124_cpufreq_probe(device_t dev)
490 {
491 
492 	device_set_desc(dev, "CPU Frequency Control");
493 
494 	return (0);
495 }
496 
497 static int
498 tegra124_cpufreq_attach(device_t dev)
499 {
500 	struct tegra124_cpufreq_softc *sc;
501 	uint64_t freq;
502 	int rv;
503 
504 	sc = device_get_softc(dev);
505 	sc->dev = dev;
506 	sc->node = ofw_bus_get_node(device_get_parent(dev));
507 
508 	sc->process_id = tegra_sku_info.cpu_process_id;
509 	sc->speedo_id = tegra_sku_info.cpu_speedo_id;
510 	sc->speedo_value = tegra_sku_info.cpu_speedo_value;
511 
512 	/* Tegra 124 */
513 	/* XXX DPLL is not implemented yet */
514 	if (1)
515 		sc->cpu_def = &tegra124_cpu_volt_pllx_def;
516 	else
517 		sc->cpu_def = &tegra124_cpu_volt_dpll_def;
518 
519 	rv = get_fdt_resources(sc, sc->node);
520 	if (rv !=  0) {
521 		return (rv);
522 	}
523 
524 	build_speed_points(sc);
525 
526 	rv = clk_get_freq(sc->clk_cpu_g, &freq);
527 	if (rv != 0) {
528 		device_printf(dev, "Can't get CPU clock frequency\n");
529 		return (rv);
530 	}
531 	if (sc->speedo_id < nitems(cpu_max_freq))
532 		sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
533 	else
534 		sc->cpu_max_freq = cpu_max_freq[0];
535 	sc->act_speed_point = get_speed_point(sc, freq);
536 
537 	/* Set safe startup CPU frequency. */
538 	rv = set_cpu_freq(sc, 1632000000);
539 	if (rv != 0) {
540 		device_printf(dev, "Can't set initial CPU clock frequency\n");
541 		return (rv);
542 	}
543 
544 	/* This device is controlled by cpufreq(4). */
545 	cpufreq_register(dev);
546 
547 	return (0);
548 }
549 
550 static int
551 tegra124_cpufreq_detach(device_t dev)
552 {
553 	struct tegra124_cpufreq_softc *sc;
554 
555 	sc = device_get_softc(dev);
556 	cpufreq_unregister(dev);
557 
558 	if (sc->supply_vdd_cpu != NULL)
559 		regulator_release(sc->supply_vdd_cpu);
560 
561 	if (sc->clk_cpu_g != NULL)
562 		clk_release(sc->clk_cpu_g);
563 	if (sc->clk_cpu_lp != NULL)
564 		clk_release(sc->clk_cpu_lp);
565 	if (sc->clk_pll_x != NULL)
566 		clk_release(sc->clk_pll_x);
567 	if (sc->clk_pll_p != NULL)
568 		clk_release(sc->clk_pll_p);
569 	if (sc->clk_dfll != NULL)
570 		clk_release(sc->clk_dfll);
571 	return (0);
572 }
573 
574 static device_method_t tegra124_cpufreq_methods[] = {
575 	/* Device interface */
576 	DEVMETHOD(device_identify,	tegra124_cpufreq_identify),
577 	DEVMETHOD(device_probe,		tegra124_cpufreq_probe),
578 	DEVMETHOD(device_attach,	tegra124_cpufreq_attach),
579 	DEVMETHOD(device_detach,	tegra124_cpufreq_detach),
580 
581 	/* cpufreq interface */
582 	DEVMETHOD(cpufreq_drv_set,	tegra124_cpufreq_set),
583 	DEVMETHOD(cpufreq_drv_get,	tegra124_cpufreq_get),
584 	DEVMETHOD(cpufreq_drv_settings,	tegra124_cpufreq_settings),
585 	DEVMETHOD(cpufreq_drv_type,	tegra124_cpufreq_type),
586 
587 	DEVMETHOD_END
588 };
589 
590 static devclass_t tegra124_cpufreq_devclass;
591 static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver,
592     tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc));
593 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver,
594     tegra124_cpufreq_devclass, NULL, NULL);
595