xref: /freebsd/sys/arm/nvidia/tegra124/tegra124_cpufreq.c (revision 87d5d10d7d7af72e5529b1cd684f8da41664183b)
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 
479 	if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
480 		return;
481 	if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
482 		device_printf(parent, "add child failed\n");
483 }
484 
485 static int
486 tegra124_cpufreq_probe(device_t dev)
487 {
488 
489 	if (device_get_unit(dev) != 0)
490 		return (ENXIO);
491 	device_set_desc(dev, "CPU Frequency Control");
492 
493 	return (0);
494 }
495 
496 static int
497 tegra124_cpufreq_attach(device_t dev)
498 {
499 	struct tegra124_cpufreq_softc *sc;
500 	uint64_t freq;
501 	int rv;
502 
503 	sc = device_get_softc(dev);
504 	sc->dev = dev;
505 	sc->node = ofw_bus_get_node(device_get_parent(dev));
506 
507 	sc->process_id = tegra_sku_info.cpu_process_id;
508 	sc->speedo_id = tegra_sku_info.cpu_speedo_id;
509 	sc->speedo_value = tegra_sku_info.cpu_speedo_value;
510 
511 	/* Tegra 124 */
512 	/* XXX DPLL is not implemented yet */
513 	if (1)
514 		sc->cpu_def = &tegra124_cpu_volt_pllx_def;
515 	else
516 		sc->cpu_def = &tegra124_cpu_volt_dpll_def;
517 
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 driver_t tegra124_cpufreq_driver = {
592 	"tegra124_cpufreq",
593 	tegra124_cpufreq_methods,
594 	sizeof(struct tegra124_cpufreq_softc),
595 };
596 
597 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver,
598     tegra124_cpufreq_devclass, 0, 0);
599