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 */
50struct 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
57struct 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
66struct cpu_speed_point {
67	uint64_t		freq;		/* Frequecy */
68	int			uvolt;		/* Requested voltage */
69};
70
71static 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
100static 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
110static 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
138static 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
148static 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
175static uint64_t cpu_max_freq[] = {
176	2014500000ULL,
177	2320500000ULL,
178	2116500000ULL,
179	2524500000ULL,
180};
181
182struct 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
207static int cpufreq_lowest_freq = 1;
208TUNABLE_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 */
221static int
222freq_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
259static void
260build_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
273static struct cpu_speed_point *
274get_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
289static int
290tegra124_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
315static int
316set_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
365static int
366tegra124_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
388static int
389tegra124_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
409static int
410tegra124_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
420static int
421get_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
467static void
468tegra124_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
484static int
485tegra124_cpufreq_probe(device_t dev)
486{
487
488	device_set_desc(dev, "CPU Frequency Control");
489
490	return (0);
491}
492
493static int
494tegra124_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
546static int
547tegra124_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
570static 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
586static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver,
587    tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc));
588DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver, NULL, NULL);
589