xref: /freebsd/sys/arm/nvidia/tegra124/tegra124_cpufreq.c (revision 96190b4fef3b4a0cc3ca0606b0c4e3e69a5e6717)
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/param.h>
28 #include <sys/systm.h>
29 #include <sys/bus.h>
30 #include <sys/cpu.h>
31 #include <sys/kernel.h>
32 #include <sys/lock.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 
36 #include <machine/bus.h>
37 #include <machine/cpu.h>
38 
39 #include <dev/clk/clk.h>
40 #include <dev/regulator/regulator.h>
41 #include <dev/ofw/ofw_bus_subr.h>
42 
43 #include <arm/nvidia/tegra_efuse.h>
44 
45 #include "cpufreq_if.h"
46 
47 #define	XXX
48 
49 /* CPU voltage table entry */
50 struct speedo_entry {
51 	uint64_t		freq; 	/* Frequency point */
52 	int			c0; 	/* Coeeficient values for */
53 	int			c1;	/* quadratic equation: */
54 	int 			c2;	/* c2 * speedo^2 + c1 * speedo + c0 */
55 };
56 
57 struct cpu_volt_def {
58 	int			min_uvolt;	/* Min allowed CPU voltage */
59 	int			max_uvolt;	/* Max allowed CPU voltage */
60 	int 			step_uvolt; 	/* Step of CPU voltage */
61 	int			speedo_scale;	/* Scaling factor for cvt */
62 	int			speedo_nitems;	/* Size of speedo table */
63 	struct speedo_entry	*speedo_tbl;	/* CPU voltage table */
64 };
65 
66 struct cpu_speed_point {
67 	uint64_t		freq;		/* Frequecy */
68 	int			uvolt;		/* Requested voltage */
69 };
70 
71 static struct speedo_entry tegra124_speedo_dpll_tbl[] =
72 {
73 	{ 204000000ULL,	1112619, -29295, 402},
74 	{ 306000000ULL,	1150460, -30585, 402},
75 	{ 408000000ULL,	1190122, -31865, 402},
76 	{ 510000000ULL,	1231606, -33155, 402},
77 	{ 612000000ULL,	1274912, -34435, 402},
78 	{ 714000000ULL,	1320040, -35725, 402},
79 	{ 816000000ULL,	1366990, -37005, 402},
80 	{ 918000000ULL,	1415762, -38295, 402},
81 	{1020000000ULL,	1466355, -39575, 402},
82 	{1122000000ULL,	1518771, -40865, 402},
83 	{1224000000ULL,	1573009, -42145, 402},
84 	{1326000000ULL,	1629068, -43435, 402},
85 	{1428000000ULL,	1686950, -44715, 402},
86 	{1530000000ULL,	1746653, -46005, 402},
87 	{1632000000ULL,	1808179, -47285, 402},
88 	{1734000000ULL,	1871526, -48575, 402},
89 	{1836000000ULL,	1936696, -49855, 402},
90 	{1938000000ULL,	2003687, -51145, 402},
91 	{2014500000ULL,	2054787, -52095, 402},
92 	{2116500000ULL,	2124957, -53385, 402},
93 	{2218500000ULL,	2196950, -54665, 402},
94 	{2320500000ULL,	2270765, -55955, 402},
95 	{2320500000ULL,	2270765, -55955, 402},
96 	{2422500000ULL,	2346401, -57235, 402},
97 	{2524500000ULL,	2437299, -58535, 402},
98 };
99 
100 static struct cpu_volt_def tegra124_cpu_volt_dpll_def =
101 {
102 	.min_uvolt =  900000,		/* 0.9 V */
103 	.max_uvolt = 1260000,		/* 1.26 */
104 	.step_uvolt =  10000,		/* 10 mV */
105 	.speedo_scale = 100,
106 	.speedo_nitems = nitems(tegra124_speedo_dpll_tbl),
107 	.speedo_tbl = tegra124_speedo_dpll_tbl,
108 };
109 
110 static struct speedo_entry tegra124_speedo_pllx_tbl[] =
111 {
112 	{ 204000000ULL,	 800000, 0, 0},
113 	{ 306000000ULL,	 800000, 0, 0},
114 	{ 408000000ULL,	 800000, 0, 0},
115 	{ 510000000ULL,	 800000, 0, 0},
116 	{ 612000000ULL,	 800000, 0, 0},
117 	{ 714000000ULL,	 800000, 0, 0},
118 	{ 816000000ULL,	 820000, 0, 0},
119 	{ 918000000ULL,	 840000, 0, 0},
120 	{1020000000ULL,	 880000, 0, 0},
121 	{1122000000ULL,	 900000, 0, 0},
122 	{1224000000ULL,	 930000, 0, 0},
123 	{1326000000ULL,	 960000, 0, 0},
124 	{1428000000ULL,	 990000, 0, 0},
125 	{1530000000ULL,	1020000, 0, 0},
126 	{1632000000ULL,	1070000, 0, 0},
127 	{1734000000ULL,	1100000, 0, 0},
128 	{1836000000ULL,	1140000, 0, 0},
129 	{1938000000ULL,	1180000, 0, 0},
130 	{2014500000ULL,	1220000, 0, 0},
131 	{2116500000ULL,	1260000, 0, 0},
132 	{2218500000ULL,	1310000, 0, 0},
133 	{2320500000ULL,	1360000, 0, 0},
134 	{2397000000ULL,	1400000, 0, 0},
135 	{2499000000ULL,	1400000, 0, 0},
136 };
137 
138 static struct cpu_volt_def tegra124_cpu_volt_pllx_def =
139 {
140 	.min_uvolt = 1000000,		/* XXX 0.9 V doesn't work on all boards */
141 	.max_uvolt = 1260000,		/* 1.26 */
142 	.step_uvolt =  10000,		/* 10 mV */
143 	.speedo_scale = 100,
144 	.speedo_nitems = nitems(tegra124_speedo_pllx_tbl),
145 	.speedo_tbl = tegra124_speedo_pllx_tbl,
146 };
147 
148 static uint64_t cpu_freq_tbl[] = {
149 	 204000000ULL,
150 	 306000000ULL,
151 	 408000000ULL,
152 	 510000000ULL,
153 	 612000000ULL,
154 	 714000000ULL,
155 	 816000000ULL,
156 	 918000000ULL,
157 	1020000000ULL,
158 	1122000000ULL,
159 	1224000000ULL,
160 	1326000000ULL,
161 	1428000000ULL,
162 	1530000000ULL,
163 	1632000000ULL,
164 	1734000000ULL,
165 	1836000000ULL,
166 	1938000000ULL,
167 	2014000000ULL,
168 	2116000000ULL,
169 	2218000000ULL,
170 	2320000000ULL,
171 	2422000000ULL,
172 	2524000000ULL,
173 };
174 
175 static uint64_t cpu_max_freq[] = {
176 	2014500000ULL,
177 	2320500000ULL,
178 	2116500000ULL,
179 	2524500000ULL,
180 };
181 
182 struct tegra124_cpufreq_softc {
183 	device_t		dev;
184 	phandle_t		node;
185 
186 	regulator_t		supply_vdd_cpu;
187 	clk_t			clk_cpu_g;
188 	clk_t			clk_cpu_lp;
189 	clk_t			clk_pll_x;
190 	clk_t			clk_pll_p;
191 	clk_t			clk_dfll;
192 
193 	int 			process_id;
194 	int 			speedo_id;
195 	int 			speedo_value;
196 
197 	uint64_t		cpu_max_freq;
198 	struct cpu_volt_def	*cpu_def;
199 	struct cpu_speed_point	*speed_points;
200 	int			nspeed_points;
201 
202 	struct cpu_speed_point	*act_speed_point;
203 
204 	int			latency;
205 };
206 
207 static int cpufreq_lowest_freq = 1;
208 TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq);
209 
210 #define	DIV_ROUND_CLOSEST(val, div)	(((val) + ((div) / 2)) / (div))
211 
212 #define	ROUND_UP(val, div)	roundup(val, div)
213 #define	ROUND_DOWN(val, div)	rounddown(val, div)
214 
215 /*
216  * Compute requesetd voltage for given frequency and SoC process variations,
217  * - compute base voltage from speedo value using speedo table
218  * - round up voltage to next regulator step
219  * - clamp it to regulator limits
220  */
221 static int
222 freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq)
223 {
224 	int uv, scale, min_uvolt, max_uvolt, step_uvolt;
225 	struct speedo_entry *ent;
226 	int i;
227 
228 	/* Get speedo entry with higher frequency */
229 	ent = NULL;
230 	for (i = 0; i < sc->cpu_def->speedo_nitems; i++) {
231 		if (sc->cpu_def->speedo_tbl[i].freq >= freq) {
232 			ent = &sc->cpu_def->speedo_tbl[i];
233 			break;
234 		}
235 	}
236 	if (ent == NULL)
237 		ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1];
238 	scale = sc->cpu_def->speedo_scale;
239 
240 	/* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */
241 	uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale);
242 	uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) +
243 	    ent->c0;
244 	step_uvolt = sc->cpu_def->step_uvolt;
245 	/* Round up it to next regulator step */
246 	uv = ROUND_UP(uv, step_uvolt);
247 
248 	/* Clamp result */
249 	min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt);
250 	max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt);
251 	if (uv < min_uvolt)
252 		uv =  min_uvolt;
253 	if (uv > max_uvolt)
254 		uv =  max_uvolt;
255 	return (uv);
256 
257 }
258 
259 static void
260 build_speed_points(struct tegra124_cpufreq_softc *sc) {
261 	int i;
262 
263 	sc->nspeed_points = nitems(cpu_freq_tbl);
264 	sc->speed_points = malloc(sizeof(struct cpu_speed_point) *
265 	    sc->nspeed_points, M_DEVBUF, M_NOWAIT);
266 	for (i = 0; i < sc->nspeed_points; i++) {
267 		sc->speed_points[i].freq = cpu_freq_tbl[i];
268 		sc->speed_points[i].uvolt = freq_to_voltage(sc,
269 		    cpu_freq_tbl[i]);
270 	}
271 }
272 
273 static struct cpu_speed_point *
274 get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq)
275 {
276 	int i;
277 
278 	if (sc->speed_points[0].freq >= freq)
279 		return (sc->speed_points + 0);
280 
281 	for (i = 0; i < sc->nspeed_points - 1; i++) {
282 		if (sc->speed_points[i + 1].freq > freq)
283 			return (sc->speed_points + i);
284 	}
285 
286 	return (sc->speed_points + sc->nspeed_points - 1);
287 }
288 
289 static int
290 tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)
291 {
292 	struct tegra124_cpufreq_softc *sc;
293 	int i, j;
294 
295 	if (sets == NULL || count == NULL)
296 		return (EINVAL);
297 
298 	sc = device_get_softc(dev);
299 	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));
300 
301 	for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) {
302 		if (sc->cpu_max_freq < sc->speed_points[j].freq)
303 			continue;
304 		sets[i].freq = sc->speed_points[j].freq / 1000000;
305 		sets[i].volts = sc->speed_points[j].uvolt / 1000;
306 		sets[i].lat = sc->latency;
307 		sets[i].dev = dev;
308 		i++;
309 	}
310 	*count = i;
311 
312 	return (0);
313 }
314 
315 static int
316 set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq)
317 {
318 	struct cpu_speed_point *point;
319 	int rv;
320 
321 	point = get_speed_point(sc, freq);
322 
323 	if (sc->act_speed_point->uvolt < point->uvolt) {
324 		/* set cpu voltage */
325 		rv = regulator_set_voltage(sc->supply_vdd_cpu,
326 		    point->uvolt, point->uvolt);
327 		DELAY(10000);
328 		if (rv != 0)
329 			return (rv);
330 	}
331 
332 	/* Switch supermux to PLLP first */
333 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p);
334 	if (rv != 0) {
335 		device_printf(sc->dev, "Can't set parent to PLLP\n");
336 		return (rv);
337 	}
338 
339 	/* Set PLLX frequency */
340 	rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
341 	if (rv != 0) {
342 		device_printf(sc->dev, "Can't set CPU clock frequency\n");
343 		return (rv);
344 	}
345 
346 	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x);
347 	if (rv != 0) {
348 		device_printf(sc->dev, "Can't set parent to PLLX\n");
349 		return (rv);
350 	}
351 
352 	if (sc->act_speed_point->uvolt > point->uvolt) {
353 		/* set cpu voltage */
354 		rv = regulator_set_voltage(sc->supply_vdd_cpu,
355 		    point->uvolt, point->uvolt);
356 		if (rv != 0)
357 			return (rv);
358 	}
359 
360 	sc->act_speed_point = point;
361 
362 	return (0);
363 }
364 
365 static int
366 tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf)
367 {
368 	struct tegra124_cpufreq_softc *sc;
369 	uint64_t freq;
370 	int rv;
371 
372 	if (cf == NULL || cf->freq < 0)
373 		return (EINVAL);
374 
375 	sc = device_get_softc(dev);
376 
377 	freq = cf->freq;
378 	if (freq < cpufreq_lowest_freq)
379 		freq = cpufreq_lowest_freq;
380 	freq *= 1000000;
381 	if (freq >= sc->cpu_max_freq)
382 		freq = sc->cpu_max_freq;
383 	rv = set_cpu_freq(sc, freq);
384 
385 	return (rv);
386 }
387 
388 static int
389 tegra124_cpufreq_get(device_t dev, struct cf_setting *cf)
390 {
391 	struct tegra124_cpufreq_softc *sc;
392 
393 	if (cf == NULL)
394 		return (EINVAL);
395 
396 	sc = device_get_softc(dev);
397 	memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
398 	cf->dev = NULL;
399 	cf->freq = sc->act_speed_point->freq / 1000000;
400 	cf->volts = sc->act_speed_point->uvolt / 1000;
401 	/* Transition latency in us. */
402 	cf->lat = sc->latency;
403 	/* Driver providing this setting. */
404 	cf->dev = dev;
405 
406 	return (0);
407 }
408 
409 static int
410 tegra124_cpufreq_type(device_t dev, int *type)
411 {
412 
413 	if (type == NULL)
414 		return (EINVAL);
415 	*type = CPUFREQ_TYPE_ABSOLUTE;
416 
417 	return (0);
418 }
419 
420 static int
421 get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node)
422 {
423 	int rv;
424 	device_t parent_dev;
425 
426 	parent_dev =  device_get_parent(sc->dev);
427 	rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply",
428 	    &sc->supply_vdd_cpu);
429 	if (rv != 0) {
430 		device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n");
431 		return (rv);
432 	}
433 
434 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g);
435 	if (rv != 0) {
436 		device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
437 		return (ENXIO);
438 	}
439 
440 	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp);
441 	if (rv != 0) {
442 		device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n");
443 		return (ENXIO);
444 	}
445 
446 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x);
447 	if (rv != 0) {
448 		device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
449 		return (ENXIO);
450 	}
451 	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p);
452 	if (rv != 0) {
453 		device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
454 		return (ENXIO);
455 	}
456 	rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll);
457 	if (rv != 0) {
458 		/* XXX DPLL is not implemented yet */
459 /*
460 		device_printf(sc->dev, "Cannot get 'dfll' clock\n");
461 		return (ENXIO);
462 */
463 	}
464 	return (0);
465 }
466 
467 static void
468 tegra124_cpufreq_identify(driver_t *driver, device_t parent)
469 {
470 	phandle_t root;
471 
472 	root = OF_finddevice("/");
473 	if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124"))
474 		return;
475 
476 	if (device_get_unit(parent) != 0)
477 		return;
478 	if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
479 		return;
480 	if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
481 		device_printf(parent, "add child failed\n");
482 }
483 
484 static int
485 tegra124_cpufreq_probe(device_t dev)
486 {
487 
488 	device_set_desc(dev, "CPU Frequency Control");
489 
490 	return (0);
491 }
492 
493 static int
494 tegra124_cpufreq_attach(device_t dev)
495 {
496 	struct tegra124_cpufreq_softc *sc;
497 	uint64_t freq;
498 	int rv;
499 
500 	sc = device_get_softc(dev);
501 	sc->dev = dev;
502 	sc->node = ofw_bus_get_node(device_get_parent(dev));
503 
504 	sc->process_id = tegra_sku_info.cpu_process_id;
505 	sc->speedo_id = tegra_sku_info.cpu_speedo_id;
506 	sc->speedo_value = tegra_sku_info.cpu_speedo_value;
507 
508 	/* Tegra 124 */
509 	/* XXX DPLL is not implemented yet */
510 	if (1)
511 		sc->cpu_def = &tegra124_cpu_volt_pllx_def;
512 	else
513 		sc->cpu_def = &tegra124_cpu_volt_dpll_def;
514 
515 	rv = get_fdt_resources(sc, sc->node);
516 	if (rv !=  0) {
517 		return (rv);
518 	}
519 
520 	build_speed_points(sc);
521 
522 	rv = clk_get_freq(sc->clk_cpu_g, &freq);
523 	if (rv != 0) {
524 		device_printf(dev, "Can't get CPU clock frequency\n");
525 		return (rv);
526 	}
527 	if (sc->speedo_id < nitems(cpu_max_freq))
528 		sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
529 	else
530 		sc->cpu_max_freq = cpu_max_freq[0];
531 	sc->act_speed_point = get_speed_point(sc, freq);
532 
533 	/* Set safe startup CPU frequency. */
534 	rv = set_cpu_freq(sc, 1632000000);
535 	if (rv != 0) {
536 		device_printf(dev, "Can't set initial CPU clock frequency\n");
537 		return (rv);
538 	}
539 
540 	/* This device is controlled by cpufreq(4). */
541 	cpufreq_register(dev);
542 
543 	return (0);
544 }
545 
546 static int
547 tegra124_cpufreq_detach(device_t dev)
548 {
549 	struct tegra124_cpufreq_softc *sc;
550 
551 	sc = device_get_softc(dev);
552 	cpufreq_unregister(dev);
553 
554 	if (sc->supply_vdd_cpu != NULL)
555 		regulator_release(sc->supply_vdd_cpu);
556 
557 	if (sc->clk_cpu_g != NULL)
558 		clk_release(sc->clk_cpu_g);
559 	if (sc->clk_cpu_lp != NULL)
560 		clk_release(sc->clk_cpu_lp);
561 	if (sc->clk_pll_x != NULL)
562 		clk_release(sc->clk_pll_x);
563 	if (sc->clk_pll_p != NULL)
564 		clk_release(sc->clk_pll_p);
565 	if (sc->clk_dfll != NULL)
566 		clk_release(sc->clk_dfll);
567 	return (0);
568 }
569 
570 static device_method_t tegra124_cpufreq_methods[] = {
571 	/* Device interface */
572 	DEVMETHOD(device_identify,	tegra124_cpufreq_identify),
573 	DEVMETHOD(device_probe,		tegra124_cpufreq_probe),
574 	DEVMETHOD(device_attach,	tegra124_cpufreq_attach),
575 	DEVMETHOD(device_detach,	tegra124_cpufreq_detach),
576 
577 	/* cpufreq interface */
578 	DEVMETHOD(cpufreq_drv_set,	tegra124_cpufreq_set),
579 	DEVMETHOD(cpufreq_drv_get,	tegra124_cpufreq_get),
580 	DEVMETHOD(cpufreq_drv_settings,	tegra124_cpufreq_settings),
581 	DEVMETHOD(cpufreq_drv_type,	tegra124_cpufreq_type),
582 
583 	DEVMETHOD_END
584 };
585 
586 static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver,
587     tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc));
588 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver, NULL, NULL);
589