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